Гайд по триатлону: CTF, часть 1/2
В этом посте я расскажу про одну из дисциплин триатлона — соревнования по информационной безопасности CTF. CTF расшифровывается как Capture The Flag. Изначально соревнования такого рода представляли собой противоборство двух команд, каждая из которых пыталась взломать сервера другой и не допустить взлома своих, поддерживая, тем не менее, их доступность. Этот формат многим (включая меня) не нравится. Я предпочитаю формат Jeopardy, похожий на одноименную игру («Своя игра»): задачи различной стоимости разделены на несколько категорий, а положение команды вычисляется из суммы стоимостей решённых задач.
Традиционными категориями являются Cryptography, Web hack, Reversing, Forensics. В последнее время всё чаще на соревнованиях встречаются новые категории: Algorithms, похожая на алгоритмическое спортивное программирование, и Reconnaissance, про разведку по открытым источникам в интернете.
В процессе решения задачи, будь то взлом криптоалгоритма, реверсинг какого-нибудь запутанного бинарника или поиск нужного аккаунта в сети, участники находят флаги — короткие опознаваемые строки. Они отправляются автоматическому чекеру в качестве решения. Например, на описываемом контесте флаги имели вид abctf{s0m3th1ng_s1m1l4r}.
Чтобы проиллюстрировать, какого рода бывают задачи, я написал разбор (обычно называемый write-up) соревнования ABCTF, прошедшего в июле 2016. Оно ориентировано на школьников, не так давно интересующихся информационной безопасностью, поэтому значительная часть задач имеет образовательную ценность для новичков. К сожалению, сейчас сайт соревнования и многие из ссылок не работают.
Если вы заинтересовались темой, почитайте учебник от UFO CTF.
Список предстоящих соревнований
Эта категория требует знакомства с известными криптопримитивами и криптосхемами, умения искать в них уязвимости, понимания математики, которая лежит в основе криптографических алгоритмов. Из инструментария чаще всего оказываются полезными Python, Maple и ручка с бумагой.
Caesar Salad - 10 (Cryptography)
Most definitely the best salad around. Can you decrypt this for us?
xyzqc{t3_qelrdeq_t3_k33a3a_lk3_lc_qe3p3}
Любой интересующийся криптографией человек, несомненно, читал популярные книжки по ней, рассказывающие, в том числе, про ее историю. Желание скрыть свое сообщение от чужих глаз имеет историю не в одну тысячу лет. И шифр Цезаря — один из самых старых. В нем к порядковому номеру символа прибавляется какое-то фиксированное число, и символ заменяется на символ с получившимся номером. Например, если сдвиг равен 1, то A становится B, B становится C, а Z переходит в A. Видно, что шифротекст похож на ключ, у него 5 символов перед {}, внутри которых строка, содержащая знаки подчеркивания. Кроме того буквы xyz идут подряд, как и abc, что позволяет заключить, что сдвиг равен -4. Пишем простую программу на Python:
которая выдает ответ abctf{w3_thought_w3_n33d3d_on3_of_th3s3} .
Yummi - 60 (Cryptography)
Well this image means something and we need you to figure it out!
Hint: Water -> Fish, Mud -> ???
По ссылке скачивается черно-белая картинка baconian.bmp 9×10.

Название должно намекнуть знатоку криптографии про еще один древний шифр — шифр Бэкона. Он стеганографически скрывал (верхним или нижним регистром, курсивом или прямым текстом) в большом тексте биты сообщения, сгруппированные по 5. Каждая группа соответствовала порядковому номеру символа в двоичной системе счисления. Здесь в виде битов очевидно выступают черные и белые пиксели, а группировку по 5 явно удобнее производить, двигаясь вертикально, по колонкам. Действительно, A, видимо, соответствует всем черным пикселям в верхней половине первой колонки (00000), B в нижней половине первой колонки уже содержит один белый пиксель в самом низу (00001), C сверху во второй колонке 00010 и так далее.
Чтобы не делать вручную то, что можно не делать вручную, напишем дешифровщик на Python:
И флаг ABCTFLOVESBACONIAN.
Old RSA - 70 (Cryptography)
I'm sure you can retrieve the flag from this file.
Hint: Some good math skills may help.
Эта и последующие задачи на RSA, что ожидаемо для образовательного контеста, решаются с помощью статьи на Википедии, в которой описано и что такое RSA, и какие на него бывают атаки.
По ссылке даны 3 числа, c, n и e. Число c это шифротекст,
, где m — открытый текст. Чтобы в RSA извлечь из шифротекста открытый текст, нужно знать d,
, где, поскольку n это произведение двух больших простых чисел p и q,
. Тогда тот, кто знает d, может вычислить
. По теореме Эйлера о тотиент-функции
, так что мы просто вычислили открытый текст m, потому что n берется всегда больше m.
Число n сравнительно небольшое, 256 бит, поэтому можно попробовать факторизовать его напрямую, используя Maple:
И действительно, через 3 с небольшим минуты Maple даст ответ (238324208831434331628131715304428889871) (296805874594538235115008173244022912163) . Найдем d:
и открытый текст m:
Флаг ABCTF{th1s_was_h4rd_in_1980}.
AES Mess - 75 (Cryptography)
We encrypted a flag with AES-ECB encryption using a secret key, and got the hash: e220eb994c8fc16388dbd60a969d4953f042fc0b ce25dbef573cf522636a1ba3fafa1a7c21ff824a 5824c5dc4a376e75
However, we lost our plaintext flag and also lost our key and we can't seem to decrypt the hash back :(.
Luckily we encrypted a bunch of other flags with the same key. Can you recover the lost flag using this?
Hint: There has to be some way to work backwards, right?
Алгоритм AES-ECB просто шифрует текст независимыми блоками по 16 байт. Поэтому если вдруг мы обнаружим в гисте с 2000 примерами шифрования строк вида abctf{...} все нужные шифроблоки e220eb994c8fc16388dbd60a969d4953, f042fc0bce25dbef573cf522636a1ba3 и fafa1a7c21ff824a5824c5dc4a376e75, для которых мы знаем прообраз, то выясним и флаг. Конечно, так и выходит.
Скрипт выводит флаг abctf{looks_like_you_can_break_aes}.
A Small Broadcast - 125 (Cryptography)
I RSA encrypted the same message 3 different times with the same exponent. Can you decrypt this?
Эта задача очень долго оставалась битой, пока ее, наконец, не починили. Смешно, что решил я ее намного раньше, чем, наконец, получил возможность посчитать ответ, используя правильные числа.
В Википедии описана атака Хастада, которая как раз возможна, если мы имеем маленькую экспоненту e и не меньше, чем e результатов шифрования одного и того же сообщения. Похоже, здесь именно этот случай и e=3.
Действительно, если у нас есть 3 остатка от деления одного числа на 3 взаимно простых делителя

и это число
, то по китайской теореме об остатках мы можем его однозначно восстановить по формуле

Реализуем в Maple:
Флаг abctf{ch!n3s3_rema1nd3r_the0rem_is_to0_o p_4_m3}.
Encryption Service - 140 (Cryptography)
See if you can break this!!
You can connect with nc 107.170.122.6 7765 and the source can be found here.
Программа принимает по сети hex-строку, приписывает слева "ENCRYPT:", справа флаг, дополняет до размера, кратного 16 (добавляя 16 символов, если уже). Потом шифрует это AES с помощью неизвестного ключа.
AES независимо шифрует блоки по 16 байт. Мы можем (примерно 100 запросами) получить шифротекст для строк вида
и так далее, забив первый блок до конца нулями. Для этого нужно передать серверу зеленую строку:
Что произойдет, если теперь мы отрежем у нее на конце 1 символ и снова ее передадим?
Один байт флага попадет во второй блок и шифроблок совпадет с каким-то из ранее посчитанных! Таким образом мы узнаем первый байт флага. Вновь посчитаем AES от группы строк
и отрежем уже 2 байта с конца передаваемой строки.
Уже два байта флага попадут во второй шифроблок и совпадут с одним из примерно 100 заново посчитанных, ведь первый мы уже знаем. Так, символ за символом, можно выяснить все байты флага. Но для начала нужно еще определить его длину, посмотрев, как меняется длина шифротекста, если передавать все более и более длинные строки. Окажется 20, так что придется добавить еще нулей и алгоритм использовать уже на третьем блоке.
Напишем код для брутфорса. Сервер выдавал примерно 1 rps, так что понадобилось чуть больше получаса.
Буквы появлялись одна за другой, как в голливудском боевике, пока не показался целиком флаг ABCTF{p4dding_4_fun}.
Sexy RSA - 160 (Cryptography)
Check this out!
В этот раз n длинный и просто так его не факторизовать. Если только p и q не слишком близки. Вычисляем квадратный корень в Maple
1099610570827941329700237866432657027914 3597980628961534068655881437258133684482 7811897743892137093567873243483114130489 9886705498243884638860011461262640420256 5942717018126078752549991465299554456515 30660964259381322198377196122396.0000000 00000000000
и, получив ответ, обнаруживаем, что они именно такие. Действительно,
9
а значит,
и флаг ABCTF{i_h4ve_an_RSA_fetish_;)}.
Custom Authentication - 160 (Cryptography)
I just learned about encryption and tried to write my own authentication system. Can you get in? Here is the source! And here is the site.
При запросе на /login скрипт создает объект {username: req.username, password: req.password, admin: "false"} (на самом деле admin: результат проверки, но мы вряд ли угадаем пароль). Объект кодируется в JSON и шифруется AES-CBC.
При запросе / желанный флаг отображается, если admin:"true" в JSON, полученном строкой
Заметим странный, подозрительный код, фильтрующий символы, но забывающий про обратный слэш, который используется во вполне валидном JSON, например, для эскейпинга кавычек. Это значит, что мы можем просто использовать в качестве пароля строку
После кодирования объект превратится в
А после удаления бэкслешей
К сожалению, для взлома этого недостаточно, декодированный из JSON объект будет использовать последнее указанное значение ключа admin, то есть "false".
Но можно попробовать испортить имя ключа, зная, что после расшифровки его шифроблока полученная строка ксорится с предыдущим шифроблоком. Конечно, даже изменение одного бита в предыдущем шифроблоке приведет к тому, что открытый текст в нем превратится в тыкву, но можно сделать так, чтобы он приходился на строку, и тыква была отфильтрована все той же заменой. Лишь бы там случайно не появились кавычки :-)
Мы инвертируем младший бит в 4-м байте 5-го шифроблока. При этом вместо красных байт дешифруется упячка, а вместо зеленого — @.
Зашифруем строку
Сервер прислал
Превратим второй ключ admin в @dmin, инвертировав младший бит в 4-м байте 5-го шифроблока, и отправим это на сервер.
Сервер сообщит нам, что мы админы и флаг abctf{i_used_encryption_so_it_must_be_se cure}.
Для форенсики полезно уметь опознавать распространенные форматы файлов, понимать, какого рода данные могут в них неявно храниться. Из инструментов пригождаются hex-редактор, TweakPNG, многочисленные распаковщики, Python.
Just open it - 15 (Forensics)
I'm almost positive we put a flag in this file. Can you find it for me?
Hint: So many editors out there!
Предлагаемый файл это JPEG-картинка, на которой нет ключа, зато есть артефакт, будто она побилась: с определенного места все квадратики 8×8 сдвинуты на один влево. Многие задачи основаны на том, что в файле одного формата хранятся данные в другом. Такие задачи-матрешки часто требуют широкой эрудиции, но в данном случае все просто. Флаг ABCTF{forensics_1_tooo_easy?} просто написан plain-текстом посреди бинарных данных JPEG, что и привело к побитому блоку.
GZ - 30 (Forensics)
We shot a flag into this file but some things got messed up on the way...
По ссылке качается файл flag без расширения, но опытный глаз без труда различает в заголовке 46-байтного файла сигнатуру 1F 8B. Заголовок задачи не врет, это действительно архив в формате GZ, который открывает, например, 7-zip. А внутри файл с ключом ABCTF{broken_zipper}.
Best Ganondorf - 50 (Forensics)
You know the deal. Find a flag in this this file?
Скачивается файл с расширением .jpg, который, однако, не открывается просмотрщиком картинок. Смотрим на него в hex-редакторе или просто в Lister, если есть Total. Действительно, в его начале отсутствует привычный JFIF-заголовок. Зато в остальном файл вполне похож на JPEG — низкая энтропия первые байт 300, а потом высокая до конца файла. Позаимствуем 11 байт из нормального JPEG-файла и добавим их в этот в hex-редакторе. FF D8 FF E0 00 10 4A 46 49 46 00, и картинка открывается. На ней счастливый азиат, много баксов и наискосок флаг abctf{tfw_kage_r3kt_nyway}.
MoonWalk - 60 (Forensics)
There is something a little off about this picture. If you could help us we could give you some points! Just find us a flag!
На двухметровой PNG-картинке изображен Инки из Pac-Man в темных очках. Слишком большой размер файла вызвал подозрения о том, что внутри PNG могут быть еще какие-то данные, и я воспользовался программой TweakPNG для промотра секций файла. Та немедленно обнаружила «мусор в конце файла» в секции puNK размером 1588789 байт, то есть на 2/3 файла. Находим эту строку и видим, что за ней идет знакомый JFIF-заголовок. Просто пересохраняем содержимое секции:
и открываем. Там фотография листка бумаги, на котором карандашом от руки написан флаг ABCTF{PNG_S0_C00l}. Здесь авторы от души поиздевались над участниками, потому что весьма непросто опознать, что в их неровном почерке нули, а не буквы, и все, кроме последней, буквы заглавные.
PasswordPDF - 80 (Forensics)
Oh no. We locked this PDF and forgot the password. Can you help us?
Hint: Is there anyway to guess the password?
Брутфорсим пароль на PDF силами Advanced PDF Password Recovery, Passware Password Recovery Kit Forensic по словарю из стандартной поставки или чем-то похожим. Пароль оказывается elephant.
Но открыв PDF, мы видим, что там написано Password:, а флаг закрыт большой красной плашкой "Censored!!! You hackers will never get me now". В STDU Viewer можно просто Файл > Экспортировать > как текст и узнать, что флаг ABCTF{Damn_h4x0rz_always_bypassing_my_PD Fs}.
Zippy - 120 (Forensics)
If your could fix this mess I am sure there would be a flag waiting for you.
По ссылке скачивается архив с 54 ZIP-файлами внутри с именами вида chunk53.zip и размером 130 байт. Внутри каждого архива лежит файл data.txt размером 4 байта, каждый запаролен. Алгоритм шифрования в ZIP слабый и, например, уязвим к plain-text атаке, если известно хотя бы 13 символов, но в данном случае она неприменима и простой брутфорс тоже не дает результата.
Заметим, однако, что к каждому файлу внутри ZIP-архива прилагается CRC32 для контроля целостности. И если внутри просто 4 байта текста, то вполне можно перебрать все возможные тексты и искать среди них с нужным CRC32. Дляразнообразия большей эффективности я взял C++, скодогенерировав для него функцию проверки CRC32 на совпадение с одним из искомых.
И весьма быстро получил результат! Впрочем, это оказался не пароль, а закодированный в BASE-64... еще один запароленный ZIP-архив. Внутри лежал flag.txt размером 35 байт. Этот пароль уже вскрылся брутфорсом, потому что состоял всего из 3 символов: z1P. И флаг flag{i_z1pp3d_a_zip_w1th_sum_zips}.
Эта категория включала тоже задачи на форенсику, но в отличие от предыдущей, где можно было проанализировать файл целиком, здесь предлагался образ, содержащий уйму файлов, среди которых нужно было найти несколько интересных. Инструменты: VirtualBox, файловый менеджер, hex-редактор.
Virtual Box 1 - 10 (Virtual Series)
Do you know how to use a VM? Download the Virtual Machine here.
В этой и последующих задачах этой категории используется один и тот же 645-метровый образ виртуальной машины в формате .ova. Его понимает VirtualBox, да и сам по себе он просто архив с файлом параметров машины и образом диска в формате vmdk. А вот в VMWare он не завелся. Практичным виндоподходом к этой задаче было просто сконвертировать vmdk-файл в vhd-образ командой вида VBoxManage.exe clonehd --format vhd M:disk1.vmdk M:disk1.vhd и примонтировать его через Computer Management > Disk Management > Attach VHD. После этого в системе появлялся диск, к которому можно было применять всю мощь инструментария форенсики, а в несжатом образе vhd найти половину флагов простым поиском подстроки "abctf{".

Первый флаг лежал на рабочем столе в файле "flag 1.doc", намекая, что его было бы неплохо открыть. В нем просто была написан флаг ABCTF{FREE_P0INTS}.
Стоит отметить, что автор задачи предпринял меры, чтобы все вставленные им флаги нельзя было найти, просто отсортировав файлы на ФС по дате. Для этого он использовал FileDate Changer от NirSoft, от использования которой, тем не менее, осталось еще больше следов на ФС :-)
Virtual Box 2 - 15 (Virtual Series)
Darn, I found this flag so I put it in flag 1.doc but I can't seem to be able to see it anymore.
Как и в задаче Just open it - 15 бинарный формат DOC содержит plain-текст с флагом, поэтому достаточно открыть его в plain-текстовом редакторе. ABCTF{H1DDEN_AWAY}.

Virtual Box 3 - 35 (Virtual Series)
This mysterious file was left here, but I have no idea how to open it. Do you? I left it in a folder named 2016 just for you.
В Моих документах лежит папка 2016, а в ней XLSX файл. Если ранние версии Office использовали для форматов DOC и XLS COM Structured Storage, то сейчас, вслед за OpenOffice, данные документа пишутся в XML, которые потом пакуются в ZIP. Флаг находится простым поиском по строке "abctf" внутри архива, в файле sharedStrings: ABCTF{FR0M_THE_FUTURE}.

Virtual Box 4 - 60 (Virtual Series)
What's this?
В Корзине лежит whatsthis.txt, а в нем ABCTF{N0T_S0_D1ff1CULT}, но он неправильный, позднее авторы признались, что просто забыли удалить его, когда создавали задачу. Делаем поиск по ABCTF в имени файла по всему диску и находим c:\program files\Outlook Express\ABCTF{Y0U_F0UND_ME}\whats this.txt. ABCTF{Y0U_F0UND_ME} и есть флаг к этой задаче.

Virtual Box 5 - 75 (Virtual Series)
I accidentaly closed out this odd message I found. Can you get it back?
В форенсике традиционно любопытство к веб-активности пользователя. У IE6 в кэше или истории, в которой не удалили только одну запись, можно найти картинку http://imgur.com/FQJ4JtO:

Сперва кажется, что это шифр простой замены, где первые 5 символов, очевидно, abctf, сильно отличающиеся треугольники это {}, а толстые стрелки вправо соответствуют _. Из abctf{1t2_с34_435167_bac5} заключаем, что 5 наверняка k, 1t2 это its, а окончание предпоследнего слова king, но дальше abctf{its_с34_43king_back} фантазия пробуксовывала, родив разве что неверный остроумный вариант its_сat_taking_back.
Но несколько позже обнаружилось, что это не шифр простой замены, а просто текст, набранный идеографическим шрифтом Wingdings 3. Дублирующиеся стрелки вниз соответствовали двум символам, а не одному, а флаг был ABCTF{ITS_C00L_L00KING_BACK}.
Virtual Box 6 - 75 (Virtual Series)
I really love this pattern, can I set it as my wallpaper? Here it is.
Смотрим список стандартных обоев рабочего стола и замечаем, что к Houndstooth, узор которого используется на платье с картинки по ссылке, справа пририсован текст флага. ABCTF{I_L0VE_PATTERNS.

Virtual Box 7 - 100 (Virtual Series)
Hmm, I wish I could figure out the team that created Windows 98 without the map hassle.
Олдфаги помнят, что если в Windows 98 открыть карту выбора временной зоны (есть, например, в Control Panel > Regional Settings), зажать Ctrl, нажать левую кнопку мыши в районе Каира, отпустить в районе Мемфиса, вновь нажать и отпустить в районе Редмонда вместе с Ctrl, можно увидеть пасхалку, со списком команды разработки Windows 98. Можете еще поискать Польшу :-)

Ту же самую пасхалку можно вызвать и другим способом, если создать ярлык к файлу C:\Application Data\Microsoft\WELCOME\Weldata.exe, передав параметром командной строки You_are_a_real_rascal и указав, что программа должна стартовать с минимизированным окном.
Мы решили, что в процессе запуска пасхалки в выданной виртуалке организаторы что-то нахимичили. На долгие часы я отправился в дизассемблер и расковырял оба пути запуска до последних винтиков.
Файл intl.cpl, отвечающий за региональные настройки в Панели управления, действительно по событиям левой кнопки мыши проверяет, используя WinAPI PtInRect и конечный автомат, попало ли событие в нужную область и выполнены ли они в нужном порядке. Если да, он достает строку "Weldata.exe You_are_a_real_rascal" из ресурсов, зашифрованную увеличением кодов символов на 1, и запускает ее через ShellExecute, добавив путь к папке.
Программа Weldata.exe создает окно, на нем окно браузера, достает из своего тела длинную строку, зашифрованную XOR с аргументом командной строки, пишет ее в ~x520.htm, который запускает в браузере, тут же переименовывает в ~x405.htm и удаляет. Если самому расксорить эту строку со строкой You_are_a_real_rascal, получается HTML-файл с кучей JavaScript, списком авторов, списком картинок, вставлявшихся из res://membg.dll/, фоновой музыкой, и небольшим VBScript, обрабатывавшим нажатия клавиш.
Решительно нигде, ни в intl.cpl, ни в Weldata.exe, ни в Welcome.exe, который она запускает по дефолту, ни в Welcome.dat не было ничего подозрительного, что бы могли изменить организаторы. Ничего не дала даже попытка проксорить с разными сдвигами строки You_are_a_real_rascal весь гигабайтный образ диска. Измучившись сравнением изрядно пропатченной Windows 98 с оригинальным дистрибутивом и парсингом своп-файла, я подумал, а не может ли ответ быть просто ABCTF{You_are_a_real_rascal}? Да, это и был последний флаг категории!
Разбор категорий Reconaissance, Programming, Web Exploitation, Reverse Engineering, Binary Exploitation в следующем посте
Традиционными категориями являются Cryptography, Web hack, Reversing, Forensics. В последнее время всё чаще на соревнованиях встречаются новые категории: Algorithms, похожая на алгоритмическое спортивное программирование, и Reconnaissance, про разведку по открытым источникам в интернете.
В процессе решения задачи, будь то взлом криптоалгоритма, реверсинг какого-нибудь запутанного бинарника или поиск нужного аккаунта в сети, участники находят флаги — короткие опознаваемые строки. Они отправляются автоматическому чекеру в качестве решения. Например, на описываемом контесте флаги имели вид abctf{s0m3th1ng_s1m1l4r}.
Чтобы проиллюстрировать, какого рода бывают задачи, я написал разбор (обычно называемый write-up) соревнования ABCTF, прошедшего в июле 2016. Оно ориентировано на школьников, не так давно интересующихся информационной безопасностью, поэтому значительная часть задач имеет образовательную ценность для новичков. К сожалению, сейчас сайт соревнования и многие из ссылок не работают.
Если вы заинтересовались темой, почитайте учебник от UFO CTF.
Список предстоящих соревнований
Cryptography
Эта категория требует знакомства с известными криптопримитивами и криптосхемами, умения искать в них уязвимости, понимания математики, которая лежит в основе криптографических алгоритмов. Из инструментария чаще всего оказываются полезными Python, Maple и ручка с бумагой.
Caesar Salad - 10 (Cryptography)
Most definitely the best salad around. Can you decrypt this for us?
xyzqc{t3_qelrdeq_t3_k33a3a_lk3_lc_qe3p3}
Любой интересующийся криптографией человек, несомненно, читал популярные книжки по ней, рассказывающие, в том числе, про ее историю. Желание скрыть свое сообщение от чужих глаз имеет историю не в одну тысячу лет. И шифр Цезаря — один из самых старых. В нем к порядковому номеру символа прибавляется какое-то фиксированное число, и символ заменяется на символ с получившимся номером. Например, если сдвиг равен 1, то A становится B, B становится C, а Z переходит в A. Видно, что шифротекст похож на ключ, у него 5 символов перед {}, внутри которых строка, содержащая знаки подчеркивания. Кроме того буквы xyz идут подряд, как и abc, что позволяет заключить, что сдвиг равен -4. Пишем простую программу на Python:
s = 'xyzqc{t3_qelrdeq_t3_k33a3a_lk3_lc_qe3p3} '
result = ''
for i in range(len(s)):
code = ord(s[i]) + 3
if code > ord('z'):
code -= 26
result += chr(code) if s[i] not in '{}_3' else s[i]
print resultкоторая выдает ответ abctf{w3_thought_w3_n33d3d_on3_of_th3s3}
Yummi - 60 (Cryptography)
Well this image means something and we need you to figure it out!
Hint: Water -> Fish, Mud -> ???
По ссылке скачивается черно-белая картинка baconian.bmp 9×10.

Название должно намекнуть знатоку криптографии про еще один древний шифр — шифр Бэкона. Он стеганографически скрывал (верхним или нижним регистром, курсивом или прямым текстом) в большом тексте биты сообщения, сгруппированные по 5. Каждая группа соответствовала порядковому номеру символа в двоичной системе счисления. Здесь в виде битов очевидно выступают черные и белые пиксели, а группировку по 5 явно удобнее производить, двигаясь вертикально, по колонкам. Действительно, A, видимо, соответствует всем черным пикселям в верхней половине первой колонки (00000), B в нижней половине первой колонки уже содержит один белый пиксель в самом низу (00001), C сверху во второй колонке 00010 и так далее.
Чтобы не делать вручную то, что можно не делать вручную, напишем дешифровщик на Python:
im = imread('baconian.bmp')
bits = ''.join(['0' if all(im[i,j,:] == [0,0,0]) else '1' for j in range(9) for i in range(10)])
print ''.join([chr(ord('A') + int(bits[off : off + 5], 2)) for off in range(0, len(bits), 5)])И флаг ABCTFLOVESBACONIAN.
Old RSA - 70 (Cryptography)
I'm sure you can retrieve the flag from this file.
Hint: Some good math skills may help.
Эта и последующие задачи на RSA, что ожидаемо для образовательного контеста, решаются с помощью статьи на Википедии, в которой описано и что такое RSA, и какие на него бывают атаки.
По ссылке даны 3 числа, c, n и e. Число c это шифротекст,
Число n сравнительно небольшое, 256 бит, поэтому можно попробовать факторизовать его напрямую, используя Maple:
n := 7073602523926523997631508869017459402164 6654881626421461009089480870633400973;
ifactor(n);И действительно, через 3 с небольшим минуты Maple даст ответ (238324208831434331628131715304428889871)
e := 3:
p := 238324208831434331628131715304428889871:
q := 296805874594538235115008173244022912163:
phin := (p - 1) * (q - 1):
d := 1 / e mod phin;и открытый текст m:
c := 2984694751921457516249741372506041254611 9233216851184246267357770082463030225:
m := c &^ d mod n:
convert(ListTools[Reverse](convert(m, base, 256)), bytes);Флаг ABCTF{th1s_was_h4rd_in_1980}.
AES Mess - 75 (Cryptography)
We encrypted a flag with AES-ECB encryption using a secret key, and got the hash: e220eb994c8fc16388dbd60a969d4953f042fc0b
However, we lost our plaintext flag and also lost our key and we can't seem to decrypt the hash back :(.
Luckily we encrypted a bunch of other flags with the same key. Can you recover the lost flag using this?
Hint: There has to be some way to work backwards, right?
Алгоритм AES-ECB просто шифрует текст независимыми блоками по 16 байт. Поэтому если вдруг мы обнаружим в гисте с 2000 примерами шифрования строк вида abctf{...} все нужные шифроблоки e220eb994c8fc16388dbd60a969d4953, f042fc0bce25dbef573cf522636a1ba3 и fafa1a7c21ff824a5824c5dc4a376e75, для которых мы знаем прообраз, то выясним и флаг. Конечно, так и выходит.
dic = {}
for line in file_get('aes.txt').splitlines():
p, h = line.split(':')
for i in range((len(p) + 15) / 16):
dic[h[32 * i : 32 * i + 32]] = p[i * 16 : i * 16 + 16]
hh = 'e220eb994c8fc16388dbd60a969d4953f042fc0 bce25dbef573cf522636a1ba3fafa1a7c21ff824 a5824c5dc4a376e75'
for i in range(3):
part = hh[i * 32 : i * 32 + 32]
if part in dic:
print dic[part]Скрипт выводит флаг abctf{looks_like_you_can_break_aes}.
A Small Broadcast - 125 (Cryptography)
I RSA encrypted the same message 3 different times with the same exponent. Can you decrypt this?
Эта задача очень долго оставалась битой, пока ее, наконец, не починили. Смешно, что решил я ее намного раньше, чем, наконец, получил возможность посчитать ответ, используя правильные числа.
В Википедии описана атака Хастада, которая как раз возможна, если мы имеем маленькую экспоненту e и не меньше, чем e результатов шифрования одного и того же сообщения. Похоже, здесь именно этот случай и e=3.
Действительно, если у нас есть 3 остатка от деления одного числа на 3 взаимно простых делителя
и это число
Реализуем в Maple:
N1 := 7960803771652791039206067070784295422411 4341083822168077002144855358998405023007 3457913559708384372736534927268573983130 4719565493301180374049816753875480765925 5275632647165202835846338059572102420992 6920733033413925124909884135525014193574 0050323219059774112072627625075386613067 9586474440949586692852365179:
C1 := 3421706580342534935644765284299319107970 5593197469002356250751196039765990549766 8221802657231739647260870168909800511897 8723383792565090208136222221836574863359 1895514369317316450142279676583079298758 3975070239423773166463005479782347295786 7831002862640850208595772540823216828495 5403531891866121828640919987:
N2 := 5800222204814123285546575879979599126084 4167004589249261667816662245991955274977 2870821427949115729892618561560405366685 5336583814527164281281160968736270084366 1481653274617983708937827484947856793885 8215862855708442745453858524017776789562 1780776860845732232993529004236222150236 7207511491516411517438589637:
C2 := 4803854257236814331592894985721334134914 4690234757944150458420344577988496364306 2273931611129392263470748387277937616959 7872207448690252512171279614236696217229 1716190060386128524977245133260307337691 8207899786103138937996758373912440621708 7981027033608074179092734033648656831999 3335039457684586195656124176:
N3 := 9513678674552047821726952860314828247371 5660891325372806774750455600642337159386 9524551443918677504920771918236307110974 2347353023517212479095131431527131054276 5846789908387211336846556241994561268538 5283197433742907891123737748935476766016 9088221170688955345596272021848639551920 0617695951617114702861810811:
C3 := 5513900116853490579103309304928148584951 6290567638780139733282880064346293967470 8845238428136793612324233302908360632483 5213102599568434114333741723711966334756 1882637003640064860966432102780676449991 7731404070558633691796921361085349526244 1166969179928662369998163643933142707918 3234388844722074263884842748:
M3 := chrem([C1, C2, C3], [N1, N2, N3]):
M := iroot(M3, 3):
convert(ListTools[Reverse](convert(M, base, 256)), bytes);Флаг abctf{ch!n3s3_rema1nd3r_the0rem_is_to0_o
Encryption Service - 140 (Cryptography)
See if you can break this!!
You can connect with nc 107.170.122.6 7765 and the source can be found here.
Программа принимает по сети hex-строку, приписывает слева "ENCRYPT:", справа флаг, дополняет до размера, кратного 16 (добавляя 16 символов, если уже). Потом шифрует это AES с помощью неизвестного ключа.
AES независимо шифрует блоки по 16 байт. Мы можем (примерно 100 запросами) получить шифротекст для строк вида
000000000000000A
000000000000000B
000000000000000C
...и так далее, забив первый блок до конца нулями. Для этого нужно передать серверу зеленую строку:
ENCRYPT:00000000 000000000000000A ABCTF{unknown}xxЧто произойдет, если теперь мы отрежем у нее на конце 1 символ и снова ее передадим?
ENCRYPT:00000000 000000000000000A BCTF{unknown}xxxОдин байт флага попадет во второй блок и шифроблок совпадет с каким-то из ранее посчитанных! Таким образом мы узнаем первый байт флага. Вновь посчитаем AES от группы строк
ENCRYPT:00000000 00000000000000AA ABCTF{unknown}xx
ENCRYPT:00000000 00000000000000AB ABCTF{unknown}xx
ENCRYPT:00000000 00000000000000AC ABCTF{unknown}xx
...и отрежем уже 2 байта с конца передаваемой строки.
ENCRYPT:00000000 00000000000000AB CTF{unknown}xxxxУже два байта флага попадут во второй шифроблок и совпадут с одним из примерно 100 заново посчитанных, ведь первый мы уже знаем. Так, символ за символом, можно выяснить все байты флага. Но для начала нужно еще определить его длину, посмотрев, как меняется длина шифротекста, если передавать все более и более длинные строки. Окажется 20, так что придется добавить еще нулей и алгоритм использовать уже на третьем блоке.
Напишем код для брутфорса. Сервер выдавал примерно 1 rps, так что понадобилось чуть больше получаса.
from Crypto.Cipher.AES import AESCipher
import socket
def cr(hexs):
sock = socket.socket()
sock.connect(('107.170.122.6', 7765))
data1 = sock.recv(1024)
sock.send(hexs + '\n')
result = ''
while True:
data = sock.recv(1024)
if data:
result += data
else:
break
sock.close()
return result[len('Here you go:'):-1]
known_key = ''
for get_char in range(20):
s = '00' * (39 - len(known_key))
their_char = cr(s)
for next_ch in range(ord(' '), ord('~') + 1):
print '\r', known_key + chr(next_ch),
sc = s + known_key.encode('hex') + '%02x' % next_ch
own_char = cr(sc)
if own_char[64 : 96] == their_char[64 : 96]:
known_key += chr(next_ch)
breakБуквы появлялись одна за другой, как в голливудском боевике, пока не показался целиком флаг ABCTF{p4dding_4_fun}.
Sexy RSA - 160 (Cryptography)
Check this out!
В этот раз n длинный и просто так его не факторизовать. Если только p и q не слишком близки. Вычисляем квадратный корень в Maple
n := 1209143407476550975641959824312993703149 9203444374221930422931315727452986626962 8427992862241244125565239149324141417053 7319784298367821654726781089600780498369 4021674433638626218869439704688196567319 5946805852878789556993653690438797981518 3897568006750131879851263753496120098205 9664420104456015343054837837592265101208 6063377081454016641949581766631247448406 1885435295870436055727722073738662516644 1867165328913287424521983648258095086022 08516407566578212780807:
evalf(sqrt(n), 250);1099610570827941329700237866432657027914
и, получив ответ, обнаруживаем, что они именно такие. Действительно,
isqrt(n) ** 2 - n;9
а значит,
n = (isqrt(n) - 3) * (isqrt(n) + 3). Назовем первое p, второе q, и расшифруем сообщение.e := 65537:
c := 2934309173767083812438248152472280636051 0430354872075810878088072797433908603669 1092136736806182713047603694090694712685 0695243830981293031832982499810514987143 8339959543065810740076855906606523111414 5553134453396428041946588586604081230659 7804316388988713629576351059010918713851 6535421354432393141059994437778101371519 5511539451275610913318909140275602013631 0776703999377335179493445799631742354231 0145027276205280659564569409154672180224 6723616268373048438591:
p := isqrt(n) - 3:
q := isqrt(n) + 3:
phin := (p - 1) * (q - 1):
d := 1 / e mod phin:
m := c &^ d mod n:
convert(ListTools[Reverse](convert(m, base, 256)), bytes);и флаг ABCTF{i_h4ve_an_RSA_fetish_;)}.
Custom Authentication - 160 (Cryptography)
I just learned about encryption and tried to write my own authentication system. Can you get in? Here is the source! And here is the site.
При запросе на /login скрипт создает объект {username: req.username, password: req.password, admin: "false"} (на самом деле admin: результат проверки, но мы вряд ли угадаем пароль). Объект кодируется в JSON и шифруется AES-CBC.
При запросе / желанный флаг отображается, если admin:"true" в JSON, полученном строкой
JSON.parse(decrypt(req.cookies.auth).rep lace(/[^0-9a-zA-Z{}":, ]+/g, ''))Заметим странный, подозрительный код, фильтрующий символы, но забывающий про обратный слэш, который используется во вполне валидном JSON, например, для эскейпинга кавычек. Это значит, что мы можем просто использовать в качестве пароля строку
","admin":"true","x":"После кодирования объект превратится в
{"username":"1","password":"\",\"admin\":\"true\",\"x\":\"","admin":"false"}А после удаления бэкслешей
{"username":"1","password":"", "admin":"true", "x":"", "admin":"false"}К сожалению, для взлома этого недостаточно, декодированный из JSON объект будет использовать последнее указанное значение ключа admin, то есть "false".
Но можно попробовать испортить имя ключа, зная, что после расшифровки его шифроблока полученная строка ксорится с предыдущим шифроблоком. Конечно, даже изменение одного бита в предыдущем шифроблоке приведет к тому, что открытый текст в нем превратится в тыкву, но можно сделать так, чтобы он приходился на строку, и тыква была отфильтрована все той же заменой. Лишь бы там случайно не появились кавычки :-)
{"username":"1",
"password":"\",\
"admin\":\"true\
",\"x\":\"000000
1234567812345678
","admin":"false
"}Мы инвертируем младший бит в 4-м байте 5-го шифроблока. При этом вместо красных байт дешифруется упячка, а вместо зеленого — @.
Зашифруем строку
def get_encrypted_cookie(pwd):
resp = requests.post('http://107.170.122.6:3001/login',
data={'username':'1', 'password': crafted_pwd})
return resp.history[0].cookies.get('auth')
crafted_pwd = r'","admin":"true","x":"00000012345678123 45678'
enc = get_encrypted_cookie(crafted_pwd)
print encСервер прислал
c5113f3d155e021350229f966a02636f
c95d772f8c585d0ac07654819dbfc515
b2070ab67a48d854454ac4683bd55e11
28dd4684913dc7f5dce8e6fcb49578a2
ff1c543d35f114bd76bbab6727e73bff
299a9752c441f3aeaa61423825d49354
94ab819da6010bcf7e0906c23cc9cfe2Превратим второй ключ admin в @dmin, инвертировав младший бит в 4-м байте 5-го шифроблока, и отправим это на сервер.
enc2 = ''.join('''
c5113f3d155e021350229f966a02636f
c95d772f8c585d0ac07654819dbfc515
b2070ab67a48d854454ac4683bd55e11
28dd4684913dc7f5dce8e6fcb49578a2
ff1c543c35f114bd76bbab6727e73bff
299a9752c441f3aeaa61423825d49354
94ab819da6010bcf7e0906c23cc9cfe2'''.splitlines()[1:])
resp = requests.get('http://107.170.122.6:3001/', cookies={'auth': enc2})
print resp.contentСервер сообщит нам, что мы админы и флаг abctf{i_used_encryption_so_it_must_be_se
Forensics
Для форенсики полезно уметь опознавать распространенные форматы файлов, понимать, какого рода данные могут в них неявно храниться. Из инструментов пригождаются hex-редактор, TweakPNG, многочисленные распаковщики, Python.
Just open it - 15 (Forensics)
I'm almost positive we put a flag in this file. Can you find it for me?
Hint: So many editors out there!
Предлагаемый файл это JPEG-картинка, на которой нет ключа, зато есть артефакт, будто она побилась: с определенного места все квадратики 8×8 сдвинуты на один влево. Многие задачи основаны на том, что в файле одного формата хранятся данные в другом. Такие задачи-матрешки часто требуют широкой эрудиции, но в данном случае все просто. Флаг ABCTF{forensics_1_tooo_easy?} просто написан plain-текстом посреди бинарных данных JPEG, что и привело к побитому блоку.
GZ - 30 (Forensics)
We shot a flag into this file but some things got messed up on the way...
По ссылке качается файл flag без расширения, но опытный глаз без труда различает в заголовке 46-байтного файла сигнатуру 1F 8B. Заголовок задачи не врет, это действительно архив в формате GZ, который открывает, например, 7-zip. А внутри файл с ключом ABCTF{broken_zipper}.
Best Ganondorf - 50 (Forensics)
You know the deal. Find a flag in this this file?
Скачивается файл с расширением .jpg, который, однако, не открывается просмотрщиком картинок. Смотрим на него в hex-редакторе или просто в Lister, если есть Total. Действительно, в его начале отсутствует привычный JFIF-заголовок. Зато в остальном файл вполне похож на JPEG — низкая энтропия первые байт 300, а потом высокая до конца файла. Позаимствуем 11 байт из нормального JPEG-файла и добавим их в этот в hex-редакторе. FF D8 FF E0 00 10 4A 46 49 46 00, и картинка открывается. На ней счастливый азиат, много баксов и наискосок флаг abctf{tfw_kage_r3kt_nyway}.
MoonWalk - 60 (Forensics)
There is something a little off about this picture. If you could help us we could give you some points! Just find us a flag!
На двухметровой PNG-картинке изображен Инки из Pac-Man в темных очках. Слишком большой размер файла вызвал подозрения о том, что внутри PNG могут быть еще какие-то данные, и я воспользовался программой TweakPNG для промотра секций файла. Та немедленно обнаружила «мусор в конце файла» в секции puNK размером 1588789 байт, то есть на 2/3 файла. Находим эту строку и видим, что за ней идет знакомый JFIF-заголовок. Просто пересохраняем содержимое секции:
f = file_get('PurpleThing.png')
file_put('punk.jpg', f[f.index('puNK') + 4:])и открываем. Там фотография листка бумаги, на котором карандашом от руки написан флаг ABCTF{PNG_S0_C00l}. Здесь авторы от души поиздевались над участниками, потому что весьма непросто опознать, что в их неровном почерке нули, а не буквы, и все, кроме последней, буквы заглавные.
PasswordPDF - 80 (Forensics)
Oh no. We locked this PDF and forgot the password. Can you help us?
Hint: Is there anyway to guess the password?
Брутфорсим пароль на PDF силами Advanced PDF Password Recovery, Passware Password Recovery Kit Forensic по словарю из стандартной поставки или чем-то похожим. Пароль оказывается elephant.
Но открыв PDF, мы видим, что там написано Password:, а флаг закрыт большой красной плашкой "Censored!!! You hackers will never get me now". В STDU Viewer можно просто Файл > Экспортировать > как текст и узнать, что флаг ABCTF{Damn_h4x0rz_always_bypassing_my_PD
Zippy - 120 (Forensics)
If your could fix this mess I am sure there would be a flag waiting for you.
По ссылке скачивается архив с 54 ZIP-файлами внутри с именами вида chunk53.zip и размером 130 байт. Внутри каждого архива лежит файл data.txt размером 4 байта, каждый запаролен. Алгоритм шифрования в ZIP слабый и, например, уязвим к plain-text атаке, если известно хотя бы 13 символов, но в данном случае она неприменима и простой брутфорс тоже не дает результата.
Заметим, однако, что к каждому файлу внутри ZIP-архива прилагается CRC32 для контроля целостности. И если внутри просто 4 байта текста, то вполне можно перебрать все возможные тексты и искать среди них с нужным CRC32. Для
#include <iostream>
#include <string>
#include <boost/crc.hpp>
using namespace std;
void check(char *data, unsigned int h)
{
if (h == 3731210267u) { cout << "chunk0.zip: " << string(data, 4) << endl; }
if (h == 2975268760u) { cout << "chunk1.zip: " << string(data, 4) << endl; }
...
}
int main()
{
char data[4];
for (data[0] = ' '; data[0] < '~'; ++data[0]) {
cout << data[0] << endl;
for (data[1] = ' '; data[1] < '~'; ++data[1]) {
for (data[2] = ' '; data[2] < '~'; ++data[2]) {
for (data[3] = ' '; data[3] < '~'; ++data[3]) {
boost::crc_32_type crc32;
crc32.process_bytes(data, 4);
check(data, crc32.checksum());
}
}
}
}
}И весьма быстро получил результат! Впрочем, это оказался не пароль, а закодированный в BASE-64... еще один запароленный ZIP-архив. Внутри лежал flag.txt размером 35 байт. Этот пароль уже вскрылся брутфорсом, потому что состоял всего из 3 символов: z1P. И флаг flag{i_z1pp3d_a_zip_w1th_sum_zips}.
Virtual Series
Эта категория включала тоже задачи на форенсику, но в отличие от предыдущей, где можно было проанализировать файл целиком, здесь предлагался образ, содержащий уйму файлов, среди которых нужно было найти несколько интересных. Инструменты: VirtualBox, файловый менеджер, hex-редактор.
Virtual Box 1 - 10 (Virtual Series)
Do you know how to use a VM? Download the Virtual Machine here.
В этой и последующих задачах этой категории используется один и тот же 645-метровый образ виртуальной машины в формате .ova. Его понимает VirtualBox, да и сам по себе он просто архив с файлом параметров машины и образом диска в формате vmdk. А вот в VMWare он не завелся. Практичным виндоподходом к этой задаче было просто сконвертировать vmdk-файл в vhd-образ командой вида VBoxManage.exe clonehd --format vhd M:disk1.vmdk M:disk1.vhd и примонтировать его через Computer Management > Disk Management > Attach VHD. После этого в системе появлялся диск, к которому можно было применять всю мощь инструментария форенсики, а в несжатом образе vhd найти половину флагов простым поиском подстроки "abctf{".

Первый флаг лежал на рабочем столе в файле "flag 1.doc", намекая, что его было бы неплохо открыть. В нем просто была написан флаг ABCTF{FREE_P0INTS}.
Стоит отметить, что автор задачи предпринял меры, чтобы все вставленные им флаги нельзя было найти, просто отсортировав файлы на ФС по дате. Для этого он использовал FileDate Changer от NirSoft, от использования которой, тем не менее, осталось еще больше следов на ФС :-)
Virtual Box 2 - 15 (Virtual Series)
Darn, I found this flag so I put it in flag 1.doc but I can't seem to be able to see it anymore.
Как и в задаче Just open it - 15 бинарный формат DOC содержит plain-текст с флагом, поэтому достаточно открыть его в plain-текстовом редакторе. ABCTF{H1DDEN_AWAY}.

Virtual Box 3 - 35 (Virtual Series)
This mysterious file was left here, but I have no idea how to open it. Do you? I left it in a folder named 2016 just for you.
В Моих документах лежит папка 2016, а в ней XLSX файл. Если ранние версии Office использовали для форматов DOC и XLS COM Structured Storage, то сейчас, вслед за OpenOffice, данные документа пишутся в XML, которые потом пакуются в ZIP. Флаг находится простым поиском по строке "abctf" внутри архива, в файле sharedStrings: ABCTF{FR0M_THE_FUTURE}.

Virtual Box 4 - 60 (Virtual Series)
What's this?
В Корзине лежит whatsthis.txt, а в нем ABCTF{N0T_S0_D1ff1CULT}, но он неправильный, позднее авторы признались, что просто забыли удалить его, когда создавали задачу. Делаем поиск по ABCTF в имени файла по всему диску и находим c:\program files\Outlook Express\ABCTF{Y0U_F0UND_ME}\whats this.txt. ABCTF{Y0U_F0UND_ME} и есть флаг к этой задаче.

Virtual Box 5 - 75 (Virtual Series)
I accidentaly closed out this odd message I found. Can you get it back?
В форенсике традиционно любопытство к веб-активности пользователя. У IE6 в кэше или истории, в которой не удалили только одну запись, можно найти картинку http://imgur.com/FQJ4JtO:

Сперва кажется, что это шифр простой замены, где первые 5 символов, очевидно, abctf, сильно отличающиеся треугольники это {}, а толстые стрелки вправо соответствуют _. Из abctf{1t2_с34_435167_bac5} заключаем, что 5 наверняка k, 1t2 это its, а окончание предпоследнего слова king, но дальше abctf{its_с34_43king_back} фантазия пробуксовывала, родив разве что неверный остроумный вариант its_сat_taking_back.
Но несколько позже обнаружилось, что это не шифр простой замены, а просто текст, набранный идеографическим шрифтом Wingdings 3. Дублирующиеся стрелки вниз соответствовали двум символам, а не одному, а флаг был ABCTF{ITS_C00L_L00KING_BACK}.
Virtual Box 6 - 75 (Virtual Series)
I really love this pattern, can I set it as my wallpaper? Here it is.
Смотрим список стандартных обоев рабочего стола и замечаем, что к Houndstooth, узор которого используется на платье с картинки по ссылке, справа пририсован текст флага. ABCTF{I_L0VE_PATTERNS.

Virtual Box 7 - 100 (Virtual Series)
Hmm, I wish I could figure out the team that created Windows 98 without the map hassle.
Олдфаги помнят, что если в Windows 98 открыть карту выбора временной зоны (есть, например, в Control Panel > Regional Settings), зажать Ctrl, нажать левую кнопку мыши в районе Каира, отпустить в районе Мемфиса, вновь нажать и отпустить в районе Редмонда вместе с Ctrl, можно увидеть пасхалку, со списком команды разработки Windows 98. Можете еще поискать Польшу :-)

Ту же самую пасхалку можно вызвать и другим способом, если создать ярлык к файлу C:\Application Data\Microsoft\WELCOME\Weldata.exe, передав параметром командной строки You_are_a_real_rascal и указав, что программа должна стартовать с минимизированным окном.
Мы решили, что в процессе запуска пасхалки в выданной виртуалке организаторы что-то нахимичили. На долгие часы я отправился в дизассемблер и расковырял оба пути запуска до последних винтиков.
Файл intl.cpl, отвечающий за региональные настройки в Панели управления, действительно по событиям левой кнопки мыши проверяет, используя WinAPI PtInRect и конечный автомат, попало ли событие в нужную область и выполнены ли они в нужном порядке. Если да, он достает строку "Weldata.exe You_are_a_real_rascal" из ресурсов, зашифрованную увеличением кодов символов на 1, и запускает ее через ShellExecute, добавив путь к папке.
Программа Weldata.exe создает окно, на нем окно браузера, достает из своего тела длинную строку, зашифрованную XOR с аргументом командной строки, пишет ее в ~x520.htm, который запускает в браузере, тут же переименовывает в ~x405.htm и удаляет. Если самому расксорить эту строку со строкой You_are_a_real_rascal, получается HTML-файл с кучей JavaScript, списком авторов, списком картинок, вставлявшихся из res://membg.dll/, фоновой музыкой, и небольшим VBScript, обрабатывавшим нажатия клавиш.
Решительно нигде, ни в intl.cpl, ни в Weldata.exe, ни в Welcome.exe, который она запускает по дефолту, ни в Welcome.dat не было ничего подозрительного, что бы могли изменить организаторы. Ничего не дала даже попытка проксорить с разными сдвигами строки You_are_a_real_rascal весь гигабайтный образ диска. Измучившись сравнением изрядно пропатченной Windows 98 с оригинальным дистрибутивом и парсингом своп-файла, я подумал, а не может ли ответ быть просто ABCTF{You_are_a_real_rascal}? Да, это и был последний флаг категории!
Разбор категорий Reconaissance, Programming, Web Exploitation, Reverse Engineering, Binary Exploitation в следующем посте