Skip to content

Commit 492c287

Browse files
committed
Updated site
1 parent 373ae0d commit 492c287

File tree

16 files changed

+47
-29
lines changed

16 files changed

+47
-29
lines changed

en/ctf/ctfatac/index.html

Lines changed: 20 additions & 11 deletions
Large diffs are not rendered by default.

en/ctf/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ <h2 class="entry-hint-parent">CTF@AC 2025
177177
KEY = b&#34;SECRET_KEY!123456XXXXXXXXXXXXXXX&#34; def decrypt_file(input_path, output_path, key): with open(input_path, &#34;rb&#34;) as f: data = f.read() iv = data[:16] ciphertext = data[16:] cipher = AES.new(key, AES.MODE_CBC, iv) plaintext = unpad(cipher.decrypt(ciphertext), AES.block_size) with open(output_path, &#34;wb&#34;) as f: f.write(plaintext) The decrypted flag.plugin init.py contains the following code:
178178
...</p>
179179
</div>
180-
<footer class="entry-footer"><span title='2025-09-16 00:00:00 +0000 UTC'>September 16, 2025</span>&nbsp;·&nbsp;33 min&nbsp;·&nbsp;6997 words&nbsp;·&nbsp;Paolo</footer>
180+
<footer class="entry-footer"><span title='2025-09-16 00:00:00 +0000 UTC'>September 16, 2025</span>&nbsp;·&nbsp;36 min&nbsp;·&nbsp;7545 words&nbsp;·&nbsp;Paolo</footer>
181181
<a class="entry-link" aria-label="post link to CTF@AC 2025" href="https://pascalctf.github.io/en/ctf/ctfatac/"></a>
182182
</article>
183183

en/tags/binary/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ <h2 class="entry-hint-parent">CTF@AC 2025
162162
KEY = b&#34;SECRET_KEY!123456XXXXXXXXXXXXXXX&#34; def decrypt_file(input_path, output_path, key): with open(input_path, &#34;rb&#34;) as f: data = f.read() iv = data[:16] ciphertext = data[16:] cipher = AES.new(key, AES.MODE_CBC, iv) plaintext = unpad(cipher.decrypt(ciphertext), AES.block_size) with open(output_path, &#34;wb&#34;) as f: f.write(plaintext) The decrypted flag.plugin init.py contains the following code:
163163
...</p>
164164
</div>
165-
<footer class="entry-footer"><span title='2025-09-16 00:00:00 +0000 UTC'>September 16, 2025</span>&nbsp;·&nbsp;33 min&nbsp;·&nbsp;6997 words&nbsp;·&nbsp;Paolo</footer>
165+
<footer class="entry-footer"><span title='2025-09-16 00:00:00 +0000 UTC'>September 16, 2025</span>&nbsp;·&nbsp;36 min&nbsp;·&nbsp;7545 words&nbsp;·&nbsp;Paolo</footer>
166166
<a class="entry-link" aria-label="post link to CTF@AC 2025" href="https://pascalctf.github.io/en/ctf/ctfatac/"></a>
167167
</article>
168168

en/tags/crypto/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ <h2 class="entry-hint-parent">CTF@AC 2025
162162
KEY = b&#34;SECRET_KEY!123456XXXXXXXXXXXXXXX&#34; def decrypt_file(input_path, output_path, key): with open(input_path, &#34;rb&#34;) as f: data = f.read() iv = data[:16] ciphertext = data[16:] cipher = AES.new(key, AES.MODE_CBC, iv) plaintext = unpad(cipher.decrypt(ciphertext), AES.block_size) with open(output_path, &#34;wb&#34;) as f: f.write(plaintext) The decrypted flag.plugin init.py contains the following code:
163163
...</p>
164164
</div>
165-
<footer class="entry-footer"><span title='2025-09-16 00:00:00 +0000 UTC'>September 16, 2025</span>&nbsp;·&nbsp;33 min&nbsp;·&nbsp;6997 words&nbsp;·&nbsp;Paolo</footer>
165+
<footer class="entry-footer"><span title='2025-09-16 00:00:00 +0000 UTC'>September 16, 2025</span>&nbsp;·&nbsp;36 min&nbsp;·&nbsp;7545 words&nbsp;·&nbsp;Paolo</footer>
166166
<a class="entry-link" aria-label="post link to CTF@AC 2025" href="https://pascalctf.github.io/en/ctf/ctfatac/"></a>
167167
</article>
168168

en/tags/ctf/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ <h2 class="entry-hint-parent">CTF@AC 2025
162162
KEY = b&#34;SECRET_KEY!123456XXXXXXXXXXXXXXX&#34; def decrypt_file(input_path, output_path, key): with open(input_path, &#34;rb&#34;) as f: data = f.read() iv = data[:16] ciphertext = data[16:] cipher = AES.new(key, AES.MODE_CBC, iv) plaintext = unpad(cipher.decrypt(ciphertext), AES.block_size) with open(output_path, &#34;wb&#34;) as f: f.write(plaintext) The decrypted flag.plugin init.py contains the following code:
163163
...</p>
164164
</div>
165-
<footer class="entry-footer"><span title='2025-09-16 00:00:00 +0000 UTC'>September 16, 2025</span>&nbsp;·&nbsp;33 min&nbsp;·&nbsp;6997 words&nbsp;·&nbsp;Paolo</footer>
165+
<footer class="entry-footer"><span title='2025-09-16 00:00:00 +0000 UTC'>September 16, 2025</span>&nbsp;·&nbsp;36 min&nbsp;·&nbsp;7545 words&nbsp;·&nbsp;Paolo</footer>
166166
<a class="entry-link" aria-label="post link to CTF@AC 2025" href="https://pascalctf.github.io/en/ctf/ctfatac/"></a>
167167
</article>
168168

en/tags/ctfatac/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ <h2 class="entry-hint-parent">CTF@AC 2025
162162
KEY = b&#34;SECRET_KEY!123456XXXXXXXXXXXXXXX&#34; def decrypt_file(input_path, output_path, key): with open(input_path, &#34;rb&#34;) as f: data = f.read() iv = data[:16] ciphertext = data[16:] cipher = AES.new(key, AES.MODE_CBC, iv) plaintext = unpad(cipher.decrypt(ciphertext), AES.block_size) with open(output_path, &#34;wb&#34;) as f: f.write(plaintext) The decrypted flag.plugin init.py contains the following code:
163163
...</p>
164164
</div>
165-
<footer class="entry-footer"><span title='2025-09-16 00:00:00 +0000 UTC'>September 16, 2025</span>&nbsp;·&nbsp;33 min&nbsp;·&nbsp;6997 words&nbsp;·&nbsp;Paolo</footer>
165+
<footer class="entry-footer"><span title='2025-09-16 00:00:00 +0000 UTC'>September 16, 2025</span>&nbsp;·&nbsp;36 min&nbsp;·&nbsp;7545 words&nbsp;·&nbsp;Paolo</footer>
166166
<a class="entry-link" aria-label="post link to CTF@AC 2025" href="https://pascalctf.github.io/en/ctf/ctfatac/"></a>
167167
</article>
168168
</main>

en/tags/ctfatac2025/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ <h2 class="entry-hint-parent">CTF@AC 2025
162162
KEY = b&#34;SECRET_KEY!123456XXXXXXXXXXXXXXX&#34; def decrypt_file(input_path, output_path, key): with open(input_path, &#34;rb&#34;) as f: data = f.read() iv = data[:16] ciphertext = data[16:] cipher = AES.new(key, AES.MODE_CBC, iv) plaintext = unpad(cipher.decrypt(ciphertext), AES.block_size) with open(output_path, &#34;wb&#34;) as f: f.write(plaintext) The decrypted flag.plugin init.py contains the following code:
163163
...</p>
164164
</div>
165-
<footer class="entry-footer"><span title='2025-09-16 00:00:00 +0000 UTC'>September 16, 2025</span>&nbsp;·&nbsp;33 min&nbsp;·&nbsp;6997 words&nbsp;·&nbsp;Paolo</footer>
165+
<footer class="entry-footer"><span title='2025-09-16 00:00:00 +0000 UTC'>September 16, 2025</span>&nbsp;·&nbsp;36 min&nbsp;·&nbsp;7545 words&nbsp;·&nbsp;Paolo</footer>
166166
<a class="entry-link" aria-label="post link to CTF@AC 2025" href="https://pascalctf.github.io/en/ctf/ctfatac/"></a>
167167
</article>
168168
</main>

en/tags/web/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ <h2 class="entry-hint-parent">CTF@AC 2025
162162
KEY = b&#34;SECRET_KEY!123456XXXXXXXXXXXXXXX&#34; def decrypt_file(input_path, output_path, key): with open(input_path, &#34;rb&#34;) as f: data = f.read() iv = data[:16] ciphertext = data[16:] cipher = AES.new(key, AES.MODE_CBC, iv) plaintext = unpad(cipher.decrypt(ciphertext), AES.block_size) with open(output_path, &#34;wb&#34;) as f: f.write(plaintext) The decrypted flag.plugin init.py contains the following code:
163163
...</p>
164164
</div>
165-
<footer class="entry-footer"><span title='2025-09-16 00:00:00 +0000 UTC'>September 16, 2025</span>&nbsp;·&nbsp;33 min&nbsp;·&nbsp;6997 words&nbsp;·&nbsp;Paolo</footer>
165+
<footer class="entry-footer"><span title='2025-09-16 00:00:00 +0000 UTC'>September 16, 2025</span>&nbsp;·&nbsp;36 min&nbsp;·&nbsp;7545 words&nbsp;·&nbsp;Paolo</footer>
166166
<a class="entry-link" aria-label="post link to CTF@AC 2025" href="https://pascalctf.github.io/en/ctf/ctfatac/"></a>
167167
</article>
168168

it/ctf/ctfatac/index.html

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@
110110
"ctfatac", "ctf", "binary", "crypto", "web", "ctfatac2025"
111111
],
112112
"articleBody": "CTF@AC 2025 Web 🌐 money Analisi La challenge espone una dashboard minimale che supporta plugin di terze parti. Quando carichiamo un plugin, la piattaforma ci permette anche di scaricare quelli esistenti (incluso l’ufficiale flag.plugin).\nExploit Dopo aver scaricato flag.plugin, notiamo che è cifrato. Il file server.py contiene sia la chiave sia la funzione per decifrarlo, quindi possiamo decifrarlo in locale usando decrypt_file.\nKEY = b\"SECRET_KEY!123456XXXXXXXXXXXXXXX\" def decrypt_file(input_path, output_path, key): with open(input_path, \"rb\") as f: data = f.read() iv = data[:16] ciphertext = data[16:] cipher = AES.new(key, AES.MODE_CBC, iv) plaintext = unpad(cipher.decrypt(ciphertext), AES.block_size) with open(output_path, \"wb\") as f: f.write(plaintext) Il init.py del flag.plugin decifrato contiene il seguente codice:\nimport json, sqlite3, pathlib, time, uuid import os plugin_dir = pathlib.Path(__file__).resolve().parent manifest_path = plugin_dir / \"plugin_manifest.json\" name, version = \"Widget\", \"1.0.0\" if manifest_path.exists(): try: m = json.loads(manifest_path.read_text()) name = m.get(\"name\", name) version = m.get(\"version\", version) except Exception: pass thumb = thumb = f''' ",
113-
"wordCount" : "5583",
113+
"wordCount" : "6161",
114114
"inLanguage": "it",
115115
"image":"https://opengraph.githubassets.com/eccdc445364e4f9dcbece7bb7f178f0756be13a48717c78ec94bf78c35861b9a/PascalCTF/PascalCTF.github.io","datePublished": "2025-09-16T00:00:00Z",
116116
"dateModified": "2025-09-16T00:00:00Z",
@@ -211,7 +211,7 @@ <h1 class="post-title entry-hint-parent">
211211
<div class="post-description">
212212
Alcune writeup della ctf CTF@AC edizione 2025.
213213
</div>
214-
<div class="post-meta"><span title='2025-09-16 00:00:00 +0000 UTC'>settembre 16, 2025</span>&nbsp;·&nbsp;27 minuti&nbsp;·&nbsp;5583 parole&nbsp;·&nbsp;Paolo&nbsp;|&nbsp;Traduzioni:
214+
<div class="post-meta"><span title='2025-09-16 00:00:00 +0000 UTC'>settembre 16, 2025</span>&nbsp;·&nbsp;29 minuti&nbsp;·&nbsp;6161 parole&nbsp;·&nbsp;Paolo&nbsp;|&nbsp;Traduzioni:
215215
<ul class="i18n_list">
216216
<li>
217217
<a href="https://pascalctf.github.io/en/ctf/ctfatac/">🇬🇧 En</a>
@@ -725,7 +725,16 @@ <h3 id="pythonese">Pythonese<a hidden class="anchor" aria-hidden="true" href="#p
725725
<h4 id="flag">Flag<a hidden class="anchor" aria-hidden="true" href="#flag">#</a></h4>
726726
<pre tabindex="0"><code>CTF{2944cec0c0f401a5fa538933a2f6210c279fbfc8548ca8ab912b493d03d2f5bf}
727727
</code></pre><h3 id="ironevil">Ironevil<a hidden class="anchor" aria-hidden="true" href="#ironevil">#</a></h3>
728-
<p>TODO</p>
728+
<h4 id="la-challenge">La challenge<a hidden class="anchor" aria-hidden="true" href="#la-challenge">#</a></h4>
729+
<p>Il binario fornito nella challenge, chiamato <code>ironveil</code>, è un eseguibile ELF 64-bit PIE compilato per Linux e collegato a un loader NixOS. Poiché il percorso dell’interprete indicato nel binario punta a una posizione non standard, il programma non può essere eseguito direttamente su un sistema tipico. È per questo che, lanciandolo da shell, compare l’errore “cannot execute: required file not found.” In pratica, la soluzione è specificare manualmente il loader del sistema, di solito <code>/lib64/ld-linux-x86-64.so.2</code>, per poter eseguire il programma.</p>
730+
<p>Il codice decompilato mostra che, prima di qualsiasi operazione di cifratura, il programma dedica molto tempo all’inizializzazione. Imposta gestori di segnali, esegue controlli con <code>poll</code> sui descrittori di file e interagisce con <code>/dev/null</code>. Inoltre interroga attributi dei thread, come indirizzo e dimensione dello stack, e li riallinea con precisione. Queste procedure sono tipiche di binari resi più resistenti a tecniche di debugging o all’esecuzione in sandbox. Una volta completata l’inizializzazione, però, la logica si riduce a un comportamento piuttosto semplice: il programma si aspetta un file come input e produce un output cifrato con il suffisso <code>.encrypted</code>.</p>
731+
<p>La routine di cifratura è basata su una macchina virtuale personalizzata. Questa VM interpreta trentadue opcode per generare uno stream di byte che funge da chiave. Lo stream viene poi applicato al file in input con un’operazione di XOR byte per byte. Ogni byte di plaintext viene combinato con il corrispondente byte della chiave e il risultato viene scritto su disco. Il dettaglio cruciale è che la VM è deterministica: lo stesso binario produce sempre lo stesso keystream. Non esiste alcun seed casuale, nonce o variazione per file. Ciò significa che la trasformazione è semplicemente <code>ciphertext = plaintext ⊕ key</code>. Applicare la trasformazione due volte con la stessa chiave la annulla, perché <code>(P ⊕ K) ⊕ K = P</code>.</p>
732+
<h4 id="la-soluzione-1">La soluzione<a hidden class="anchor" aria-hidden="true" href="#la-soluzione-1">#</a></h4>
733+
<p>La challenge ci metteva a disposizione soltanto il binario e un file già cifrato, <code>flag.txt.encrypted</code>. La soluzione pensata dagli autori probabilmente era quella di invertire la VM, studiarne le trentadue istruzioni e rigenerare lo stream di chiave per decifrare manualmente il ciphertext. Tuttavia, la natura deterministica dell’algoritmo offriva una via molto più semplice. Dando in pasto al programma il file già cifrato, lo stesso keystream veniva applicato di nuovo. Di conseguenza, la doppia cifratura si annullava e restituiva il plaintext originale.</p>
734+
<p>Eseguendo il binario tramite il loader di sistema con il file cifrato come input veniva generato un nuovo file, <code>flag.txt.encrypted.encrypted</code>. Aprendolo si poteva vedere immediatamente la flag in chiaro all’inizio del file. Il resto conteneva byte spazzatura, coerenti con l’operazione XOR che prosegue oltre la flag su dati inutilizzati o irrilevanti. Ma la presenza della flag completa all’inizio era sufficiente per risolvere la challenge.</p>
735+
<h4 id="note-finali">Note finali<a hidden class="anchor" aria-hidden="true" href="#note-finali">#</a></h4>
736+
<p>La debolezza di sicurezza qui risiede proprio nel riutilizzo di uno stream di chiave statico. Nella crittografia reale, i cifrari a flusso sono sicuri solo se ogni cifratura usa un nonce o un vettore di inizializzazione univoco, così da garantire che lo stream non si ripeta mai. In assenza di questa misura, il cifrario si riduce a un insicuro “many-time pad”, in cui l’uso ripetuto dello stesso keystream porta inevitabilmente a perdite di informazione. In questo caso, la falla era talmente grave che una semplice doppia esecuzione del binario invertiva la trasformazione ed esponeva direttamente la flag in chiaro.</p>
737+
<p>La challenge quindi poteva essere risolta in pochi secondi senza comprendere affatto il funzionamento della macchina virtuale, semplicemente ri-cifrando il ciphertext fornito. Il risultato inatteso ma valido è stato il recupero della flag:</p>
729738
<h3 id="pixel-gate">Pixel Gate<a hidden class="anchor" aria-hidden="true" href="#pixel-gate">#</a></h3>
730739
<p>Questa challenge includeva un eseguibile Go <code>challenge</code> strip-pato e uno script helper <code>gen.py</code>. Il binario si aspetta un PNG con un formato molto specifico e stampa i contenuti solo se tutte le validazioni interne vanno a buon fine. Facendo reverse del build Go RISC-V64 troviamo un parser PNG volutamente minimale e fatto a mano, i cui vincoli sono rispecchiati esattamente dallo script generatore.</p>
731740
<h4 id="lalgoritmo">L’algoritmo<a hidden class="anchor" aria-hidden="true" href="#lalgoritmo">#</a></h4>
@@ -763,7 +772,7 @@ <h5 id="generatore-png-in-python">Generatore PNG in Python<a hidden class="ancho
763772
</span></span><span class="line"><span class="cl"> <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s2">&#34;pass.png&#34;</span><span class="p">,</span> <span class="s2">&#34;wb&#34;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
764773
</span></span><span class="line"><span class="cl"> <span class="n">f</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
765774
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;Wrote pass.png (</span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">data</span><span class="p">)</span><span class="si">}</span><span class="s2"> bytes)&#34;</span><span class="p">)</span>
766-
</span></span></code></pre></div><h4 id="note-finali">Note finali<a hidden class="anchor" aria-hidden="true" href="#note-finali">#</a></h4>
775+
</span></span></code></pre></div><h4 id="note-finali-1">Note finali<a hidden class="anchor" aria-hidden="true" href="#note-finali-1">#</a></h4>
767776
<p>Le stringhe che sembrano esadecimali non vengono mai interpretate—il confronto avviene sui byte ASCII letterali. Consentire il color type 6 qui non aggiunge valore, quindi il type 2 evita complicazioni su palette e alpha. Poiché non avviene decompressione, un <code>IDAT</code> vuoto basta. Qualunque deviazione—lunghezze errate, costante alterata, chunk mancante o CRC non corrispondente—provoca l’aborto prima dell’output. Il risultato è un PNG volutamente minuscolo e deterministico, usato come “token” di accesso.</p>
768777
<h2 id="cryptography-">Cryptography 🔑<a hidden class="anchor" aria-hidden="true" href="#cryptography-">#</a></h2>
769778
<h3 id="repeated-rsa">Repeated RSA<a hidden class="anchor" aria-hidden="true" href="#repeated-rsa">#</a></h3>

it/ctf/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ <h2 class="entry-hint-parent">CTF@AC 2025
177177
KEY = b&#34;SECRET_KEY!123456XXXXXXXXXXXXXXX&#34; def decrypt_file(input_path, output_path, key): with open(input_path, &#34;rb&#34;) as f: data = f.read() iv = data[:16] ciphertext = data[16:] cipher = AES.new(key, AES.MODE_CBC, iv) plaintext = unpad(cipher.decrypt(ciphertext), AES.block_size) with open(output_path, &#34;wb&#34;) as f: f.write(plaintext) Il init.py del flag.plugin decifrato contiene il seguente codice:
178178
...</p>
179179
</div>
180-
<footer class="entry-footer"><span title='2025-09-16 00:00:00 +0000 UTC'>settembre 16, 2025</span>&nbsp;·&nbsp;27 minuti&nbsp;·&nbsp;5583 parole&nbsp;·&nbsp;Paolo</footer>
180+
<footer class="entry-footer"><span title='2025-09-16 00:00:00 +0000 UTC'>settembre 16, 2025</span>&nbsp;·&nbsp;29 minuti&nbsp;·&nbsp;6161 parole&nbsp;·&nbsp;Paolo</footer>
181181
<a class="entry-link" aria-label="post link to CTF@AC 2025" href="https://pascalctf.github.io/it/ctf/ctfatac/"></a>
182182
</article>
183183

0 commit comments

Comments
 (0)