Caso di studio * DownUnderCTF 2023

Trova la bandiera in
un binario CTF.

Usa REA per ispezionare un piccolo correttore di flag, trasformare le sue regole in equazioni e trovare un input che faccia stampare il programma originale Correct!.

quadrati mascherati bandiera checker * Facile * Linux x86-64

Visualizza la sfida originale

Da un binario a una risposta controllata

  1. 01 * Trova il controlloStringhe → funzioni di controllo REA trova il prompt, i suoi riferimenti e il codice che accetta o rifiuta un input.
  2. 02 * Estrai le regole36 caratteri * 26 somme REA restituisce le istruzioni e i dati dietro ogni controllo. L'agente li trasforma in equazioni.
  3. 03 * Risolvere ed eseguireBandiera recuperata → Corretta!Uno script Python risolve le equazioni. REA cattura il programma originale accettando il risultato.
La sfida è di joseph, pubblicato nel repository ufficiale di DownUnderCTF.

Trova il codice di controllo

Il volantino è un eseguibile da 15 KB. Chiede una bandiera, poi stampa Correct! o Incorrect!. Inizia con una semplice richiesta al tuo agente.

Il tuo agente di codifica

Utilizzare REA per analizzare ms_flag_checker e trovare il flag. Spiega come funzionano i controlli, quindi verifica la risposta con il programma originale.

Un prompt di esempio, con la sfida scaricata disponibile localmente e un'analisi del provider di programmi di codice macchina collegato.

  1. Seguire il prompt di input per la sua funzione

    Agente → REA
    open_binary
    {"path": "ms_flag_checker"}
    
    search_strings
    {"pattern": "flag|correct|wrong|input",
     "mode": "regex", "case_sensitive": false}
    
    xrefs
    {"address": "0x102004"}
    
    resolve_containing_procedure
    {"address": "0x10126d"}
    REA → agente * risultati selezionati
    0x102004  "What is the flag? "
    0x10201c  "Incorrect!"
    0x102027  "Correct!"
    
    Prompt referenced at: 0x10126d
    Containing function: 0x10124d

    Il riferimento fornisce all'agente un posto in cui indagare, anche se i nomi delle funzioni originali dell'eseguibile sono stati rimossi.

  2. Leggi il correttore e i suoi due aiutanti

    Agente → REA
    analyze_function
    {"procedure": "0x10124d"}
    
    analyze_function
    {"procedure": "0x101189"}
    
    analyze_function
    {"procedure": "0x101217"}
    REA → agente * istruzioni selezionate
    0x1012c1: CMP EDI, 0x24
    0x1012c6: LEA RBX, [0x1040e0]
    0x1012cd: LEA RBP, [0x104060]
    0x1012d4: LEA R13, [RBX + 0x270]
    0x1012e1: CALL 0x00101189
    0x1012ec: CALL 0x00101217
    0x1012f1: CMP dword ptr [RBP], EAX
    0x1012f4: JNZ 0x00101335
    0x1012f6: ADD RBX, 0x18

    Il primo ciclo copia 36 codici di caratteri. Il ciclo di controllo decodifica una maschera, somma i codici selezionati e confronta il risultato con un numero memorizzato. Sua 0x18- passi byte attraverso 0x270 i byte danno 26 maschere.

Questi sono risultati selezionati da una nuova analisi REA. Il percorso di destinazione locale viene abbreviato per la visualizzazione; gli indirizzi si riferiscono all'immagine importata di REA.

Un controllo rivela un carattere

Il controllore organizza l'ingresso in una griglia 6×6. Una maschera sceglie quali cellule contribuiscono a una somma. La sua codifica compatta utilizza numeri negativi per saltare le celle e numeri positivi per selezionarli.

La settima maschera salta 21 celle, seleziona la posizione 21, quindi salta 14. Solo quella cella contribuisce alla somma. Il suo codice di carattere richiesto è 55, il che significa che il carattere è 7.
Il settimo controllo seleziona solo una posizione. Apri figura.

Leggi la maschera e il suo obiettivo dal binario

Agente → REA * read_bytes
{"address": "0x1040e0", "length": 624}
{"address": "0x104060", "length": 144}
REA → agente * settima voce
Mask at 0x104170:
eb 01 f2 00  →  -21, +1, -14, stop

Target at 0x104078:
37 00 00 00  →  55

Istruzione MOVSX legge i byte della maschera come valori firmati. Ecco perché eb significa -21. L'obiettivo è un numero intero little-endian. Insieme, questi byte dicono all'agente che code[21] = 55, in modo che il carattere è 7.

Dalle istruzioni a un controllo leggibile

Selezionare un passaggio per collegare l'helper sommatore e il suo chiamante alla stessa regola in C.

REA * istruzioni originali selezionate
0x10121c: MOV ECX, 0x0

0x10122c: CMP dword ptr [RSI + RAX*0x1], 0x0
0x101230: JZ 0x00101223

0x101232: ADD ECX, dword ptr [RDI + RAX*0x1]

0x101223: ADD RAX, 0x4

0x1012f1: CMP dword ptr [RBP], EAX
0x1012f4: JNZ 0x00101335
Leggibile C * riepilogo di un controllo
int check_one_mask(const int codes[36],
                   const int mask[36],
                   int target) {
    int total = 0;
    for (int i = 0; i < 36; ++i) {
        if (mask[i]) {
            total += codes[i];
        }
    }
    return total == target;
}

01 * Inizia da zero. ECX contiene la somma corrente.

Le istruzioni provengono dall'helper sommatore e dal suo chiamante. La C è un riassunto esplicativo con nomi descrittivi e un ciclo appiattito a 36 celle.

Risolvi le 26 equazioni

La maggior parte delle maschere seleziona diverse celle. Ad esempio, il primo controllo aggiunge 16 codici di caratteri e richiede un totale di 1441. Le selezioni sovrapposte danno equazioni che un piccolo script Python può risolvere insieme.

Python * estratto del risolutore
from z3 import Int, Or, Solver, Sum, sat

codes = [Int(f"code_{i}") for i in range(36)]
solver = Solver()
alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_{}"
for code in codes:
    solver.add(Or(*[code == ord(c) for c in alphabet]))
for code, char in zip(codes, "DUCTF{"):
    solver.add(code == ord(char))
solver.add(codes[-1] == ord("}"))

for selected, target in checks:
    solver.add(Sum([codes[i] for i in selected]) == target)

assert solver.check() == sat
model = solver.model()
print("".join(chr(model.eval(code).as_long()) for code in codes))

Z3 è un risolutore che trova valori che soddisfano queste equazioni. Questo estratto utilizza i controlli estratti e presuppone un DUCTF{…} bandiera con lettere, cifre, caratteri di sottolineatura e parentesi graffe. Il download completo include tutte le 26 maschere e obiettivi.

Scarica il risolutore completo

Controlla la risposta con il programma originale

L'acquisizione del processo di REA registra l'eseguibile originale accettando il flag risolto. Modifica di un carattere selezionato da z per y fa la prima somma 1440 invece di 1441, e il programma lo rifiuta.

Input Uscita osservata Codice di uscita
Bandiera del risolutore Correct! 0
Un personaggio cambiato Incorrect! 255
Mostra il flag recuperato e l'output catturato
REA * uscita del programma originale
What is the flag? DUCTF{ezzzpzzz_07bcda7bfe81faf43caa}
Correct!

Il valore recuperato corrisponde anche alla bandiera nei metadati della sfida pubblicati dagli organizzatori, controllati dopo aver risolto il binario.

Fonte, identità di destinazione e dettagli di analisi

Analisi fresche e due acquisizioni di processo l ' 8 ottobre 2026, utilizzando REA 4.1.0 con Ghidra 12.1.4 su Linux x64. Il binario è un ELF x86-64 spogliato, 15.248 byte.

Eseguibile originale * SHA-256
dcd3bec4f608e11f3a12ce461100aaf5f621851ee63a1f870d7c90d4e3dd51ae

I riferimenti di stringa, le funzioni e le costanti sono stati ispezionati prima di leggere la fonte o la soluzione degli organizzatori. Il risolutore Python e il diagramma sono stati costruiti da quei risultati REA.

Confronta con la fonte degli organizzatori · Metadati sfida e flag · Note di prova REA

Provalo tu stesso

Scarica la sfida originale e il risolutore in un'unica cartella. Utilizzare il prompt sopra per indagare con il proprio agente o eseguire lo script incluso.

Terminale * risolvere ed eseguire
python3 -m venv .venv
.venv/bin/python -m pip install z3-solver
.venv/bin/python solve.py

chmod +x ms_flag_checker
./ms_flag_checker

Lo script stampa un flag candidato; incollarlo al prompt del programma. Risolvere i bisogni di Python e z3-solver. L'esecuzione dell'eseguibile originale richiede Linux x86-64.

Configura REA con il tuo agente di codifica

Cima