Mozilla CTF 2012 - writeup

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

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

Mozilla CTF 2012 - writeup

Опубликовано 26.01.2012 автором Дмитрий Москин
Прошёл очередной CTF, осталось двоякое чувство: с одной стороны - задания интересные, а с другой стороны - одному играть за всю команду как то скучновато, да и опять к заданиям я приступил, когда уже пол игры было сыграно. Но пост, естественно, не об этом :)

Из 22 заданий мне удалось решить только 12, что в итоге дало 2225 баллов и, аж 19е место из 206 команд (119 команд решили хотя бы одно задание). Теперь, собственно, сами таски.

2 - Buoy
3 - Spark - Things long forgotten
5 - Spark - Piracy on the High Seas
7 - Spark - Underwater Camouflage
8 - Spark - Who do you know?
11 - Spark - Message in a Bottle
12 - Joe's Fish Shop
13 - We Love Fish
14 - Text Transformation Puzzle
17 - IP Panel
19 - Fishr - Fish your messages out of the sea

2 - Buoy
Get access to the system of the communication buoy (pwned feds, international waters) and steal the private key that is located in /home/buoy/private.key
It might help you that our intelligence has found the source code.


При входе на указанный сайт, нас встречает форма авторизации, но никаких реквизитов нам не давали, да и ссылки на регистрацию тоже нет, зато есть исходники. Изучив исходники, обращаем внимание на то, что в файле modules/register.php единственная проверка на вводимые пользователем данные - это длина строки в 50 символов, а аккаунты записываются в обычный текстовый файл в формате "username;password;enabled;\n". При этом enabled всегда установлен в 0, что не позволяет воспользоваться аккаунтом, просто зарегистрированным функцией register. Но 50 символов вполне хватает, чтобы за одну регистрацию записать в файл двух пользователей, один из которых будет авторизован, а второй вообще может быть не валидным, ибо это не важно.

Для успешной регистрации пользователя, указываем в качестве имени "random_username;md5_hash_of_password;1;%0A", а в качестве пароля можно указать что угодно. После авторизации, мы получаем доступ к интерфейсу отправки и чтения сообщений, который реализуется в read.php. Все записи хранятся в файлах и их имена генерируются правильно, лишнего не прочитаешь, но вот фильтрация при выводе использует флаг "e" для preg_replace и не экранирует $1, что позволяет выполнить произвольный php код, как будто это не preg_replace, а eval. Зато magic_quotes включен, поэтому эскейпим строку в последовательность chr и в итоге получаем длинную строку:
[uc]{${print(file_get_contents(chr(47).chr(104).chr(111).chr(109).chr(101).chr(47).chr(98).chr(117).chr(111).chr(121).chr(47).chr(112).chr(114).chr(105).chr(118).chr(97).chr(116).chr(101).chr(46).chr(107).chr(101).chr(121)))}}[/uc]

Введя которую в поле отправки сообщения, на странице чтения сообщений, мы получаем флаг: JEn8OIHPRuLVbHFbKbS5ZU.
Вместо последовательности chr можно было использовать бэк-тики:
[uc]{${print(`cat /home/buoy/private.key`)}}[/uc]


3 - Spark - Things long forgotten
Find something the developer forgot about.

Регистрируем пользователя в системе Spark, заходим в свой профиль и в исходном коде, рядом со своим ником, видим html комментарий:
<!-- <a href="http://ocean.mozillactf.org/en-US/users/6461726B">Debug User</a> -->

Обращаем внимание на то, что 6461726B это закодированное в HEX имя пользователя. Переходим по ссылке и видим ещё один комментарий:
<!-- Flag ='There are so many buried treasures in the sea!' -->

Который явно говорит о том, что он флаг :)

5 - Spark - Piracy on the High Seas
Someone has found buried treasure, steal their account and take their ship!

Этот такс был решён во время описания решения для следующего таска :D
Для его решения, я воспользовался ссылкой для смены пароля, полученной в предыдущем задании, но перешёл по ней имени другого пользователя. Уж не знаю, повлияло ли на получение флага то, что у меня было максимальное количество шар в системе или просто нужно было сгенерировать ссылку для смены пароля любого другого пользователя, но тем ни менее, мне дали флаг: "You sunk their battleship!".

7 - Spark - Underwater Camouflage
There's something fishy about the generation of recovery token. Find out how to generate them for other accounts!

У каждого пользователя есть специальный ключ, с помощью которого он может сменить себе пароль, в случае, если он его забыл. Зарегистрировав несколько аккаунтов, с немного отличающимися данными, я выявил закономерность:
email: me@darkbyte.ru
hash: KwkhA1tSTC8YGhwOARAMRSMWBBMfFwsRFg4aHAkAYA0PUhsOGB0LDgEcCg00RUY
email: me@darkbyte.re
hash: KwkhA1tSTC8YGhwOAQAMRSMWBBMfFwsRFg4aDAkAYA0PUhsOGB0LDgEMCg00RUY=

После чего, недолго думая, я проксорил email (повторенный N раз) и декодированный из base64 hash и получил заветную строку: "Flag: 'Many sea creatures hide in plain sight!'"

8 - Spark - Who do you know?
Check the leaderboard and see where you stand in the competition

Возможно, я сделал что-то до этого, например, выбрался на первое место, но, по-моему, достаточно было добиться того, чтобы весь скорборд отобразился на одной странице, для этого в ссылке "/toplist/5/1" меняем 5 на 10000, а 1 на 0 и в самом верху, видим еле заметный флаг "All the fish in the sea!".

11 - Spark - Message in a Bottle
A strangely formatted message has been given to us in a bottle. We know the person who sent the message likes to use cutting edge 3d debugging tools.

Есть просто открыть файл в браузере, то мы увидим только множество единиц, поделенных на блоки 5х5. В исходном коде можно увидеть зашифрованную строку и простой дешефратор, который просто отнимает от каждого символа единицу. Но для решения задания, совсем не обязательно декодировать строку, достаточно посмотреть на DOM и увидев некоторые особенности, добавить стиль "<style>span span{background-color:black}</style>". Получится вполне читабельно. Осталось только записать флаг: MIRAGESAREHARD.

12 - Joe's Fish Shop
Go, get some tasty dinner over at Joe's Fish Shop!
If you know how to play the admin, you'll get free desert! :)

Заходим на сайт и видим почти голый текст, без единой ссылки. Заходим по адресу /admin и не обнаруживаем админки. Смотрим куки и видим: Role=bm90X2FkbWlu и access=user. Записываем Role=YWRtaW4= и access=admin, обновляем страницу и видим: "Welcome Administrator. Please take your flag: x0sld0ef0d".

13 - We Love Fish
The Fish Lover's Blog contains some hidden information. Find it!

И опять сайт без ссылок. Зато в html комментариях находим полезную информацию:
<!-- the files are stored at /webserver_upload_3043493/ctf/hidden_files/ -->
<!-- BUGBUG: make sure permissions on directories and files are correct -->

На секунду мелькает мысль о том, что права на папку всё таки не выставлены и прочитать её содержимое получится без проблем. Но нет, 403 Forbidden. Немного помучавшись, догадываемся, что файл называется flag.txt (на-него то права забыли выставить правильные) и содержит в себе флаг: "youJustGotTheFlagDudeCongrats".

14 - Text Transformation Puzzle
Below is the first paragraph for the book "Flatland".
As a bonus, I will give you this key "49665857477f4b40304276". You will need that to derive the password.

If my ppoor Flatland friend retained the vigour of mind which he enjoyed when he began to compose these Memoirs, TI should not now need to represent him in this preface, in which he desires, flirstly, to return his thanks to his readders and critics in Spaceland, whosew appreciation has, with unexpected celerity, required a sFecond edition of his work; secondlyy, to sapologize for certain Serrors and misprints (for which, however, he is not entirely responsible); and, thirdlyq, to explain one or two misconceptions. But he is not the Square he once was. Years of imprisonment, and the still heavier burden of general incredulity and mockery, have combined with the natural decay of old age to erase from his mind Dmany of the thoughts and notions, and much also of the terminology, which he acquired during his short stay in Spaceland. He has, therefore, requested me to reply in his behalf to two special objections, one of an intellectual, the other of a moral nature.

При чтении представленного текста, глаз цепляется за лишние символы, но т.к. читать его полностью жутко лень, да и можно чего-нибудь пропустить, то гуглим оригинал текста, сравниваем любыми подручными средствами и получаем разницу в виде "pTldwFysSqD". Видим, что длина полученной строки совпадает с ключём (в hex), который дали в начале. Xorим и получаем флаг: "92430923c32".

17 - IP Panel
Exploit Mozillas IP Panel! This IP Panel is used for whitelisting IP addresses. We know that the webinterface will call a bash script that will execute an iptables command without validation. Find the flag somewhere in /home/ippanel/ and submit it!

В задании содержалась небольшая ошибка, которая особо не влияла на его выполнение. Флаг лежал не в домашней директории ippanel, а в текущей дерриктории пользователя www, из под которого и выполнялся скрипт. Это недоразумение значительно упрощало процесс получения ключа, ибо, не смотря на то, что в задании было сказано об отсутствии фильтрации, но тем ни менее, не проходил любой запрос с символом "p", вырезался ряд символов, как например "/ \ [ ] < >". Но для получения флага достаточно было двух команд:
|echo *

Получаем список файлов в текущей директории, среди которых имеется "th15-15_th3_fl4g.txt"
|cat th15-15_th3_fl4g.txt

Получаем флаг: i1gALKeMunqCcyeVMud7TCbI

19 - Fishr - Fish your messages out of the sea
Please log in to Fishr using the name 0wn and the password pwnthis.
The flag is on fl4gdud3's wall, get it.

Некоторый аналог твиттера, только сообщения в нём писать нельзя, только читать, да и опять в задании ошибка, нужно прочитать сообщение пользователя flagdud3, а не fl4gdud3.
Для начала проходим авторизацию и смотрим куки, а потом удаляем одну из кук и обновляем страницу. Неожиданно, на странице появляется ошибка, сообщающая о том, что переменная не определена, но главное, что она указывает на файл, в котором произошла ошибка: /inc/wall.inc. Заходим в директорию /inc/ и видим целых 3 файла с расширением .inc, которые можно прочитать. Их можно скачать отсюда. В файле util.inc интересна функция is_logged_in, которая проверяет валидность кук и проверяет настолько хорошо, что, не зная SECRET, не подделаешь куку data, а так же функция get_login_info, которая парсит куку data.

Но, как оказалось, эта проверка не выполняется, если обращаться не к index.php, а к ajax.php, который, в том числе, отвечает за чтение сообщений. Поэтому достаточно дописать в куку data текст ":admin" и тогда можно будет читать сообщения любого пользователя, в т.ч. flagdud3, который пишет: "Flag: s0ci4lly4wkw4rd".

И на этом всё, на что меня хватило за эти 12 часов, которые я планировал потратить на сон :)

UPD: ещё один сервис, который был решён нашей командой, а точнее by Marchael, но немного позже отведённого времени
Deep beneath the Kritiko Pelagos lie the ruins of lost Atlantis... one who wrote this challenge will reward those who hail from his fair city!

Очень простой таск, как ни странно его решение не имеет никакого отношения к мифическому материку.
Меня подвело то, что недочетав таск до конца я полез искать координаты предпологаемого нахождения и поочередно их постил. На самом деле все было очень просто:
> one who wrote this challenge will reward those who hail from his fair city!
Надо было найти место где живет автор таска.
1. Смотрим https://mozillactf.org/credits.php ищем автора таска №9
2. Гуглим, у меня получислось найти его по запросу "Yvan MozillaCTF"
3. По первой ссылке идем в твитор автора и видим что он из Vancouver
4. Дальше нужно было зарегаться на спарке и посмотреть какие запросы гоняются между серером и клиентом после того как клиент запросит у сервера определить его местоположение.
5. После того как сервер определил наше местоположение, а мы определили запросы которыми это местоположение устанавливается, то мы можем невозбранно его поменять, пользователи фф могут открыть веб-консоль и вбить туда
$.post('http://ocean.mozillactf.org/en-US/m/boost1','csrfmiddlewaretoken=89c058bee6515c178aa0f0fc16660ce8&lat=49.25&long=-123.1&city_id=0&city=Vancouver&country_code=CA&us_state=',function(a,b,c){console.log(a)})
$.post('http://ocean.mozillactf.org/en-US/m/boost1_confirm','csrfmiddlewaretoken=89c058bee6515c178aa0f0fc16660ce8&lat=49.25&long=-123.1&city_id=0&city=Vancouver&country_code=CA&us_state=',function(a,b,c){console.log(a)})

где csrfmiddlewaretoken=89c058bee6515c178aa0f0fc16660ce8 - ваш токен
lat=49.25 - долгота, long=-123.1 - широта, city_id=0 - id города, я его просто оставил как есть, city=Vancouver - город, country_code=CA - код страны, us_state= - оставить как есть.
После чего обновить страницу и увидеть "Flag: Welcome, fellow Atlantean!"