Дмитрий DarkByte Москин

Мой блог, да.
logo

PHDays hackquest writeup

Опубликовано 25.05.2012 автором Дмитрий Москин
Странный CTF, времени много, заданий мало, что необходимо сделать в большинстве случаев не понятно, интерактивные таски меняются налету, файлы с заданиями удаляются, метки с тасками с карты исчезают, без каких либо предупреждений :)

Но не смотря на всё это, играть было интересно, пусть и в свободное от написания диплома время. Начнём разбор с простых флагов:

1) /about.php - 3c34e5b8dff4064dd8855ce47b730605 (+25 points)
2) /robots.txt - 61b5aaf260befbd3e5e9bc4ef9c9fce9 (+25 points)
3) /crossdomain.xml - a8d3e428a4467831a95f5c4002738048 (+50 points)

Moscow hackspace Crackmes (200+25 points)
Shukhov Tower Radiostream (125 points)
Luzhiniki Find a hacker (150 points)
White House Hack the planet (200+100+100+50 points)
Belorussky Rail Terminal Get a ticket code (100 points)
Ostankino Tower Video stream (200 points)
Moscow State University Help students (150 points)
Luzhniki Stadium #2 Find a second hacker (250 points)
Circus on Tsvetnoy Like as fraudster (250 points)
Tretyakov Gallery Find admin's nickname (150 points)


Moscow hackspace Crackmes (200+25 points)
Дан файл crackme.exe, который представляет из себя шифрованный с помощью MMCache PHP скрипт, упакованный в EXE приложение. В самом конце файла можно найти первый флаг: adc4fa7ec8fc519e529f3c59fc77d29e.php - это имя файла со скриптом. Чуть выше можно увидеть вызовы mmcache_load с передачей им в качестве параметров строк в кодировке base64, которые предварительно упакованы функцией gzcompress.

Смотрим первую строку и среди бинарных данных видим слова: argv, md5, 2c211d1ca0d651605d6410286adab7fa, Flag is, YzA2OTc2YWRlYTRkMGZlZTA4NGQ0NzBlNjA=, base64_decode, Serial failed
Usage: crk.exe <SERIAL>. И примерно представляем логику работы скрипта:
if(md5(argv[1]) == '2c211d1ca0d651605d6410286adab7fa')
echo base64_decode('YzA2OTc2YWRlYTRkMGZlZTA4NGQ0NzBlNjA=')+'...';
else echo 'Serial failed';


Но не понятно, откуда берутся ещё 6 символов в флаге, а хеш 2c211d1ca0d651605d6410286adab7fa по базам не находится. Но если поменять этот хеш на какой-нибудь свой, например на 202cb962ac59075b964b07152d234b70, а затем передать программе в качестве параметра строку "123", то она спокойно отдаст флаг: be8d11c06976adea4d0fee084d470e60.


Shukhov Tower Radiostream (125 points)
Дан аудио файл radiostream.mp3 с записью передачи азбукой морзе, практически весь флаг декодируется нормально, за исключением двух символов: 9ad8f48e267d27d2d**cbe02526a9ce7, которые забиты каким-то шумом, но фильтр на 440гц исправляет ситуацию. Флаг: 9ad8f48e267d27d2d8dcbe02526a9ce7.


Luzhiniki Find a hacker (150 points)
Дан дамп wifi трафика dump.pcap, необходимо обнаружить, где находился тот, кто этот трафик генерировал. Собираем все MAC адреса из трафика и с использованием сервиса wigle.net находим координаты wi-fi точек доступа. Накладываем координаты на карту и находим перекрёсток в германии, в городе Нюрнберг. Но т.к. точки сильно разбросаны вокруг перекрёстка, то после нескольких неудачных попыток ввести ответ, пробуем перебор. Всего там три улицы: HESSESTRASSE, KNAUERSTRASSE и OSIANDERSTRASSE, номера домов решил взять от 1 до 30. Правильным ответом оказался "GERMANY:NUREMBERG:HESSESTRASSE:2" и флаг adaea0a697c5b723034589c474be31cb. Я, наверное, чего-то не понял, но эта цифра написана рядом с дорогой, а не на здании.


White House Hack the planet (200+100+100+50 points)
Адрес сайта можно было найти в файле crossdomain.xml: a8d3e428a4467831a95f5c4002738048.hackquest.phdays.com. Но на сайте авторизация, и не понятно, что туда вводить. После бесполезных попыток перебора пароля, запустил сканирование дирректорий и вход таки был найден: папка /debug/. В этой папке находился скрипт следующего содержания:
<?php
if(isset($_GET['file'])){
system("md5sum /tmp/{$_GET['file']}");
}

Скрипт предоставляет доступ к shell оболочке от имени hackquest2. Проанализировав систему, находим устройство /dev/vdc смонтированное по адресу /mnt/secret, но прав на его чтение у нас нет. Зато они есть у утилиты sg_dd, которая позволяет скопировать содержимое раздела туда, куда у нас есть доступ и прочитать его.
-rwx--s--x 1 root backup 39936 May  6 18:48 /usr/bin/sg_dd
brw-r----- 1 root backup 254, 32 May 21 18:10 /dev/vdc

В этом разделе обнаруживаются рандомные данные, а так же флаг: 00b994965fa5ac08fd0a46a8219b4262.
Остальные два флага мне получить не удалось.



Belorussky Rail Terminal Get a ticket code (100 points)
Имеется сайт, которому можно отправлять данные, в ответ на которые он устанавливает куку sso_token с содержимым
<root><ticket seccode='********'><number>123</number><date>25/05/2012 13:37</date></ticket></root>
где 123 - вводимые данные, а под звёздочками скрывается флаг. Сначала подумал про XXE, но не прокатило, стоит фильтр на слова SYSTEM и PUBLIC.
По анализу ошибок удалось примерно восстановить тот XML документ, который передавался в loadXML
<!DOCTYPE root [
<!ATTLIST ticket seccode CDATA "">
<!ENTITY tnum "$input">
]>
<root><ticket seccode="$flag"><number>&tnum;</number><date>25/05/2012 13:37</date></ticket></root>

Переопределяем элемент ticket и говорим, что тип seccode не текст, а ссылка:
"><!ATTLIST ticket seccode IDREF ""><!ENTITY foo "

И получаем флаг в тексте ошибки:
DOMDocument::validate(): IDREF attribute seccode references an unknown ID "16eab33834c9220554ec6c3d4343fc63" in /var/www/hackquest.phdays.com/belorus.php on line 53

Вот оно какое, Error Based XXE.


Ostankino Tower Video stream (200 points)
Дан файл весом 131мб и судя по энтропии он зашифрован. До появления хинта "4CRPHP" было не понятно чем. После стало понятно, что алгоритм RC4, осталось найти ключ. Долгий брут не дал никаких результатов, но потом появилась идея проверить по словарям. Первый же словарь содержал правильный пароль "abcdefgh" (кто бы мог подумать D:). На видео была какая то старая запись с канала ОРТ, в которой в репортаж был вставлен суфлёр для глухонемых (и тех, кто проходит квест).

Читая по рукам и губам удалось получить строку "70a6bb46a62988a696653af", которая очень напоминала флаг, но в ней не хватало ещё нескольких символов. Просмотрев видео ещё раз, заметил, что в некоторых кадрах можно увидеть начало флага: "90050fe00". Но то, что получилось в итоге в качестве флага системой не принималось. Написал об этом организаторам. В ответ выдали правильный флаг "cfd14167b1d838c4226efec87836dc9f".


Moscow State University Help students (150 points)
Задание звучало следующим образом:
A large group of students asks you to give a lecture on the client-side vulnerabilities. You should find materials in Internet to prepare a report.

Первым делом прошерстил гугл по различным запросам, связанным с уязвимостями на клиентской стороне, нашёл с десяток md5 хешей, подходящих под флаг, но в качестве флага они не прокатывали. Затем я обратил внимание на википедию, в частности на категорию, в которой было множество клиентских уязвимостей Web_security_exploits.

Из-за того, что добавленный оргинизаторами хеш могли удалить, для каждой статьи я смотрел историю правок, и чудо произошло. Для статьи "Session fixation" была правка от D0znpp, в которой он добавил флаг 0c8d68bbbc920a7341fdab57292cd88f к одной из ссылок.


Luzhniki Stadium #2 Find a second hacker (250 points)
Дан ещё один дамп трафика, весом 25мб. Опять собираем все MAC адреса wi-fi точек из трафика и прогоняем их через сервис wigle.net. Из полученных координат генерируем kml файл для Google Earth. Обращаем внимание на очерёдность посещения точек.
Получается маршрут примерно такой: MUNICH -> DORTMUND -> LIMBURG -> SIEGBURG -> COLOGNE. И более всего вероятный транспорт: поезд. Пробуем:
00:00:00:GERMANY:MUNICH:00:00:00:GERMANY:COLOGNE:TRAIN:000 - оба города не правильные
00:00:00:GERMANY:DORTMUND:00:00:00:GERMANY:SIEGBURG:TRAIN:000 - город назначения верный
00:00:00:GERMANY:LIMBURG:00:00:00:GERMANY:SIEGBURG:TRAIN:000 - оба города верны

В трафике можно увидеть немного HTTP трафика (+много потокового видео), по ответам сервера узнаём время:
HTTP/1.0 200 OK
Date: Tue, 15 May 2012 21:53:48 GMT

HTTP/1.0 302 Moved Temporarily
Date: Tue, 15 May 2012 22:11:09 GMT

В Германии часовой пояс GMT+2, поэтому добавляем к полученному времени 2 часа. Заходим на сайт bahn.de, в поиск вводим все имеющиеся данные и получаем номер маршрута: 522. Формируем и отправляем ответ
15:05:23:GERMANY:LIMBURG:16:05:00:GERMANY:SIEGBURG:TRAIN:522

Получаем флаг: 9c0649a26448e7e12350141a3dd4dfae


Circus on Tsvetnoy Like as fraudster (250 points)
Был дан номер телефона и задание - заставить его владельца скинуть вам немного денег. Сначала я отправил пару SMS примерно такого содержания:
Для вас доступна новая опция! Бесплатная защита от SMS мошенников. Подробнее по тел. *145*[мойномер]*145# и на сайте beeline.ru
Уважаемый абонент, для Вас была активирована услуга SMS анти-мошенник. Информацию о стоимости читайте на сайте beeline.ru. Для отключения наберите *145*[мойномер]*145# и нажмите кнопку вызова.

Но не прокатило. Через несколько часов пришла другая идея: отправить с сайта билайна SMS с текстом:
Зачислено 124,00 руб
Пополняй баланс за 0%, инфо 0533, oplata.beeline.ru

А затем со своего номера написать, мол ошибся номером, не туда зачислил, верните обратно. Отправил, а в ответ тишина - не прокатило, подумал я, но часов через 6 пришёл ответ, с флагом 89a56ba9fbe0ed7897cf39870f9adc8b :)


Tretyakov Gallery Find admin's nickname (150 points)
Не столько сложный, сколько долгий таск. Решал я его от самого начала игры и до самого конца. В задании был единственный скрипт getimage.php, которому можно было передать в качестве параметра img имя файла изображения. Скрипт выглядит примерно следующим образом:
<?php
header('Content-Type: image/jpg');
$file = './'.$_GET['img'];
if(is_dir($file)) die('No!');
if(!getimagesize($file)) die('Could not read image');
readfile($file);

Если мы запрашиваем не существующий файл, то получаем варнинг:
getimagesize(./qwe) [function.getimagesize]: failed to open stream: No such file or directory in /Library/WebServer/Documents/images/quests/tretyakov/getimage.php on line 13

Путь до файла (хоть он и фейковый) как бы намекает на mac os, а скрипт на то, что нужно найти такой файл, который не будет картинкой, но функцией getimagesize будет воспринят таковым.

План был такой: найти макось, сделать список файлов в системе и прогнать их через данный скрипт. План провалился, ни один файл не подошёл. Поискал информацию про какие нибудь специфичные файлы макоси, нашёл список, среди которого был .DS_Store, скачал несколько примеров файла, часть из них прошла через getimagesize. Поискал во всех известных мне дирректориях таска этот файл - не нашёл.

Затем я собирал списки файлов с различных систем и прогонял их через скрипт. В итоге нужный файл был найден: /etc/aliases.db, а вместе с ним и флаг: e156b1c88788b9522b35ab3409382a40

UPD: для получения оставшихся двух флагов в белом доме необходимо было использовать флаг blk_sgio для sg_dd и прошерстить оставшуюся часть диска в поисках двух флагов, один из которых был в начале, другой ближе к концу.