مطالعه موردی · DownUnderCTF 2023

پرچم را در
یک باینری CTF.

از REA برای بازرسی یک چک کننده پرچم کوچک استفاده کنید ، قوانین آن را به معادلات تبدیل کنید و ورودی را پیدا کنید که برنامه اصلی را چاپ کند Correct!.

مربع نقاب دار چک پرچم * آسان * Linux x86-64

چالش اصلی را مشاهده کنید

از یک باینری به یک پاسخ چک شده

  1. 01 * چک را پیدا کنیدرشته ها → بررسی توابع REA پیام ، مرجع های آن و کد را پیدا می کند که ورودی را قبول یا رد می کند.
  2. 02 * قوانین را استخراج کنید36 کاراکتر * 26 مجموع REA دستورالعمل ها و داده های پشت هر چک را باز می گرداند. عامل آنها را به معادلات تبدیل می کند.
  3. 03 * حل و اجراپرچم بازیابی → درست است!یک اسکریپت پایتون معادلات را حل می کند. REA برنامه اصلی پذیرش نتیجه را ضبط می کند.
چالش توسط جوزف است که در مخزن رسمی DownUnderCTF منتشر شده است.

کد چک کردن را پیدا کنید

این کتابچه یک فایل اجرایی 15 کیلو بایت است. پرچم ميخواد ، بعدش چاپ ميکنه Correct! یا Incorrect!. با یک درخواست ساده به نماینده خود شروع کنید.

عامل برنامه نویسی شما

از REA برای تجزیه و تحلیل ms_flag_checker و پیدا کردن پرچم استفاده کنید. نحوه کار چک ها را توضیح دهید ، سپس پاسخ را با برنامه اصلی تأیید کنید.

یک مثال سریع، با چالش دانلود شده در دسترس محلی و تجزیه و تحلیل ارائه دهنده برنامه های کد ماشین متصل شده است.

  1. از دستور ورودی به تابع آن پیروی کنید

    نماینده → 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 → عامل * نتایج انتخاب شده
    0x102004  "What is the flag? "
    0x10201c  "Incorrect!"
    0x102027  "Correct!"
    
    Prompt referenced at: 0x10126d
    Containing function: 0x10124d

    مرجع به مامور جایی برای تحقیق می دهد ، حتی اگر نام های اصلی تابع اجرایی حذف شده باشند.

  2. چک کننده و دو کمک کننده اش رو بخون

    نماینده → REA
    analyze_function
    {"procedure": "0x10124d"}
    
    analyze_function
    {"procedure": "0x101189"}
    
    analyze_function
    {"procedure": "0x101217"}
    REA → عامل * دستورالعمل های انتخاب شده
    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

    حلقه اول 36 کد کاراکتر را کپی می کند. حلقه چک کردن یک ماسک را رمزگشایی می کند ، کدهای انتخاب شده را جمع می کند و نتیجه را با یک عدد ذخیره شده مقایسه می کند. اون 0x18- گام های بایت در سراسر 0x270 بایت ها 26 ماسک می دهند.

این نتایج از تجزیه و تحلیل REA تازه انتخاب شده است. مسیر هدف محلی برای نمایش کوتاه می شود ؛ آدرس ها به تصویر وارد شده REA مراجعه می کنند.

یک چک یک شخصیت را نشان می دهد

چک کننده ورودی را در یک شبکه 6×6 مرتب می کند. ماسک انتخاب می کند که کدام سلول ها به جمع کمک می کنند. کدگذاری جمع و جور آن از اعداد منفی برای حذف سلول ها و اعداد مثبت برای انتخاب آنها استفاده می کند.

ماسک هفتم 21 سلول را رد می کند ، موقعیت 21 را انتخاب می کند ، سپس 14 را رد می کند. فقط اون سلول به جمع کمک ميکنه کد کاراکتر مورد نیاز آن 55 است ، به این معنی که کاراکتر 7 است.
بررسی هفتم فقط یک موقعیت را انتخاب می کند. شکل باز.

ماسک و هدف آن را از باینری بخوانید

نماینده → REA * read_bytes
{"address": "0x1040e0", "length": 624}
{"address": "0x104060", "length": 144}
REA → عامل * ورودی های هفتم
Mask at 0x104170:
eb 01 f2 00  →  -21, +1, -14, stop

Target at 0x104078:
37 00 00 00  →  55

دستورالعمل MOVSX بایت های ماسک را به عنوان مقادیر امضا شده می خواند. به همین دلیل است eb به معنی -21 هدف یک عدد صحیح اندکی است. با هم ، این بایت ها به عامل می گویند که code[21] = 55، پس اون شخصیت 7.

از دستورالعمل ها تا چک قابل خواندن

یک مرحله را برای اتصال کمک کننده جمع آوری و تماس گیرنده آن به همان قانون در C انتخاب کنید.

REA * دستورالعمل های اصلی انتخاب شده
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 * یک چک خلاصه
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 * از صفر شروع کنید. ECX مبلغ در حال اجرا را نگه می دارد.

دستورالعمل ها از طرف کمک کننده جمع آوری و تماس گیرنده اش می آید. C یک خلاصه توضیحی با نام های توصیفی و یک حلقه 36 سلولی مسطح است.

معادلات 26 را حل کنید

اکثر ماسک ها چندین سلول را انتخاب می کنند. به عنوان مثال ، اولین چک 16 کد کاراکتر اضافه می کند و در مجموع 1441 مورد نیاز دارد. انتخاب های همپوشانی معادلاتی را ارائه می دهند که یک اسکریپت کوچک پایتون می تواند با هم حل کند.

پایتون * گزیده حل کننده
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 یک حل کننده است که مقادیر را برای برآورده کردن این معادلات پیدا می کند. این گزیده از چک های استخراج شده استفاده می کند و فرض می کند DUCTF{…} پرچم با حروف ، ارقام ، زیرنویس ها و بریس ها. دانلود کامل شامل تمام 26 ماسک و هدف است.

دانلود حل کننده کامل

پاسخ را با برنامه اصلی بررسی کنید

ضبط فرآیند REA ، فایل اجرایی اصلی را که پرچم حل شده را قبول می کند ، ثبت می کند. تغییر یک کاراکتر انتخاب شده از z به y اولین مبلغ 1440 را به جای 1441 می سازد و برنامه آن را رد می کند.

ورودی خروجی مشاهده شده کد خروج
پرچم حل کننده Correct! 0
یک شخصیت تغییر کرد Incorrect! 255
نشان دادن پرچم بازیابی شده و خروجی گرفته شده
REA * خروجی برنامه اصلی
What is the flag? DUCTF{ezzzpzzz_07bcda7bfe81faf43caa}
Correct!

مقدار بازیابی شده همچنین با پرچم در متا داده های چالش منتشر شده سازمان دهندگان مطابقت دارد که پس از حل باینری بررسی شده است.

منبع ، هویت هدف و جزئیات تجزیه و تحلیل

تجزیه و تحلیل تازه و دو فرآیند ضبط در 8 اکتبر 2026 ، با استفاده از REA 4.1.0 با Ghidra 12.1.4 در Linux x64. باینری یک ELF x86-64 است که 15248 بایت است.

اجرایی اصلی * SHA-256
dcd3bec4f608e11f3a12ce461100aaf5f621851ee63a1f870d7c90d4e3dd51ae

مرجع های رشته ای ، توابع و ثابت ها قبل از خواندن منبع یا راه حل سازمان دهندگان بازرسی شدند. حل کننده پایتون و نمودار از نتایج REA ساخته شده است.

با منبع سازمان دهندگان مقایسه کنید · چالش متا داده ها و پرچم · یادداشت های شواهد REA

خودتان امتحان کنید

چالش اصلی و حل کننده را در یک پوشه دانلود کنید. از دستور بالا برای تحقیق با نماینده خود استفاده کنید یا اسکریپت همراه را اجرا کنید.

ترمینال * حل و اجرا
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

اسکریپت پرچم کاندیداها را چاپ می کند ؛ آن را در دستور برنامه چسبانید. حل نیازها پایتون و z3-solver. اجرای فایل اجرایی اصلی نیاز به Linux x86-64 دارد.

REA را با عامل کدگذاری خود تنظیم کنید

بالا