چالش اول شترگاوپلنگ - خشت خام
در توضیح سوال این طور داده شده است:
xor -f raw -s "**...*\n" > raw.out
بنابراین، در اولین گام از ابزار xor-tools
استفاده میکنیم. این ابزار توسط Aleksei Udovenko توسعه داده شده که در حوزهی رمزنگاری متخصص است و در CTF با نام مستعار hellman شناخته شده است.
با کمی تلاش، متوجه میشویم که این ابزار، روی این پرونده کارگشا نیست و به نظر میآید که پروندهی اصلی، از جنس متن نبوده که بتوان با این ابزار xor را شکست. احتمالا، پروندهی اصلی باینری بوده و با همین فرض هم به ادامهی حل سوال میپردازیم. پروندهی اصلی میتواند یک پروندهی اجرایی، یک تصویر و یا چیزهای دیگری باشد. در هر صورت، بایستی در ابتدای آن، امضای پرونده (file signature) مشخص شده باشد.
ابتدا پروندهی raw را با یک ویرایشگر هگزادسیمال (مثلا GHex) باز میکنیم. امیدواریم که بتوانیم با حدس زدن امضاهای مختلف، کلید را بفهمیم. اما نیازی به این کار نیست، در همان نگاه اول متوجه واژهی key در ویرایشگر خواهیم شد. اگر این واژه را در ادامه هم جستجو کنیم، میبینیم که یک بار دیگر در انتهای فایل تکرار شده. محل اول در بایت ۲۶ و محل دوم در بایت ۱۸۸۵ است. میدانیم که بایستی بزرگترین مقسوم علیه مشترک این دو عدد، بر طول کلید xor بخشپذیر باشد. از قضا، ب.م.م. این دو عدد ۱۳ است و بنابراین، طول کلید فقط میتواند ۱۳ باشد.
مطلب مهمی را فهمیدهایم. اکنون میتوانیم ۱۳ بایت ابتدایی پروندهی باینری را بررسی کنیم تا خود کلید را هم به دست آوریم. سه حرف ابتدای کلید، یعنی key، را میدانیم. پس میتوان سه بایت ابتدای پرونده را هم به دست آورد.
'key' xor '\xE257' = '\x89PN' = '\x89\x50\x4E'
با یک جستجوی ساده متوجه میشویم که پروندهی اصلی از جنس PNG بوده است. بنابراین یک بایت دیگر هم از کلید به دست آوردیم! مستندات خوبی در مورد پروندهی PNG وجود دارد (مثلا ویکی آن) و با استفاده از آنها میتوانیم بایتهای بعدی کلید را هم به دست آوریم. در نهایت، کلید برابر با عبارت key is 31337\n
به دست میآید.
اکنون میتوانیم پروندهی اصلی را بازیابی کنیم. با قطعهکد زیر، این کار انجام میشود:
key = b'key is 31337\n'
raw = open('raw_e3f5aab232bf56b77219a9df5f267d18.out', 'rb').read()
out = open('output.png', 'wb')
result = b''
for i in range(len(raw)):
result += (raw[i] ^ key[i % 13]).to_bytes(1, 'big')
out.write(result)
out.close()
با مشاهدهی تصویر به دست آمده، متوجه میشویم که با یک QR code مواجه هستیم اما این کد از میان نصف شده و غیرقابل استفاده است. همچنان به نظر میرسد که رنگ سیاه و سفید آن برعکس شده است. با کمی جستجو در مورد QR متوجه میشویم که یک QR به صورت نصف شده، قطعا قابل بازیابی نیست. پس به دو حالت میرسیم، یا سوال غیرقابل حل است و یا اطلاعاتی درون خود تصویر پنهان شده است.
تصویر را با file
بررسی میکنیم.
file output.png
output.png: PNG image data, 966 x 483, 1-bit grayscale, non-interlaced
متاسفانه از اینجا هم به نتیجهای نمیرسیم. اما یک حدس وجود دارد و آن هم این که در قسمت IHDR مربوط به تصویر، ارتفاع تصویر دستکاری شده باشد. با کمک یک ویرایشگر هگزادسیمال، مقدار ارتفاع را برابر با ۹۶۶ قرار میدهیم تا تصویر مربعی شود. همچنین بایستی CRC مربوط به IHDR را هم تغییر دهیم و متناسب با مقدار جدید تصحیحش کنیم.
بعد از این کار متوجه میشویم که حدسمان درست بوده و تصویر به صورت کامل قابل مشاهده است. اکنون سیاه و سفید را باید با مثلا یک ابزار آنلاین و یا ابزارهای ویرایشگر تصویر، برعکس کنیم. سپس تصویر کامل و درست QR را داریم و میتوانیم مثلا باز هم با یک ابزار آنلاین آن را دیکد کنیم. با دیکد کردن آن، به عبارت زیر میرسیم:
UEsDBAoACQAAACuoV1IrfYlxNgAAACoAAAAIABwAZmxhZy50eHRVVAkAA+k7NWAN
PDVgdXgLAAEE
6AMAAAToAwAA/1gwVsowAjNPajk4kBvbjyNWaDVJWrTl2x3YtFDWh+SR3kPvE/36
7VwYqYmmuvTs
2ol1SvdSUEsHCCt9iXE2AAAAKgAAAFBLAQIeAwoACQAAACuoV1IrfYlxNgAAACoA
AAAIABgAAAAA
AAEAAACkgQAAAABmbGFnLnR4dFVUBQAD6Ts1YHV4CwABBOgDAAAE6AMAAFBLBQYA
AAAAAQABAE4A
AACIAAAAAAA=
این یک عبارت به صورت base64 است. آن را هم با base64 -d
دیکد میکنیم و به یک عبارت میرسیم که نامفهوم است و مشخصا باینری است. بنابراین آن را در یک فایل قرار داده و دستور file
را روی آن اجرا میکنیم و متوجه میشویم که با یک پروندهی ZIP مواجه هستیم.
تلاش میکنیم که آن را unzip کنیم اما نیاز به گذرواژه دارد! اما پیش از این، در مرحلهی رمزگشایی از XOR، ذکر شده بود که کلید 31337 است! از آن استفاده میکنیم و پرچم به دست میآید:
parcham{7b2ecfd62c217f3401448b5a9279dc47}