Skip to content

Commit 40bc25c

Browse files
committed
Add some other writeups to the site
1 parent 894cdb2 commit 40bc25c

1 file changed

Lines changed: 93 additions & 12 deletions

File tree

content/it/ctf/pascalCTF2026.md

Lines changed: 93 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -38,20 +38,20 @@ editPost:
3838
# Pascal CTF 2026
3939
![pascalCTF logo](/images/pascalCTF.png)
4040

41-
La PascalCTF 2026 è stata una competizione di Capture The Flag (CTF) organizzata dal nostro team [Paolo](https://pascalctf.github.io/). La competizione si è svolta dal `31 gennaio 2026` al `1 febbraio 2026` e ha visto la partecipazione di numerosi team provenienti da tutto il mondo.
41+
La PascalCTF 2026 è stata una competizione di Capture The Flag (CTF) organizzata dal nostro team [Paolo](https://pascalctf.github.io/). Si è svolta dal `31 gennaio 2026` al `1 febbraio 2026` e ha visto la partecipazione di numerosi team provenienti da tutto il mondo.
4242

43-
Buona parte delle challenge è stata creata per l'edizione **Beginner** tenutasi nello stesso mese presso l'[ITT Pascal](https://www.ispascalcomandini.it/pagine/pascal-ctf). Le challenge erano suddivise in diverse categorie, tra cui *Web Security*, *Cryptography*, *Binary Exploitation*, *Reverse Engineering*, *Miscellaneous* e *Intelligenza Artificiale*. Ogni categoria presentava sfide di difficoltà variabile, adatte sia a principianti che a esperti.
43+
Gran parte delle challenge è stata realizzata per l'edizione **Beginner**, ospitata nello stesso mese presso l'[ITT Pascal](https://www.ispascalcomandini.it/pagine/pascal-ctf). Le sfide erano suddivise in diverse categorie, tra cui *Web Security*, *Cryptography*, *Binary Exploitation*, *Reverse Engineering*, *Miscellaneous* e *Intelligenza Artificiale*, con difficoltà variabile e adatte sia a principianti sia a esperti.
4444

4545
![pascalCTF 2026](/images/pascalctf2026.jpeg)
4646

47-
Ci teniamo inoltre a ringraziare tutti i **partecipanti** per il loro entusiasmo e la loro dedizione, nonché i nostri [**sponsors**](/it/sponsors#2026) per il loro supporto.
47+
Desideriamo inoltre ringraziare tutti i **partecipanti** per l'entusiasmo e la dedizione dimostrati, così come i nostri [**sponsors**](/it/sponsors#2026) per il loro supporto.
4848

4949
## Web 🌐
5050

5151
### JSHit
5252
* Autore: `Alan Davide Bovo`[`@AlBovo`](https://github.com/AlBovo)
5353

54-
Come si può intuire dal nome, questa challenge era basata su un semplice script JSFuck il quale poteva essere "deoffuscato" mediante un semplice `toString()`:
54+
Come suggerisce il nome, questa challenge era basata su un semplice script JSFuck, che poteva essere "deoffuscato" con un banale `toString()`:
5555

5656
```javascript
5757
let f = [][(![]+[])[+!+[]]+(!![]+[]) ... ];
@@ -71,13 +71,15 @@ Una volta deoffuscato, lo script risultava essere il seguente:
7171
}
7272
```
7373

74-
Ciò nonostante il metodo più veloce per risolvere una challenge del genere era semplicemente utilizzare un qualsiasi LLM disponibile (ad esempio ChatGPT) e chiedergli di deoffuscare il codice, ottenendo così la flag in pochi secondi.
74+
Nonostante ciò, il modo più veloce per risolvere una challenge del genere era semplicemente usare un qualsiasi LLM disponibile, ad esempio ChatGPT, chiedendogli di deoffuscare il codice e ottenendo così la flag in pochi secondi.
7575

7676
### ZazaStore
7777
* Autore: `Enea Maroncelli`[`@ZazaMan`](https://github.com/Eneamaroncelli27)
7878
* Autore: `Alan Davide Bovo`[`@AlBovo`](https://github.com/AlBovo)
7979

80-
TODO
80+
ZazaStore era un sito scritto in *NodeJS* che implementava alcune funzionalità molto semplici tipiche di un e-commerce.
81+
82+
In sintesi, il sito permetteva di acquistare alcuni oggetti, tra cui anche la **flag**:
8183

8284
```javascript
8385
const content = {
@@ -89,8 +91,23 @@ const content = {
8991
const prices = { "FakeZa": 1, "ElectricZa": 65, "CartoonZa": 35, "RealZa": 1000 };
9092
```
9193

94+
Osservando il modo in cui veniva inizializzato un utente, si notava che nessun giocatore disponeva ovviamente di abbastanza denaro per acquistare la flag in `RealZa`...
95+
```javascript
96+
app.post('/login', (req, res) => {
97+
const { username, password } = req.body;
98+
if (username && password) {
99+
req.session.user = true;
100+
req.session.balance = 100;
101+
req.session.inventory = {};
102+
req.session.cart = {};
103+
return res.json({ success: true });
104+
} else {
105+
res.json({ success: false });
106+
}
107+
});
108+
```
92109

93-
110+
Analizzando gli altri endpoint, però, saltava subito all'occhio `/add-cart`, che permetteva di aggiungere un prodotto al carrello salvato nella sessione tramite un oggetto `product`.
94111
```javascript
95112
app.post('/add-cart', (req, res) => {
96113
const product = req.body;
@@ -116,8 +133,11 @@ app.post('/add-cart', (req, res) => {
116133
});
117134
```
118135

136+
Prestando attenzione si può notare che viene controllato solo il nome del prodotto, e quindi di fatto sanitizzato, mentre la quantità non viene mai verificata per accertarsi che sia un `Number` e rimane quindi completamente non sanitizzata.
119137

138+
Per capire il vero exploit bisogna però guardare anche l'endpoint `/checkout`, che usa la sessione inizializzata da `/login` e modificata da `/add-cart` per calcolare il totale dei prodotti e verificare che sia inferiore al saldo disponibile.
120139

140+
Solo nel caso in cui il saldo disponibile sia sufficiente, i prodotti vengono aggiunti all'inventario dell'utente e quindi mostrati:
121141
```javascript
122142
app.post('/checkout', (req, res) => {
123143
if (!req.session.inventory) {
@@ -153,12 +173,73 @@ app.post('/checkout', (req, res) => {
153173
});
154174
```
155175

176+
La domanda spontanea è però: *come faccio ad avere abbastanza soldi per comprare la flag?*
177+
178+
Questo, però, è il punto di vista sbagliato per risolvere la challenge: grazie ai dettagli notati in `/add-cart`, possiamo infatti impostare la quantità di un prodotto su un qualunque oggetto (`"stringa"`, `0`, `{}`, `[]`).
179+
180+
A questo punto vogliamo bypassare due controlli:
181+
1. L'`if` presente in `/add-cart` il quale controlla che `quantity < 1`
182+
2. L'`if` presente in `/checkout` il quale controlla che `total > req.session.balance`
183+
184+
Per superare il primo `if` si possono usare tutti e tre i casi tra **stringhe**, **array** (con almeno un oggetto) e un **oggetto** vuoto (`{}`).
185+
186+
Nel secondo `if`, invece, il metodo intended per rendere sufficiente il bilancio era usare una **stringa** oppure un **oggetto**, così che la moltiplicazione `prices[product] * cart[product]` producesse **`NaN`**.
187+
188+
Per definizione, `NaN < x` e `NaN > x` restituiscono entrambe `false` e, in questo caso specifico, poiché il sito controlla se l'utente ha superato il proprio bilancio, il fatto che questa verifica ritorni `false` consente di acquistare qualsiasi cosa!
189+
190+
### Travel Playlist
191+
* Autore: `Alan Davide Bovo`[`@AlBovo`](https://github.com/AlBovo)
192+
193+
Il codice di questo sito era davvero minimale ed era sostanzialmente il seguente:
194+
```python
195+
from flask import Flask, jsonify, request, render_template
196+
197+
app = Flask(__name__)
198+
199+
@app.route("/")
200+
def index():
201+
return render_template("index.html")
202+
203+
@app.route("/pages/<int:index>")
204+
def page(index):
205+
return render_template("pages.html", index=index)
206+
207+
@app.route("/api/get_json", methods=["POST"])
208+
def get_json():
209+
index = request.json.get("index")
210+
if not index:
211+
return jsonify({"error": "Index is required"}), 400
212+
213+
path = f"static/{index}"
214+
try:
215+
with open(path, "r") as file:
216+
data = file.read()
217+
return data, 200
218+
except FileNotFoundError:
219+
return jsonify({"error": "File not found"}), 404
220+
except Exception as e:
221+
return jsonify({"error": str(e)}), 500
222+
223+
if __name__ == "__main__":
224+
app.run(host="0.0.0.0", port=5000, debug=False)
225+
```
226+
227+
Un po' come nella challenge precedente, l'endpoint interessante era `/api/get_json`, che accettava un JSON e restituiva il contenuto del file `static/{index}`.
228+
229+
Guardando la cartella *static* si trovano 7 file con indici da **1** a **7**, ma il loro contenuto non è particolarmente interessante.
230+
231+
La flag, infatti, si trova in `flag.txt` e non in `static/flag.txt`.
232+
233+
L'aspetto rilevante per risolvere la challenge è che questa normalissima path traversal non implementa nemmeno un controllo sull'indice, che può assumere qualsiasi valore e non solo un intero.
234+
235+
Di conseguenza, il sito risponde senza problemi a un normale `{"index": "../flag.txt"}`, restituendo direttamente la flag.
236+
156237
## Cryptography 🔒
157238

158239
### XorD
159240
* Autore: `Filippo Boschi`[`@pllossi`](https://github.com/pllossi)
160241

161-
La challenge forniva un semplice script Python che implementava una cifratura XOR mediante un One-Time Pad (OTP) inizializzato con un seed fisso:
242+
La challenge forniva un semplice script Python che implementava una cifratura XOR tramite un One-Time Pad (OTP) inizializzato con un seed fisso:
162243

163244
```python
164245
import os
@@ -186,7 +267,7 @@ La vulnerabilità risiedeva nell'uso di un seed fisso (`1337`). Poiché la seque
186267
### Ice Cramer
187268
* Autore: `Alan Davide Bovo`[`@AlBovo`](https://github.com/AlBovo)
188269

189-
Questa challenge come si può intuire dal nome si basava interamente sulla risoluzione di un normalissimo sistema di equazioni lineari le cui incognite altro non erano che i singoli byte della flag. Il sistema veniva generato in maniera casuale, ma con la garanzia che avesse una soluzione unica, e veniva fornito al giocatore sotto forma di stringa:
270+
Come suggerisce il nome, questa challenge si basava interamente sulla risoluzione di un normale sistema di equazioni lineari, in cui le incognite erano i singoli byte della flag. Il sistema veniva generato in modo casuale, ma con la garanzia di avere una soluzione unica, e veniva fornito al giocatore sotto forma di stringa:
190271

191272
```python
192273
def generate_system(values):
@@ -202,7 +283,7 @@ def generate_system(values):
202283
print(streq)
203284
```
204285

205-
Per risolvere il sistema, era sufficiente utilizzare un qualsiasi software di algebra computazionale (ad esempio Wolfram Alpha) o scrivere una semplice solve mediante l'utilizzo di librerie come [`z3`](https://ericpony.github.io/z3py-tutorial/guide-examples.htm).
286+
Per risolvere il sistema era sufficiente usare un qualsiasi software di algebra computazionale, ad esempio Wolfram Alpha, oppure scrivere un semplice solver con librerie come [`z3`](https://ericpony.github.io/z3py-tutorial/guide-examples.htm).
206287

207288
### Linux Penguin
208289
* Autore: `Alan Davide Bovo`[`@AlBovo`](https://github.com/AlBovo)
@@ -243,9 +324,9 @@ TODO
243324
TODO
244325

245326
## Conclusioni
246-
Nonostante le diverse problematiche incontrate durante l'organizzazione e lo svolgimento della competizione, siamo estremamente soddisfatti del risultato finale e della partecipazione che abbiamo ricevuto. Vorremmo però anche scusarci con tutti i partecipanti per eventuali disagi o problemi tecnici che si sono verificati durante la competizione, e assicurarvi che faremo del nostro meglio per evitare che si ripetano in futuro.
327+
Nonostante le diverse problematiche incontrate durante l'organizzazione e lo svolgimento della competizione, siamo estremamente soddisfatti del risultato finale e della partecipazione ricevuta. Vorremmo però anche scusarci con tutti i partecipanti per eventuali disagi o problemi tecnici verificatisi durante la competizione, e assicurarvi che faremo del nostro meglio per evitare che si ripetano in futuro.
247328

248-
Ci teniamo inoltre a riflettere sull'utilizzo degli **LLM** e dell'**AI** in generale all'interno delle competizioni CTF. Se da un lato queste tecnologie possono essere strumenti estremamente potenti per risolvere le challenge, dall'altro rischiano di rendere alcune sfide troppo *semplici* o addirittura *banali*. Per questo motivo, stiamo valutando l'idea di introdurre delle **limitazioni** all'utilizzo di questi strumenti nelle future edizioni della PascalCTF, al fine di mantenere un certo livello di difficoltà e di stimolare la creatività e l'ingegno dei partecipanti.
329+
Vogliamo inoltre riflettere sull'utilizzo degli **LLM** e dell'**AI** in generale all'interno delle competizioni CTF. Se da un lato queste tecnologie possono essere strumenti estremamente potenti per risolvere le challenge, dall'altro rischiano di rendere alcune sfide troppo *semplici* o addirittura *banali*. Per questo motivo, stiamo valutando l'idea di introdurre delle **limitazioni** all'utilizzo di questi strumenti nelle future edizioni della PascalCTF, così da mantenere un certo livello di difficoltà e stimolare la creatività e l'ingegno dei partecipanti.
249330

250331
Il nostro scopo rimarrà infatti, oggi come in futuro, quello di offrire una competizione *divertente*, *educativa* e *stimolante* per tutti i partecipanti, indipendentemente dal loro livello di esperienza o dalle tecnologie che decidono di utilizzare.
251332

0 commit comments

Comments
 (0)