
71
T-CTF. Write-up соревнования по кибербезопасности
Capture The Flag (CTF) - соревнования для белых хакеров, которым за ограниченное время нужно "взломать" определенный сервис или приложение либо получить несанкционированный доступ к информации.
T-банк прокодит CTF третий год подряд, насколько я понимаю. Поучаствовать меня пригласил коллега, который принимал участие в прошлом году в CTF, еще работая в прошлой компании. Мне тема зашла - я интересовался различными баг-баунти давно, но только в теории.
В рамках рабочих задач я скорее по ту сторону - обеспечиваю отсутствие уязвимостей на ревью кода, разрабатываю сервисы и схемы обмена данными с учетом их возможного взлома, периодически приходят сторонние заказчики, провожу аудит их кода в том числе с точки зрения безопасности.
Но CTF это непосредственно практика хакинга - одно дело знать что такое SQL инъекция и как от неё защититься, и совсем другое - успешно эксплуатировать её.
Собственно цели на участие у меня стояли следующие:
- попробовать себя в этой сфере;
- проверить насколько эффективными в таких задачах покажут себя ИИ;
- лучше понять сферу эксплуатации уязвимостей, чтобы учесть при разработке.
Давайте пройдем по части задач, которые решить в ходе соревнования удалось. Легенда в рамках T-CTF такая, что действие происходит в вымышленном городе "Капибаровск", где живут капибары, так что названия заданий будут соответствовать. Так называемый write-up заданий в порядке их решения мной.
Капиблагость [средний уровень]
Дано: сайт, который дает при регистрации 1$ баланса, за 1$ можно купить 101 минуту воодушевляющих лекций. Также без потерь можно конвертировать и обратно 101 минуту в 1$. Флаг выдается, когда скуплены все минуты. Также есть исходники сайта на go.
Решение
Открываем исходники в Cursor - просим Sonnet 3.7 найти потенциальную уязвимость. Он быстренько дает ссылку на исходники:
user, exists := loadUser(username)
amountStr := r.FormValue("amount")
amountBaks, err := strconv.ParseUint(amountStr, 10, 64)
if err != nil || amountBaks <= 0 {
http.Error(w, "Неверное количество минут", http.StatusBadRequest)
return
}
dirStr := r.FormValue("direction")
if dirStr == "min_to_baks" {
mins := amountBaks * rate_min_to_baks
if user.BalanceMinutes < mins {
http.Error(w, "Недостаточно минут", http.StatusBadRequest)
return
}
user.BalanceMinutes -= mins
user.FreeMinutesRest += mins
user.BalanceKapibaks += amountBaks
} else if dirStr == "baks_to_min" {
amount_mins := amountBaks * rate_min_to_baks
if user.BalanceKapibaks < amountBaks {
http.Error(w, "Недостаточно капибаксов", http.StatusBadRequest)
return
}
user.BalanceMinutes += amount_mins
user.FreeMinutesRest -= amount_mins
user.BalanceKapibaks -= amountBaks
} else{
http.Error(w, "Не поддерживается", http.StatusBadRequest)
return
}
saveUser(user)
Первая очевидная мысль - race condition. Если одновременно у нас может выполниться 2 операции одного типа - в результате мы получим х2 минут либо баксов. Идея увенчалась неудачей - loadUser и saveUser хранили состояние в файле и даже если что-то и выполнялось параллельно - файл все равно перезаписывался корректными данными.
Ничего другого я не придумал, поэтому решил побрутить логин/пароль - здесь также Cursor написал мне скрипт на питоне и даже составил словарь с учетом входных данных. Причем скрипт не просто проверял подходят ли данные, но и баланс счета. Так я за минуту получил доступ к учетке с логином и паролем capibara123 / capibara123:
Это очевидная недоработка разработчика задания - нужно было делать отдельные БД для пользователей, чтобы такое исключалось. Здесь мы просто покупаем / продаем минуты и получаем флаг.
Какая уязвимость в коде была на самом деле:
type User struct {
Username string `json:"username"`
Password string `json:"password"`
FreeMinutesRest uint64 `json:"freeins"`
BalanceMinutes uint64 `json:"minutes"`
BalanceKapibaks uint64 `json:"kapibaks"`
}
Переполнение uint64 при корректно подобранном значении (max uint64 + 101) при продаже минут даст нам достаточное количество баксов для покупки всех свободных минут. Об этом я узнал уже из чата после окончания мероприятия.
Капитальный ремонт [средний уровень]
Дано: сайт для внесения показаний счетчика с фото. Есть архив с исходниками и начальным дампом сайта, где видно что id мэра = 1. По истории мэр потратил на свой дом кучу денег и нужно было найти куда они ушли. В таблице users есть поле address - флаг лежит в нем.
Решение
Опять просим Cursor найти уязвимость и он быстренько находит SQL инъекцию, здесь бэкенд уже на Java:
public void create(long id, String measurement) {
jdbcTemplate.update(
String.format(
"INSERT INTO measurements (account_id, measurement) VALUES (%d, '%s')",
id,
measurement
)
);
}
При этом сам сервис получает на вход фото счетчика, сначала проверяет есть ли на фото счетчик, дальше распознает показания. Насколько понял - запросами к api gpt-4o.
Т.е. нам нужно внедрить строку запроса в фото со счетчиком. Я с рисованием счетчика особо не страдал, Cursor это уже учел и написал скрипт на питоге, который рисовал мне картинку с "показаниями" уже с "счетчиком" на ней. Еще какое-то время ушло на то, чтобы понять как эксплуатировать SQL Injection правильно, практики у меня в этом не было. В итоге сработал такой вариант:
Отдельно усложняло процесс кривое распознавание текста - то распознается только первый символ, то кавычка превратится в вертикальную черту - приходилось несколько раз заливать одно и то же или менять минимально запрос, чтобы он распознался иначе. После этого идем в список показаний и видим там флаг.
Капибегущая строка [сложный уровень]
Дано: видео, на котором "злоумышленники" взломали освещение здания и запустили на нем бегущую строку. На видео видно начало - TCTF{
- это начало флага. Также есть дамп wireshark сигналов, передаваемых в этот момент.
Решение
Открываем дамп wireshark'ом, видим там zigbee трафик, в описании некоторых записей есть явное OnOff: On - т.е. включение/выключение устройств. Т.е. это сигналы для каждого отдельного пикселя, нужно только восстановить очередность и корректно прочесть.
Изначала пытался как-то сконвертировать все адреса конечных устройств в матрицу, но потом пришла гениальная идея - у нас же бегущая строка, т.е. нам достаточно получить только адреса одного столбца (5 пикселей в высоту - 5 адресов нам нужно). Первые символы мы знаем, разница между кадрами ~150мс - на питоне пишем скрипт, который переводит логи wireshark в последовательность кадров, адреса устройств и состояние, при этом отбрасывает лишнее. Вот так лог выглядел после выкидывания всего мусора (первые 5 кадров после очистки экрана):
2 143 7.373755 0x010c On
3 145 7.528859 0x010b On
4 147 7.683991 0x010a On
4 149 7.687106 0x0119 On
4 151 7.690137 0x0126 On
4 154 7.693926 0x0133 On
4 156 7.696955 0x0140 On
5 158 7.851796 0x0109 On
5 160 7.854978 0x0118 On
5 162 7.857955 0x0119 Off
5 165 7.861403 0x0125 On
5 167 7.864484 0x0126 Off
5 169 7.868092 0x0132 On
5 171 7.871094 0x0133 Off
5 173 7.874080 0x013f On
5 175 7.877072 0x0140 Off
Очевидно, что 0x010c - это правый верхний пиксель, в 4 кадре загорается весь правый столбец (палка от буквы T) - т.е. просто перебираем все эти адреса и покадрово скриптом рисуем матрицу, чтобы получить флаг (прогоняем строку программно по кадрам и восстанавливаем в консоли). Если верно определили адреса - получаем верный ответ (в консоли):
Капибаксы [средний уровень]
Дано: биржа валют, у нас есть информация, что курсы установлены не совсем корректно и есть уязвимая цепочка конвертаций.
Решение
Cursor пытался получить цепочку перебором - бесполезно, была еще куча путаницы с курсами и математикой конвертации в сгенерированных скриптах, пришлось править руками.
Далее скормил ту же задачу o3 - и он написал скрипт поиска цепочки методом Беллмана - Форда, цепочка нашлась:
CAB → BTC → TJS → KPW → ETB → MNT → AOA → PHP → THB → JOD → GEL → STN → SHP → BAM → MYR → PLN → VND → MZN → NGN → AFN → SLL → AZN → BGN → HNL → MGA → CAB
Давала примерно 9% прибыли после прохождения, а нужно было из 100 баксов сделать 13300, после этого "купить франшизу" - тем самым получить флаг. о3 в своем скрипте сразу верно написал запрос и на покупку франшизы и парсинг флага, так что после запуска в консоли и ожидания, пока нужная сумма накрутится - я получил распарсенный флаг в консоли.
Капибарбадос [средний уровень]
Дано: исполняемый файл в формате elf с консольным приложением, в котором происходит регистрация на рейс и прохождение на посадку. Также ssh для подключения к этому сервису для регистрации и посадки.
Решение
Отправляем Cursor искать в чем дело - очень быстро находим, что:
- при регистрации на рейс все получают место по порядку;
- 104 место - место пилота, под ним тоже можно пройти на посадку;
- для прохождения на посадку пилота нужен 8-значный пин-код;
- после того как пилот проходит на посадку - нужно сыграть минуту в какую-то игру, после чего дают флаг.
Какое-то время ушло на написание скрипта для брутфорса пинкода, курсор пытался написать словарь и пробовал варианты вроде 12345678, но это не привело к успеху. o3 написал скрипт для полного перебора (напоминаю, все это по ssh происходит) - и при его запуске оказалось, что пинкод 00000000 подходит - возможно, была уязвимость в коде валидации, т.к. генерация явно была рандомной - здесь я глубже не копал.
Скрипт закрыл, подключился руками, нарегистрировал 104 пассажиров, прошел на посадку пилотом, ввел код и вуаля, играем в флаппи-берд:
Выводы
Команда решила 19 заданий из 30 и по окончании мероприятия занимает 42 место из 1783 прошедших вводное задание (в лиге разработки - это новички):
Далее будут 2 месяца проверок следования командами правил - отсутствие шаринга флагов друг с другом, соблюдение количества человек в команде, критериев опытности. В прошлом году за нарушение правил выкинули из топа команд 15. Как будет в этом - неизвестно, но для получения самого минимального утешительного приза в виде плюшевой капибары - нужно получить хотя бы 20 место. Вряд ли с 42 места возможно попасть на 20, но и цель была не в получении игрушки.
Самое удивительное во всем этом - то, что ни разу ни одна из моделей ИИ не отказалась что-то сломать. Просто пишешь ей ключевое слово CTF - и все, она считает что генерировать SQL инъекции, брутфорсить пароли и взламывать исходники - это святое дело. Так что командам Alignment'а моделей еще есть куда стремиться.
Ну и главный вывод - сейчас уже не нужно досконально разбираться в аспектах дизассемблирования сборок, дешифровке паролей dpapi, sql- и других инъекций - ИИ снижает порог входа кардинально. Достаточно общих знаний, способности быстро ориентироваться в новом материале и какой-то природной сообразительности - и можно успешно решать задачи и попадать в топ-50 лучших команд.
Комментариев пока нет
-
T-CTF. Write-up соревнования по кибербезопасности
Capture The Flag (CTF) - соревнования для белых хакеров, которым за ограниченно… -
Проект смотритель. Часть 8. Софт
Esp32cam - довольно популярный контроллер. Управляемые по wifi девайсы с камеро… -
Проект смотритель. Часть 7. Железо
Схему устройства я уже показал, давайте здесь чуть больше рассмотрим физические… -
Чемпионат области по спортивному программированию
Разбавлю посты о роботе историей из жизни, с роботом вернусь через неделю, там… -
Проект смотритель. Часть 6. Моделирование и печать
Моделирование тоже является одной из сфер, которые мне интересны. Но в отличие… -
Проект смотритель. Часть 5. Гусеницы
Проектируем и печатаем гусеницы на 3д-принтере. Печатать будем из TPU SOFT.