Bypass SSRF: Обход фильтров хоста
SSRF с обходом слабого фильтра хоста в URL и эксплуатация через альтернативные IP-адреса.
mediumgolangPro
Задача
# SSRF: обход blacklist-фильтрации хоста через альтернативные нотации
## Сценарий
Вы аудируете внутренний сервис **SecureHooks**, в котором есть webhook-форма: пользователь указывает URL внешнего сервиса (Slack, Discord, custom-эндпоинт), а сервер от своего имени отправляет туда тестовый запрос. После предыдущего инцидента команда добавила «защиту» от SSRF: фильтр проверяет hostname в URL по списку запрещённых имён (`localhost`, `127.0.0.1`, `internal`). Команда уверена, что эндпоинт теперь безопасен. По данным внутреннего аудита, в приложении сохранился административный эндпоинт, доверяющий сетевой границе loopback-интерфейса; его требуется достичь, имея только обычную учётную запись.
## Цель
1. Изучите, какие именно строки фильтр считает «запрещёнными» для hostname.
2. Найдите альтернативную нотацию адреса, которая сетевым стеком резолвится в loopback-интерфейс, но строковую проверку не триггерит.
3. Используя серверный HTTP-клиент как прокси, обратитесь к административному эндпоинту и извлеките флаг.
## Теория
Blacklist по строковому представлению hostname — самая частая ошибка при «латании» SSRF: разработчик блокирует точные имена (`localhost`, `127.0.0.1`) или подстроки (`internal`, `private`), но сетевой стек интерпретирует адрес куда более либерально. Один и тот же loopback IP можно записать десятками способов, каждый из которых проходит фильтр и резолвится в `127.0.0.1`.
**Уязвимый паттерн:**
```go
// Защита по строке — обходится альтернативной нотацией адреса
host := parsedURL.Hostname()
if host == "localhost" || host == "127.0.0.1" || strings.Contains(host, "internal") {
http.Error(w, "Forbidden", 403); return
}
resp, _ := http.Get(rawURL)
```
Альтернативные представления loopback включают: сокращённые формы IPv4 (`127.1`, `127.0.1`), целочисленные представления (`2130706433`), шестнадцатеричные (`0x7f000001`), восьмеричные (`0177.0.0.1`), IPv6-нотации (`[::1]`, `[::ffff:127.0.0.1]`), специальные публичные домены, резолвящиеся в loopback (`localtest.me`, `127.0.0.1.nip.io`), unspecified-адрес `0.0.0.0` (на многих системах эквивалентен loopback при подключении). Любая из этих форм проходит строковую проверку, но сетевой стек resolveит её в тот же loopback-интерфейс.
## Точка входа атаки
`POST /webhook` — форма принимает поле `url` и выполняет HTTP-запрос от имени сервера.
* **Цель:** заставить сервер обратиться к внутреннему административному эндпоинту, доверяющему loopback-источнику запроса, и получить флаг из ответа.