---
title: 'CTF Reverse Engineering: DownUnderCTF Flag Checker-REA'
url: https://rea.tools/pl/showcase/ctf/
---

[Spis treści](https://rea.tools/pl/) / [Gabloty](https://rea.tools/pl/showcase/) / CTF

Studium przypadku \* DownUnderCTF 2023

# Znajdź flagę w binarny CTF.

Użyj REA, aby sprawdzić mały kontroler flag, przekształcić jego reguły w równania i znaleźć Dane wejściowe, które sprawiają, że oryginalny program drukuje `Correct!`.

maskowane kwadraty FLAG checker \* Easy \* Linux x86-64

[Zobacz oryginalne wyzwanie](https://github.com/DownUnderCTF/Challenges_2023_Public/tree/b48f83db2984bc7fa2ec7879a32d7efb1be8d333/rev/masked-squares-flag-checker)

Od binarnej do sprawdzonej odpowiedzi

1. 01 \* Znajdź czek

   **Ciągi → sprawdzanie funkcji**

   REA znajduje monit, jego odwołania i kod, który akceptuje lub odrzuca dane wejściowe.
2. 02 \* Wyodrębnij Zasady

   **36 znaków · 26 Sum**

   REA zwraca instrukcje i dane za każdym czekiem. Agent zamienia je w równania.
3. 03 \* rozwiązać i uruchomić

   **Odzyskana flaga → poprawna!**

   Skrypt Pythona rozwiązuje równania. REA przechwytuje oryginalny program akceptujący wynik.

Wyzwanie jest autorstwa Josepha, opublikowane w oficjalnym repozytorium DownUnderCTF.

## Znajdź kod kontrolny

Materiały informacyjne to plik wykonywalny o wielkości 15 KB. Prosi o flagę, a następnie drukuje `Correct!` lub `Incorrect!`. Zacznij od prostej prośby do swojego agenta.

Twój agent kodowania

Użyj REA, aby przeanalizować ms_flag_checker i znaleźć flagę. Wyjaśnij, jak działają kontrole, a następnie zweryfikuj odpowiedź za pomocą oryginalnego programu.

Przykładowy monit z pobranym wyzwaniem dostępnym lokalnie i analizą podłączonego dostawcy programów kodu maszynowego.

1. #### Postępuj zgodnie z monitem wejściowym do jego funkcji

   Agent → 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 → agent \* wybrane wyniki

   ```
   0x102004  "What is the flag? "
   0x10201c  "Incorrect!"
   0x102027  "Correct!"

   Prompt referenced at: 0x10126d
   Containing function: 0x10124d
   ```

   Odwołanie daje agentowi miejsce do zbadania, mimo że oryginalne nazwy funkcji pliku wykonywalnego zostały usunięte.
2. #### Przeczytaj kontroler i jego dwóch pomocników

   Agent → REA

   ```
   analyze_function
   {"procedure": "0x10124d"}

   analyze_function
   {"procedure": "0x101189"}

   analyze_function
   {"procedure": "0x101217"}
   ```

   REA → agent \* wybrane instrukcje

   ```
   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
   ```

   Pierwsza pętla kopiuje 36 kodów znaków. Pętla sprawdzania dekoduje maskę, sumuje wybrane kody i porównuje wynik z zapisaną liczbą. Jego `0x18`- bajtowe kroki w poprzek `0x270` bajty dają 26 masek.

Są to wybrane wyniki ze świeżej analizy REA. Lokalna ścieżka docelowa jest skrócona do wyświetlania; adresy odnoszą się do importowanego obrazu REA.

## Jeden czek ujawnia jedną postać

Kontroler układa dane wejściowe w siatce 6×6. Maska wybiera, które komórki przyczyniają się do sumy. Jego kompaktowe kodowanie wykorzystuje liczby ujemne do pomijania komórek i liczby dodatnie do ich wybierania.

![Siódma Maska pomija 21 komórek, wybiera pozycję 21, a następnie pomija 14. Tylko ta komórka przyczynia się do sumy. Wymagany kod znaku to 55, co oznacza, że znak to 7.](https://rea.tools/assets/localized/pl/figures/ctf-mask-equation.svg)

Siódmy czek wybiera tylko jedną pozycję. [Otwórz rysunek](https://rea.tools/assets/localized/pl/figures/ctf-mask-equation.svg).

### Odczytaj maskę i jej cel z pliku binarnego

Agent → REA \* read_bytes

```
{"address": "0x1040e0", "length": 624}
{"address": "0x104060", "length": 144}
```

REA → agent \* siódme wpisy

```
Mask at 0x104170:
eb 01 f2 00  →  -21, +1, -14, stop

Target at 0x104078:
37 00 00 00  →  55
```

Instrukcja `MOVSX` odczytuje bajty maski jako wartości podpisane. Właśnie dlatego `eb` oznacza -21. Celem jest liczba całkowita little-endian. Razem te bajty mówią agentowi, że `code[21] = 55`, więc ta postać jest `7`.

## Od instrukcji do czytelnego czeku

Wybierz krok, aby połączyć pomocnika sumowania i jego wywołującego z tą samą regułą w C.

REA \* wybrane oryginalne instrukcje

```
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
```

Czytelne podsumowanie C \* one-check

```
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 \* zacznij od zera ·**  `ECX` trzyma bieżącą sumę.

**02 \* Sprawdź komórkę maski.** Wartość zerowa pomija znak; wartość niezerowa go zawiera.

**03 \* Dodaj kod znaku ·**  Liczba całkowita wejścia przy tym samym przesunięciu jest dodawana do sumy.

**04 \* przejdź do następnej komórki.** Oryginalna pętla przesuwa cztery bajty na liczbę całkowitą i odwiedza sześć wierszy po sześć komórek.

**05 \* Porównaj z zapisanym celem.** Dzwoniący otrzymuje sumę w `EAX`. Niedopasowanie skacze do `Incorrect!`.

Instrukcje pochodzą od pomocnika sumującego i jego dzwoniącego. C jest podsumowaniem wyjaśniającym z opisowymi nazwami i spłaszczoną pętlą 36 komórek.

## Rozwiąż 26 równań

Większość masek wybiera kilka komórek. Na przykład pierwsze sprawdzenie dodaje 16 kodów znaków i wymaga łącznie 1441. Nakładające się zaznaczenia dają równania, które mały skrypt Pythona może rozwiązać razem.

Python \* solver fragment

```
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 to solver, który znajduje wartości spełniające te równania. Ten fragment wykorzystuje wyodrębnione kontrole i zakłada `DUCTF{…}` flaga z literami, cyframi, podkreśleniami i nawiasami klamrowymi. Pełne pobieranie obejmuje wszystkie 26 masek i celów.

[Pobierz kompletny solver](https://rea.tools/showcase/ctf/solve.py)

## Sprawdź odpowiedź za pomocą oryginalnego programu

REA przechwytywanie procesu rejestruje oryginalny plik wykonywalny akceptujący rozwiązaną flagę. Zmiana jednego wybranego znaku z `z` do `y` tworzy pierwszą sumę 1440 zamiast 1441, a program ją odrzuca.

| Wejście | Obserwowane wyjście | Kod wyjścia |
| --- | --- | --- |
| Flaga solvera | `Correct!` | 0 |
| Jedna postać się zmieniła | `Incorrect!` | 255 |

Pokaż odzyskaną flagę i przechwycone dane wyjściowe

REA \* oryginalne wyjście programu

```
What is the flag? DUCTF{ezzzpzzz_07bcda7bfe81faf43caa}
Correct!
```

Odzyskana wartość pasuje również do flagi w opublikowanych przez organizatorów metadanych wyzwania, sprawdzonych po rozwiązaniu pliku binarnego.


Źródło, tożsamość docelowa i szczegóły analizy

Nowa analiza i dwa przechwytywanie procesów w dniu 8 października 2026 r.przy użyciu REA 4.1.0 z Ghidra 12.1.4 na Linux x64. Plik binarny to pozbawiony x86-64 ELF, 15 248 bajtów.

Oryginalny plik wykonywalny \* SHA-256

```
dcd3bec4f608e11f3a12ce461100aaf5f621851ee63a1f870d7c90d4e3dd51ae
```

Odniesienia do ciągów, funkcje i stałe zostały sprawdzone przed przeczytaniem źródła lub rozwiązania organizatorów. Solver Python i diagram zostały zbudowane z tych wyników REA.

[Porównaj ze źródłem organizatorów](https://github.com/DownUnderCTF/Challenges_2023_Public/blob/b48f83db2984bc7fa2ec7879a32d7efb1be8d333/rev/masked-squares-flag-checker/src/ms_flag_checker.c) · [Metadane wyzwania i flaga](https://github.com/DownUnderCTF/Challenges_2023_Public/blob/b48f83db2984bc7fa2ec7879a32d7efb1be8d333/rev/masked-squares-flag-checker/ctfcli.yaml) ·  [REA dowody uwagi](https://github.com/morluto/rea/blob/main/website/evidence/ctf-masked-squares.md)

## Spróbuj sam

Pobierz oryginalne wyzwanie i solver do jednego folderu. Użyj powyższego monitu, aby zbadać sprawę z agentem lub uruchom dołączony skrypt.

[Pobierz oryginalne wyzwanie](https://raw.githubusercontent.com/DownUnderCTF/Challenges_2023_Public/b48f83db2984bc7fa2ec7879a32d7efb1be8d333/rev/masked-squares-flag-checker/publish/ms_flag_checker)[Pobierz solver](https://rea.tools/showcase/ctf/solve.py)

Terminal \* Rozwiąż i uruchom

```
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
```

Skrypt drukuje flagę kandydata; wklej go w monicie programu. Rozwiązywanie potrzeb Python i `z3-solver`. Uruchomienie oryginalnego pliku wykonywalnego wymaga Linux x86-64.

[Skonfiguruj REA z agentem kodującym](https://rea.tools/get-started/)
