Estudo de caso * DownUnderCTF 2023

Encontre a bandeira em
um binário CTF.

Use REA para inspecionar um pequeno verificador de bandeiras, transformar suas regras em equações e encontrar uma entrada que faça o programa original imprimir Correct!.

verificador Mascarado da bandeira dos quadrados * fácil * Linux x86-64

Veja o desafio original

De um binário para uma resposta verificada

  1. 01 * encontrar o chequeCadeias de caracteres extraterritoriais REA encontra o prompt, suas referências e o código que aceita ou rejeita uma entrada.
  2. 02 * extrair as regras36 caracteres * 26 somas REA retorna as instruções e os dados por trás de cada verificação. O Agente os transforma em equações.
  3. 03 * resolver e executarBandeira recuperada valuetech Correct!Um script Python resolve as equações. REA captura o programa original aceitando o resultado.
O desafio é de joseph, publicado no repositório oficial da DownUnderCTF.

Encontrar o código de verificação

O folheto é um executável de 15 KB. Pede uma bandeira, depois imprime Correct! ou Incorrect!. Comece com um simples pedido ao seu agente.

O seu agente de codificação

Use REA para analisar ms_flag_checker e encontrar o sinalizador. Explique como funcionam as verificações e, em seguida, verifique a resposta com o programa original.

Um exemplo de alerta, com o desafio baixado disponível localmente e uma análise do provedor de programas de código de máquina conectado.

  1. Siga o prompt de entrada para sua função

    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 extraterritorial * resultados seleccionados
    0x102004  "What is the flag? "
    0x10201c  "Incorrect!"
    0x102027  "Correct!"
    
    Prompt referenced at: 0x10126d
    Containing function: 0x10124d

    A referência dá ao Agente um local para investigar, mesmo que os nomes das funções originais do executável tenham sido removidos.

  2. Leia o verificador e seus dois ajudantes

    Agente REA
    analyze_function
    {"procedure": "0x10124d"}
    
    analyze_function
    {"procedure": "0x101189"}
    
    analyze_function
    {"procedure": "0x101217"}
    REA7 agente * instruções seleccionadas
    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

    O primeiro ciclo copia códigos de 36 caracteres. O ciclo de verificação descodifica uma máscara, soma os códigos seleccionados e compara o resultado com um número memorizado. Sua 0x18- passos byte através 0x270 bytes dar 26 máscaras.

Estes são resultados seleccionados de uma nova análise REA. O caminho de destino local é encurtado para exibição; os endereços referem-se à imagem importada de REA.

Uma verificação revela um carácter

O verificador organiza o input numa grelha de 6-6. Uma máscara escolhe quais células contribuem para uma soma. Sua codificação compacta usa números negativos para pular células e números positivos para selecioná-los.

A sétima máscara Pula 21 células, seleciona a posição 21 e, em seguida, Pula 14. Só essa célula contribui para a soma. Seu código de caracteres exigido é 55, o que significa que o caractere é 7.
A sétima verificação selecciona apenas uma posição. Figura aberta.

Leia a máscara e seu alvo a partir do binário

Agente REA * read_bytes
{"address": "0x1040e0", "length": 624}
{"address": "0x104060", "length": 144}
REA7agente * sétima entrada
Mask at 0x104170:
eb 01 f2 00  →  -21, +1, -14, stop

Target at 0x104078:
37 00 00 00  →  55

A instrução MOVSX lê bytes de máscara como valores assinados. É por isso que eb meios -21. O alvo é um número inteiro little-endian. Juntos, esses bytes informam ao agente que code[21] = 55, então esse personagem é 7.

Das instruções a um controlo legível

Selecione uma etapa para conectar o Auxiliar de soma e seu chamador à mesma regra em C.

REA * instruções originais selecionadas
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
C · resumo de uma verificação legível
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 * Comece em zero. ECX detém a soma corrente.

As instruções vêm do Auxiliar de Somação e do seu interlocutor. O C é um Resumo Explicativo com nomes descritivos e um loop de 36 células achatado.

Resolva as 26 equações

A maioria das máscaras seleciona várias células. Por exemplo, a primeira verificação adiciona 16 códigos de caracteres e requer um total de 1441. As seleções sobrepostas fornecem equações que um pequeno script Python pode resolver juntos.

Python * trecho do solver
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 é um solucionador que encontra valores que satisfazem essas equações. Este excerto utiliza as verificações extraídas e assume uma DUCTF{…} bandeira com letras, dígitos, sublinhados e chaves. O download completo inclui todas as 26 Máscaras e alvos.

Baixe o solucionador completo

Verifique a resposta com o programa original

A captura de processo do REA regista o executável original que aceita o sinalizador resolvido. Alterar um carácter seleccionado de z para y faz a primeira soma 1440 em vez de 1441, e o programa rejeita-a.

Entrada Resultados observados Código de saída
Bandeira do Solver Correct! 0
Um caractere alterado Incorrect! 255
Mostrar o sinalizador recuperado e a saída capturada
REA * saída original do programa
What is the flag? DUCTF{ezzzpzzz_07bcda7bfe81faf43caa}
Correct!

O valor recuperado também corresponde ao sinalizador nos metadados do Desafio publicados pelos organizadores, verificados após a resolução do binário.

Fonte, identidade do alvo e dados de análise

Nova análise e duas capturas de processo em 8 de outubro de 2026, utilizando REA 4.1.0 com Ghidra 12.1.4 em Linux x64. O binário é um Elf x86-64 despojado, 15.248 bytes.

Executável Original * SHA-256
dcd3bec4f608e11f3a12ce461100aaf5f621851ee63a1f870d7c90d4e3dd51ae

As referências, funções e constantes das cadeias de caracteres foram inspecionadas antes da leitura da fonte ou solução dos organizadores. O solucionador Python e o diagrama foram construídos a partir desses resultados REA.

Compare com a fonte dos organizadores · Metadados do Desafio e sinalizador · REA notas de prova

Experimente você mesmo

Baixe o desafio original e o solucionador em uma pasta. Use o prompt acima para investigar com seu agente ou execute o script incluído.

Terminal * resolver e executar
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

O script imprime um sinalizador candidato; cole-o no prompt do programa. Resolvendo necessidades Python e z3-solver. A execução do executável original Precisa de Linux x86-64.

Configurar REA com o seu agente de codificação

Top