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

SSRF через обход проверки IP с помощью HTTP-редиректа

Приложение проверяет IP адрес при первом запросе, но cURL автоматически следует редиректам на внутренние адреса — атакующий обходит проверку через промежуточный сервер.

hardphpPro
Задача
# SSRF через обход проверки IP с помощью HTTP-редиректа ## Сценарий Интернет-магазин **SecureShop** содержит функцию предпросмотра ссылок: пользователь вводит URL в форму, сервер скачивает содержимое и возвращает превью. Эндпоинт `POST /fetch-url` обрабатывает запросы и использует cURL для загрузки. Разработчики знали про класс уязвимостей **Server-Side Request Forgery (SSRF)** и попытались защититься: перед запросом резолвят имя хоста в IP-адрес и блокируют loopback-диапазон (`127.0.0.0/8`, `::1`). Прямой запрос к `http://127.0.0.1:8080/admin/stats` возвращает `403 Access denied`. Однако реализация защиты — однократная: проверяется только начальный URL. cURL настроен с `CURLOPT_FOLLOWLOCATION = true`, что означает автоматическое следование 301/302 редиректам без повторной валидации адреса назначения. Это и есть **redirect-based SSRF bypass** — классический шаблон, когда фильтр охраняет «входную дверь», но не следит, куда ведёт цепочка перенаправлений. ## В чём суть атаки HTTP-запрос — это не одно действие, а последовательность шагов: TCP-коннект, отправка request, получение response, при 3xx — повторный коннект к новому хосту. Защита, проверяющая только первый URL, оставляет «зазор» между «фильтр одобрил» и «сервер реально подключился к внутреннему ресурсу». Атакующему нужны два элемента: 1. **Целевой внутренний эндпоинт** — `/admin/stats`, который содержит конфиденциальные данные (флаг, пароль администратора), но открыт только для запросов с `127.0.0.1`. 2. **Открытый редиректор** — публично доступный URL, который проходит первичную проверку и возвращает `302 Location: <внутренний адрес>`. В этой лабе роль «редиректора» играет встроенный эндпоинт `GET /redirect?target=URL`, доступный по адресу `0.0.0.0:8080` (тот же контейнер, но другой публичный IP проходит фильтр `127.`). В реальной системе таким редиректором мог бы быть OAuth callback, partner-tracking URL, open-redirect в маркетинговом домене — везде, где разработчики позволяют контролируемый `Location`-заголовок. ## Цели 1. Авторизуйтесь как `demo` / `demo` и найдите форму предпросмотра ссылок. 2. Убедитесь, что прямой запрос с loopback-адресом (`http://127.0.0.1:8080/admin/stats`) блокируется фильтром. 3. Найдите эндпоинт, который умеет возвращать редирект на произвольный URL. 4. Постройте цепочку: внешне-валидный URL → 302 → внутренний адрес. 5. Извлеките CTF-флаг из JSON-ответа эндпоинта `/admin/stats`. ## Данные | Параметр | Значение | |----------|----------| | Обычный пользователь | `demo` / `demo` | | Внутренний эндпоинт с флагом | `/admin/stats` (доступен только с `127.0.0.1`) | | Эндпоинт загрузки URL | `POST /fetch-url` (параметр `url`) | | Встроенный редиректор | `GET /redirect?target=<URL>` (возвращает 302) | > Подсказка: первичный фильтр проверяет, что резолвленный IP не начинается с `127.`. Но это не единственный способ адресовать сервер по loopback — есть алиасы и адреса-маркеры, которые проходят такую строковую проверку, но фактически указывают на ту же машину.
🚧 Сайт в разработке. Полный функционал пока недоступен. Все вопросы — support@hackandfix.ru