Приветствую всех любителей CTF и этичного хакинга на стороне Red Team! В этой статье мы рассмотрим прохождение таска средней сложности "ТЕТРИС", разработанного пентестерами из команды Codeby.Games.
Справка: codeby.games - отечественный условно бесплатный веб-проект, где каждый может попрактиковаться в оттачивании навыков наступательной кибербезопасности. Таски (задания) представлены в широком спектре: начиная от использования методов OSINT и заканчивая компрометацией учебного домена Active Directory. CTF разделяются на три группы - "Легкий", "Средний", "Сложный" в различных категориях. Но подробнее об этом - на официальном сайте проекта.
Задание "Тетрис" находится в категории "Веб". Категория посвящена оттачиванию практических навыков в рамках OWASP Top 10. Цель этого задания - получить доступ к панели администратора веб-приложения и захватить флаг.
Общий план решения CTF выглядит так:
Посещаем веб-ресурс с уязвимым API и изучаем функционал API.
Изучаем исходный код API и находим уязвимости в коде.
Эксплуатируем уязвимость.
Получаем флаг.
Комментарий: на первый взгляд может показаться, что задание не такое уж и сложное. Однако это далеко не так. Таск относится к категории OWASP Top 10, а это значит, что нужно акцентировать внимание на анализе логики приложения и искать ошибки/недоработки, связанные с ее построением.
Посещаем веб-ресурс с уязвимым API и изучаем функционал API
Мы видим перед собой форму для регистрации новых пользователей. Регистрируемся с дефолтными кредами "user:123"
После авторизации перед нами возникает простенький веб-интерфейс, в котором реализована "игра миллионов" - тетрис. Сверху опция logout.
Функционал крайне скромный для того, чтобы определить вектор атаки. Что делать дальше? Продолжать изучать логику приложения.
Попробуем выполнить вход под УЗ администратора. Ожидаемо получаем ошибку - "invalid credintals". Что делать дальше? Продолжать изучать логику приложения.

Одним из способов получения доступа в админку является сброс пароля. Попробуем воспользоваться формой "Forget Password?".


Сервер отправил ссылку для восстановления пароля на почту, которую мы, конечно же, не знаем. Что делать дальше?
2. Изучаем исходный код API и находим уязвимости
Нам очень повезло, т.к. к заданию прилагается zip-архив с исходным кодом (в реальной жизни такое бывает только в случае тестирования API в режиме White Box).
Комментарий: заранее прошу прощения у новичков: я не буду детально описывать код API, "разжевывая" каждую строку. Во-первых, это существенно увеличит время чтения статьи. Во-вторых,"Тетрис" - все-таки задание из категории средней сложности. В нем подразумевается, что вы уже владеете языками программирования (в нашем случае python), а также уверенно представляете себе, что такое об SQL-запросы и локальные БД. Прошу отнестись с пониманием)
2.1 Запускам приложение и попутно приступаем к анализу файла "main.py". Приложение реализовано на Flask, после запуска открывается доступ внутри VLAN, генерируется простенькая sqlite3-БД, а также пароль админа к веб-интерфейсу, состоящий из 12 символов разного регистра.

При каждом новом посещении веб-ресурса, локальная БД и админский пароль сбрасываются, а затем генерируется заново. Отсюда первый вывод: забрутфорсить пароль админа не получится.
2.2 Идем дальше. Изучаем функции API, а также их назначение. Внимание привлекают reset_password и reset_uuid


Первая обрабатывает запрос на восстановление пароля, вторая - формирует ссылку для сброса пароля. Изучаем файл локальной БД, которая автоматически создается при запуске Web API.

Выводы из анализа API:
Генерация reset_uuid происходит происходит после отправки POST-запроса к эндпоинту /reset_password&&username=<username>.
Сброс пароля пользователя осуществляется в результате GET-запроса к эндпониту /reset/<reset_uuid>.
По замыслу разработчика, ссылка отправляется на почту и перехватить ее не предоставляется возможным. НО!
Количество уникальных комбинаций reset_uuid составляет всего 729 штук. С точки зрения безопасности веб-приложения, это критически мало. Это значит, что...
Эндпоинт /reset/<reset_uuid> уязвим для брутфорса!!
3. Эксплуатируем уязвимость
Сначала задача мне показалась очень простой. Я сгенерировал словарь "tokens.txt" и запустил Burp Intruder. Но тут же столкнулся с проблемой - сбросить пароль админа получилось, но запустить новую сессию от его имени - нет.

Почему так произошло? Потому что знать об уязвимости мало, нужно еще понять, как ее проэксплуатировать. Для этого мы снова возвращаемся к анализу логики, но на этот раз - на стороне сервера.


Что такое флаг "HttpOnly" и как его обойти, я предлагаю вам изучить самостоятельно :)
4. Захват флага
Преодолев защиту на стороне сервера, запросите эндпоинт /admin и будет вам счастье.

На этом все. Удачной охоты за жуками!)
P.s.
Задание действительно интересное и - самое главное - полезное с практической точки зрения. Сброс пароля пользователя - базовый функционал любого API. Разработчик может предусмотреть защиту со стороны сервера, ограничить доступ к исходному коду, обеспечить безопасное хранение и передачу ссылок, но может забыть про безопасную генерацию reset-link.
Мог ли злоумышленник найти эту уязвимость, не имея доступа к исходному коду веб-приложения? Да. Достаточно зарегистрировать несколько УЗ и внимательно изучить ссылки для восстановления пароля, чтобы установить некоторые закономерности.