فروردین امسال (1402) کوئرا یک مسابقه مسابقه فتح پرچم (یا همون CTF) برگزار کرد با نام هکاتون. ثبتنام مسابقه تا 23ام اسفندماه 1401 ادامه داشت و شما میتونستید پس از پرداخت هزینه نسبتا سنگین (480)، برای مسابقه و 18 ساعت آموزش (نه چندان با کیفیت) اقدام کنید. در بخش معرفی رویداد این مطالب نوشته شده بود:
رویداد هکاتون امنیت، چهارمین هکاتون برنامهنویسی کوئرا است که با موضوع امنیت و در چارچوب طرح شهید بابایی بنیاد ملی نخبگان برگزار میشود.
این رویداد شامل یک بخش آموزشی و یک بخش رقابتی است. در ابتدا، موضوعات جذاب و کاربردی حوزه امنیت در ۳ روز و با همراهی اساتید برتر این حوزه برگزار میشود و شما مجموعا ۱۸ ساعت آموزش میبینید. بعد از آموزش به تیمهای ۲ الی ۴ نفره تقسیم میشوید و در یک مسابقه چالشی به رقابت میپردازید. بعد از مسابقه راهحل تیمها داوری میشود و نفرات برتر مشمول دریافت امتیاز نخبگی بنیاد و همینطور برنده جایزه نقدی مسابقه میشوند. علاوه بر این نفرات برتر برای استخدام به شرکتهای مطرح معرفی خواهند شد. برای مشاهده مراحل و زمانبندی رویداد روی این لینک کلیک کنید.
? به تمام شرکتکنندگان، گواهی شرکت در رویداد اهدا خواهد شد اما فقط نفرات برتر مسابقه و بعد از داوری راهحلها، مشمول دریافت امتیاز نخبگی بنیاد میشوند.
⚠️ شرکت در رویداد به صورت فردی است اما پیش از مسابقه، شرکتکنندگان به تیمهای ۲ الی ۴ نفره تقسیم میشوند تا به صورت تیمی به رقابت بپردازند. اگر از ابتدا تیم شما مشخص است و دوست دارید با تیم خود در این رویداد شرکت کنید لطفا به صورت جدا جدا ثبتنام خود را تکمیل کنید و بعد از ثبتنام به ما اطلاع دهید که میخواهید در یک تیم باشید.
برای برگزاری رویداد از پلتفرم CTFd استفاده شده بود و تیم کوئرا چند روز قبل از مسابقه، با هدف آشنایی بچهها با پلتفرم یک کوییز آزمایشی (و بدون تاثیر در نتایج مسابقه) قرار داد. سوالات این کوییز از رویدادهایی مثل picoctf و uutctf انتخاب شده بودند و به عنوان دست گرمی کمک بزرگی محسوب میشد. در پرانتز این هم بگم که سوالات مسابقه با اختلاف....باااا اختلااااف، سختتر و جذابتر بودند.
امتیاز: 200
متن سوال:
Extract the flag from the video.
The flag is in queraCTF{somthing} format. something is a text containing lowercase letters and _.
راهنمایی: ships used this to communicate.
ویدئو: لینک
توجه: متاسفانه ویدئو این سوال در میانه مسابقه جایگزین شد. ویدئو اول در این لینک قرار داره.
با دیدن این ویدئو و راهنمایی سوال خیلی سریع میشه متوجه شد که با کد مورس طرفیم. قبل از ارائه راه حل سوال کمی درباره کد مورس توضیح میدم.
کد موردس یکی از روشهای اولیه کدگذاری متن محسوب میشه و کاری که میکنه اینه که هر کاراکتر البفا انگلیسی (شامل a-z0-9 و کارکترهایی مثل / و ? و غیره) را در قالب یک الگو از نقطه و خط نمایش میده. با یه سرچ ساده morse code table میشه جدول کد مورس برای کاراکترهای مختلف را پیدا کرد. همینطور میشه از CyberChef برای تولید کد مورس استفاده کرد.
اگر فرستنده قصد ارسال پیامی در قالب کد مورس را داشته باشه، باید کارکتر به کاراکتر، متنش را به الگوهای مورس ترجمه کنه و با تنظیم مکث بین ارسال نقطه و خطها و مکث بین کاراکترها، متن را ارسال کنه. فرضا اگر قصد داشته باشیم متن Hello Wrold را ارسال کنیم، کد مورس معادل میشه مثل زیر. دقت کنید که حروف بزرگ و کوچیک اهمیتی ندارند.
Hello: .... . .-.. .-.. ---
World: .-- --- .-. .-.. -..
کسی که کد را ارسال میکنه (چه با تلگراف و چه با نور یا هر روش دیگه) میاد و به ازای هر نقطه یک مدت زمان کوتاه سیگنال میفرسته (مثلا لامپ را روشن میکنه) و به ازای هر خط یک مدت زمان بلندتر سیگنال را میفرسته. همینطور بین ارسال نقطه و خطهای یک کاراکتر از مکث کوتاه استفاده میکنه و بین ارسال کاراکترهای مختلف از فاصله بلندتری استفاده میکنه (ارسال eee و s را در CyberChef بررسی کنید).
در این چالش، وجود لوگوی کوئرا در یک فریم معادل ارسال سیگنال در مورس در نظر گرفته شده و نبود لوگو به معنی عدم ارسال سیگناله. متاسفانه در ط.ل انجام مسابقه نونستم ابزار مناسبی برای تشخیص کد مورس در ویدئو پیدا کنم (یک کد سی در گیتهاب بود که کامپایل نمیشد، با CyberChef هم نمیتونستم فریمهای ویدئو را دریافت کنم). برای همین دست به کد شدم :))
ایده کلی ساده است: ویدئو را فریم به فریم جدا کن و اگر در فریمی لوگو کوئرا بود 1 چاپ کن و اگر نه 0. بعد هم صفر و یکها را به کد کورس تبدیل کن. برای پردازش ویدئو از کتابخونههای OpenCV و Numpy در پایتون استفاده کردم. کد زیر، ویدئو را فریم به فریم جدا میکنه و اگر میانگین پیکسلها بزرگتر از 50 بود یک چاپ میکنه و در غیر این صورت صفر. عدد 50 را بعد از چاپ مقدار np.average(frame) در کنسول انتخاب کردم چون دیدم فریمهایی که لوگو کوئرا را دارند، میانگین روشنایی پیکسلهاشون میشه حدود 57 و بقیه فریمها صفر (سیاه =(0،0،0)).
نتیجه در فایل result.txt ذخیره میشه. بخشی از این فایل به صورت زیره:
1111111111111111111100000000001111111111111111111100000000000000000000000000000000000000001111111111111111111100000000001111111111111111111100000000001111111111111111111100000000000000000000000000000000000000001111111111000000000011111111111111111111000000000011111111110000000000000000000000000000000000000000111111111100000000001111111111000000000011111111110000000000000000000000000000000000000000111111111100000000000000000000000000000000000000001111111111111111111100000000001111111111000000000011111111111111111111000000000011111111110000000000000000000000000000000000000000111111111111111111110000000000111111111111111111110000000000111111111111111111110000000000000000000000000000000000000000
حالا فقط کافیه در vscode با یک ctrl+h ساده اول دنبالههای بلند صفر را به \n تبدیل کنیم، بعد دنبالههای کوتاه صفر را به هیچ (نقش فاصله برای تشخیص خط و نقطه است که در ادامه مشخص میشن)، و بعد دنبالههای بلند یک را به خط و دنبالههای کوتاه 1 را به نقطه. دقت کنید که مهمه اول دنبالهها بلندتر به کاراکتر معادلشون تبدیل بشن و بعد دنبالهها کوتاهتر. در این سوال تبدیلها میشن به این صورت:
دنباله 11111111111111111111 به خط
دنباله 0000000000000000000000000000000000000000 به کاراکتر خط جدید (\n)
دنباله 0000000000 به هیچی
دنباله 1111111111 به نقطه
بخشی از نتیجه میشه مثل زیر:
--
---
.-.
...
.
-.-.
حالا با CybreChef دنباله را ترجمه میکنیم و به جواب میرسیم:
جواب: queraCTF{morse_video_is_very_great}
همونطور که گفتم، هنوز چند ساعت از شروع مسابقه نگذشته بود که ویدئو عوض شد. ویدئو اول با سرعت خیلی بالاتری، پیام بلندتری را مخابره میکرد. برای حل چالش اول از کد قسمت بالا برای چاپ صفر و یک استفاده کردم. مشکل اینجا بود که بر خلاف ویدئو دوم، در ویدئو اول طول دنبالههای صفر و یک ثابت نبود. مثلا تول کد هفتتا یک پشت س هم میدیدی، ششتا و پنجتا و .. و حتی تک یک هم بود. به طور مشابه صفرها هم همین وضعیت را داشتند. اینجا بود که تصمیم گرفتم این دنباله صفر و یک را به یک فایل صوتی تبدیل کنم و به این سایت بدم تا متن را برگردونه (بماند که متن خروجی هم کاملا بی معنی بود). حدس میزنم هدف کوئرا این بوده که در اینجا طول دنباله صحیح را حدس بزنیم (با کد و تست حالتها) یا با تغییر وضعیت سیگنال کار کنیم (مثل رمزکذاری منچستر در بحث شبکه). در هر صورت قبل از اینکه بیشتر درگیر بشیم کلا ویدئو عوض شد و کد تولید فایل صوتی رو دستم موند. این کدی که میذارم را برای تولید فایل صوتی استفاده کردم (با حذف بخشی از دنباله تولید شده توسط کد قبل در متغیر data). چه دیدی، شاید یه روزی به کارتون اومد.