Перейти к содержимому
← Каталог nodejs IDOR

SSRF: Обход проверки URL через HTTP-редирект в Node.js

Админ-форма импорта продуктового фида проверяет hostname URL и отвергает loopback и приватные сети, но fetch() автоматически следует HTTP-редиректам — внешний сервер атакующего перенаправляет на внутренний /admin/stats и утечка флага.

hardnodejsPro
Задача
# SSRF: обход проверки URL через HTTP-редирект ## Сценарий Перед вами Express-приложение SecureShop — интернет-магазин с админ-панелью. В админке есть удобная фича «Import Product Feed»: оператор подаёт URL партнёрского фида, сервис делает к нему пробный `GET`-запрос и показывает тело ответа, чтобы убедиться, что партнёр действительно отвечает `200 OK` и возвращает ожидаемый формат, прежде чем сохранить адрес в production-конфигурации. Команда понимала, что такой инструмент потенциально опасен: если оставить его без проверок, любой авторизованный администратор сможет «подсмотреть» внутренние сервисы, до которых снаружи доступа нет. Поэтому в код встроена защита: перед каждым запросом hostname URL сверяется со списком запрещённых сетей — loopback (`127.0.0.0/8`, `::1`), приватные RFC1918 (`10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`), link-local (`169.254.0.0/16`). Если URL ведёт в одну из этих сетей — сервис отвечает `403 Forbidden` и до сетевого вызова дело не доходит. Дополнительно фильтр содержит «удобство для разработки»: список доверенных адресов через переменную окружения `PUBLIC_HOST_OVERRIDES` (типичный enterprise-паттерн — staging-прокси на приватной подсети, который маршрутизируется в публичную сеть через SNAT). Хосты из этого списка пропускаются без проверки сети. В том же приложении живёт внутренний админ-эндпоинт `/admin/stats`, который возвращает JSON со статистикой и CTF-флагом. В production его слушает только loopback-интерфейс. Прямая попытка передать форме импорта фида loopback-адрес отвергается на старте: проверка hostname видит запрещённую сеть и блокирует запрос. Но защита проверяет **только начальный URL**. Поведение HTTP-клиента после первого ответа сервиса остаётся незащищённым — а именно там скрывается уязвимость класса **SSRF (Server-Side Request Forgery)**. Ваша задача — построить такой сценарий, в котором проверка hostname проходит на старте, но финальный запрос всё равно уходит на внутренний админ-эндпоинт, и в ответе оказывается CTF-флаг. ## Цели 1. Войдите как администратор и изучите форму «Import Product Feed»; эмпирически убедитесь, что прямой адрес внутреннего эндпоинта блокируется проверкой hostname. 2. Постройте цепочку, в которой начальный URL для проверки выглядит «внешним», а итоговый сетевой запрос всё равно попадает на `/admin/stats`. 3. Извлеките CTF-флаг из JSON-ответа внутреннего эндпоинта. ## Данные | Параметр | Значение | |----------|----------| | Форма импорта фида | `POST /admin/import-feed` (параметры: `url`, `csrf_token`) | | Эндпоинт админ-панели | `GET /admin` | | Эндпоинт с флагом | `GET /admin/stats` (отдаёт JSON с `flag`) | | Учётные данные администратора | `admin / admin` | | Допустимые схемы URL | `http://`, `https://` | | Запрещённые сети начального URL | loopback, RFC1918, link-local | > Подсказка: HTTP-протокол поддерживает не только прямые ответы. Если внешний сервер отвечает `30x` с заголовком `Location:`, многие HTTP-клиенты молча выполняют второй сетевой запрос — уже без всякой повторной валидации. Подумайте, что произойдёт, если адресом «второго запроса» окажется loopback-адрес внутреннего админ-эндпоинта.
🚧 Сайт в разработке. Полный функционал пока недоступен. Все вопросы — support@hackandfix.ru