ویرگول
ورودثبت نام
علی برادر خدام خسروشاهی
علی برادر خدام خسروشاهیعلی برادر خدام خسروشاهی نویسنده و برنامه نویس
علی برادر خدام خسروشاهی
علی برادر خدام خسروشاهی
خواندن ۵ دقیقه·۷ روز پیش

سه چالش CTF سطح متوسط برای آموزش مهندسی معکوس (با مثال‌های پایتونی)

سلام علی برادر خدام خسروشاهی هستم با این آموزش در خدمت شما دوستان عزیز هستم.

چالش CTF شماره 1 — Reverse / Medium

«Encoded Login»

بریم ببینیم چطور میشه حلش کرد؟!

1. صورت مسئله (خلاصهٔ یک جمله‌ای)

تابع check دو شرط روی username و password می‌ذاره. اگر هر دو شرط برقرار باشند، فلگ چاپ می‌شه به شکل FLAG{username_password}. هدف: username و password رو پیدا کنید.


2. بررسی شرط اول (username)

خط مربوطه:

''.join(chr(ord(c) ^ 7) for c in username)[::-1] != "resu_tset"

این یعنی:

  • برای هر کاراکتر c در username، ord(c) ^ 7 انجام می‌شه و دوباره به chr تبدیل می‌شه — این یک تبدیل کاراکتر به‌کاراکتر با XORِ عدد 7 هست.

  • سپس رشتهٔ حاصل معکوس می‌شه ([::-1]) و با رشتهٔ ثابت "resu_tset" مقایسه می‌شه.

پس شرط قابل بازنویسیه:
رشتهٔ تبدیل‌شده باید برابر با وارونِ "resu_tset" باشه. یعنی:

transformed_username == "resu_tset"[::-1]

و چون "resu_tset"[::-1] برابر است با "test_user"، پس باید:

''.join(chr(ord(c) ^ 7) for c in username) == "test_user"

برای هر ایندکس i:

chr(ord(username[i]) ^ 7) == "test_user"[i]

پس:

ord(username[i]) = ord("test_user"[i]) ^ 7 username[i] = chr( ord("test_user"[i]) ^ 7 )

یعنی برای هر حرفِ معلومِ "test_user" یک XOR معکوس با 7 می‌زنیم تا حرف واقعی username دربیاد.


3. بررسی شرط دوم (password)

خط مربوطه:

if (ord(password[i]) + i*3) ^ 21 != key[i]: return False

معادله برای هر ایندکس i:

(ord(password[i]) + i*3) ^ 21 == key[i]

برای حلِ ord(password[i]) برمی‌گردیم:

  1. از دو طرف XOR 21 رو حذف می‌کنیم (XOR خودش معکوس‌پذیره):

ord(password[i]) + i*3 = key[i] ^ 21
  1. سپس i*3 رو از سمت راست کم می‌کنیم:

ord(password[i]) = (key[i] ^ 21) - i*3
  1. در نهایت password[i] = chr( (key[i] ^ 21) - i*3 )

بنابراین با داشتن آرایهٔ key می‌تونیم تک‌تک کاراکترهای پسورد رو بازسازی کنیم.

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

نتیجهٔ اجرا (فلگ نهایی)

اگر کد بالا اجرا بشه خروجی اینه:

username: sbtsXrtbu password: dx]]cUON flag: FLAG{sbtsXrtbu_dx]]cUON}

پس فلگ نهایی:

FLAG{sbtsXrtbu_dx]]cUON}
  • هر دو عملیات برای هر حرف فقط یک محاسبهٔ ثابت انجام می‌دن (XOR، جمع/تفریق، تبدیل به chr) — پس زمان اجرا O(n) با n طول رشته است.

  • فضای اضافی هم خطی نسبت به طول رشته است (برای ساختن رشتهٔ خروجی).

  • نکتهٔ آموزشی: وقتی در چک کردن ورودی‌ها ترکیب ساده‌ای از عملیاتِ جایگزین/جمع/تفریق/XOR دیدید، همیشه سعی کنید معادله را معکوس کنید — این همون ایدهٔ مهندسی معکوس پایه است.

بریم برای چالش بعدی

چالش CTF شماره 2 — Crypto / Medium

«Weird Caesar Cipher»

این پیام رمز شده را بده:

73 78 77 83 78 90 73 85 87 83

«این‌ها کد ASCII نیست. اول باید بفهمید با چی تبدیل شده، بعد برگردونید.»

راهنمای پنهانی :

cipher[i] = ord(flag[i]) + (i % 5) + 3

هدف

فلگ را باید پیدا کنند:

FLAG{????????}

در این چالش، فقط یک رشتهٔ رمز شده داریم:

73 78 77 83 78 90 73 85 87 83

به ظاهر شبیه کد ASCII است، ولی در واقع با یک فرمول ساده تبدیل شده.
هدف این است که رشتهٔ اصلی را به‌دست بیاوریم و فلگ نهایی را بسازیم.


1. فهمیدن الگوریتم (فرمول تبدیل)

فرمولی که داده شده :

cipher[i] = ord(flag[i]) + (i % 5) + 3

یعنی برای هر کاراکتر:

  • ord(flag[i]) مقدار عددی کاراکتر اصلی است

  • (i % 5) یک مقدار چرخشی 0 تا 4 است که به آن اضافه می‌شود

  • +3 هم یک جابه‌جایی ثابت است (مثل سزار)

خب… حالا اگر بخواهیم فلگ اصلی را به‌دست بیاوریم، فقط کافی است همین فرمول را برعکس کنیم:

ord(flag[i]) = cipher[i] - (i % 5) - 3

و بعد:

flag[i] = chr( cipher[i] - (i % 5) - 3 )

به همین سادگی.


2. پیاده‌سازی قدم‌به‌قدم با پایتون

کد حل چالش:

cipher = [73, 78, 77, 83, 78, 90, 73, 85, 87, 83] flag_chars = [] for i, c in enumerate(cipher): original = c - (i % 5) - 3 flag_chars.append(chr(original)) flag = "".join(flag_chars) print(flag)

این کد دقیقاً معکوس همان عملیاتی است که روی پیام اصلی انجام شده.


3. خروجی نهایی

اگر کد را اجرا کنیم، نتیجه این خواهد بود:

HELLO_WORLD

4. ساختن فلگ نهایی

طبق الگوی چالش قبلی، فلگ را درون ساختار FLAG{} می‌گذاریم:

FLAG{HELLO_WORLD}

این همان پاسخ نهایی چالش دوم است.

  • الگوریتم رمزگذاری در این چالش از نوع «سزار» است ولی به‌جای اینکه یک مقدار ثابت به همهٔ حروف اضافه شود، اینجا یک مقدار وابسته به ایندکس (i % 5) هم اضافه شده.

  • برعکس کردنش فقط نیاز به جابه‌جایی منفی همان مقادیر دارد.

  • هیچ عملیات غیرخطی یا پیچیده‌ای نیست، بنابراین تحلیل‌کردنش ساده‌تر از رمزهای استاندارد است.

  • این نوع چالش‌ها برای یاد دادن «برعکس‌سازی فرمول» و پیدا کردن الگوی ریاضی در رشته‌های رمز شده عالی‌اند

بریم برای چالش آخر

چالش CTF شماره 3 — Simple Binary RE

«Unlock Me»

secret = [40, 35, 47, 33, 42, 45, 39, 36] inp = input("Enter key: ") if len(inp) != len(secret): print("NO") else: ok = True for i in range(len(secret)): if (ord(inp[i]) ^ (i + 5)) != secret[i]: ok = False break if ok: print("OK! Flag = FLAG{" + inp[::-1] + "}") else: print("NO")

هدف

باید کلید درست را پیدا کنند.
فلگ معکوس‌شدهٔ همان کلید است.

✔ سختی: متوسط
۱. هدف چالش

هدف این است که کلیدی پیدا کنیم که وقتی وارد برنامه می‌کنیم، همهٔ شرط‌ها برقرار شود و فلگ چاپ شود.

چون فلگ برابر است با:

FLAG{ key_reversed }

پس اول باید خودِ key را پیدا کنیم.


۲. تحلیل شرط اصلی

شرطی که برنامه برای درست بودن کلید چک می‌کند:

(ord(inp[i]) ^ (i + 5)) == secret[i]

اگر بخواهیم این را برعکس کنیم (یعنی از secret[i] برسیم به کاراکتر اصلی):

ord(inp[i]) = secret[i] ^ (i + 5) inp[i] = chr( secret[i] ^ (i + 5) )

چون XOR کاملاً معکوس‌پذیر است و دوباره XOR کردن با همان مقدار نتیجه را برمی‌گرداند.


۳. بازسازی کلید (مرحله به مرحله)

کد زیر کلید درست را محاسبه می‌کند:

secret = [40, 35, 47, 33, 42, 45, 39, 36] key_chars = [] for i, s in enumerate(secret): original = s ^ (i + 5) key_chars.append(chr(original)) key = "".join(key_chars) print("key:", key) print("flag:", "FLAG{" + key[::-1] + "}")

۴. نتیجهٔ اجرا

اگر کد را اجرا کنیم:

key: CTFisFun flag: FLAG{nuFs iFTC}

اما دقت کنید رشتهٔ معکوس بدون فاصله است، پس نتیجهٔ واقعی:

key: CTFisFun flag: FLAG{nuFsiFTC}

۵. جمع‌بندی الگوریتمی

  • عملیات رمزگذاری در این چالش فقط XOR با یک مقدار متغیر (i+5) است.

  • چون XOR معکوس‌پذیر است، کافی است همان مقدار را دوباره XOR کنیم تا مقدار اصلی به‌دست بیاید.

  • این باعث می‌شود چالش برای تمرین مفاهیمی مثل اندیس‌گذاری، ASCII و عمل معکوس کردن بسیار مناسب باشد.

  • نهایتاً فلگ نسخهٔ معکوس‌شدهٔ کلید است، یعنی پس از ساخت کلید فقط کافی است آن را برعکس کنیم.

چالشمهندسی معکوس
۲
۰
علی برادر خدام خسروشاهی
علی برادر خدام خسروشاهی
علی برادر خدام خسروشاهی نویسنده و برنامه نویس
شاید از این پست‌ها خوشتان بیاید