Постановка задачи и архитектура приложения
Всего один некорректно настроенный параметр URL может позволить злоумышленнику использовать запросы на стороне сервера для получения потенциального доступа к внутренним сервисам, конечным точкам облачных метаданных или скрытым ресурсам, которые изначально не предназначались для внешнего доступа. В этой статье, мы рассмотрим процесс постановки задачи и разработки архитектуры приложения, которое использует уязвимость SSRF (Server-Side Request Forgery) для атаки на внутренний админский API.Discovery: поиск SSRF-вектора
Ключевая деталь заключается в том, кто именно отправляет запрос: сервер, а не браузер пользователя. Это имеет важное значение, потому что сервер, как правило, находится внутри доверенного сетевого контура. Он имеет доступ к внутренним API, панелям администрирования, конечным точкам облачных метаданных и бэкенд-сервисам, которые остаются невидимыми для внешних злоумышленников. Внедряя вредоносный URL-адрес, вы фактически «заимствуете» эту привилегированную позицию.
Анализ функции URL preview/fetch
Начните с тех, которые явно управляются через URL, потому что быстрое их исключение позволяет понять, есть ли у цели вообще какая-либо защита от SSRF.Параметры URL, выглядящие как идентификаторы. Параметры с именами являются классическими кандидатами для эксплуатации SSRF:
- callback
- return_url
- redirect_uri
- next
- image_url
- avatar
- url
- uri
- dest
- source
- path
- target
- reference
- site
- feed
Проверка обработки внешних ресурсов
Места, где уязвимости SSRF сохраняются в production-среде. Поля, заголовки или параметры, которые косвенно определяют целевой ресурс; поскольку разработчики редко распознают их как «приемники URL» (URL sinks), они практически никогда не подвергаются столь же тщательной защитной обработке, как более очевидные элементы.HTTP-заголовки, влияющие на маршрутизацию или выборку. Такие заголовки, как:
- X-Forwarded-For
- X-Forwarded-Host
- X-Original-URL
- X-Rewrite-URL
- Referer
- Forwarded
- URL-адреса, внедренные в загруженные файлы
- Внешние сущности XML
- Теги SVG <image href>
- Ссылки на изображения в формате Markdown
- Содержащиеся в загруженном контенте
- HTML-шаблоны в генераторах PDF
- А также файлы DOCX/XLSX с внешними ссылками
Функции импорта и предварительного просмотра файлов. Такие инструменты, как:
- «Импорт по URL»
- RSS-ридеры
- Сервисы создания скриншотов
- Генераторы PDF и конвертеры URL в изображения
file://, а также выполнение внутренних HTTP-запросов.Fingerprinting внутренней сети через SSRF
Это техника разведки, при которой атакующий использует уязвимый веб-сервер в качестве «прокси» для сканирования, маппинга и определения сервисов, находящихся внутри периметра безопасности компании (в локальной сети или в приватном облаке), к которым нет прямого доступа из интернета.Port scanning через SSRF
SSRF позволяет выполнять сканирование внутренних портов, что дает злоумышленникам возможность составить карту внутренних сервисов и выявить уязвимости.В уязвимое URL поле (как правило, от сервиса который что-то импортирует из файлов или ссылок), вводится уязвимый адрес – локальный.
http://127.0.0.1:22Сервер возвращает интересный ответ «Failed to download from (http:127.0.0.1:22): wrong status line: “SSH-2.0-OpenSSH_7.4”», таким образом, мы понимаем что на 22 порту крутиться SSH.
Enumeration internal services (127.0.0.1, 10.0.0.0/8)
Злоумышленники часто начинают эксплуатацию уязвимостей SSRF с перечисления внутренних сервисов. Они систематически сканируют распространенные порты и конечные точки на localhost, а также в диапазонах адресов внутренней сети.Такой «Bruteforce» можно реализовать либо через Burp Suite в разделе Intruder (при наличии pro версии) с регулярным выражением "
^((?!Connection refused).)$*", либо через python-скрипт и библиотеку requests.Обход защитных фильтров
Большинство целевых систем, с которыми вы столкнетесь, тем или иным образом будут проверять ваши входные данные и пытаться воспрепятствовать доступу к внутренним сервисам или запросу ресурсов, на получение которых у вас нет разрешения. Один из способов, к которому прибегают разработчики, заключается в проверке имени хоста в предоставленном URL-адресе путем его сопоставления со списком разрешенных или запрещённых хостов.
IP blacklist bypass (decimal/hex encoding, DNS rebinding)
Приложение будет блокировать запросы к 127.0.0.1 или 192.168.0.1, оно обычно проверяет только строковое значение ввода.ОС и сетевые библиотеки на самом деле понимают IP-адреса не только в привычном формате. Они принимают числа в 16ричных и 8ричных системах или в виде одного огромного числа.
Шестнадцатеричный формат:
127 = 7F, 0 = 00, 1 = 01
http://0x7F00001 или http://0x7F.0x00.0x00.0x01Некоторые из ваших целей пойдут еще дальше и выполнят DNS-запрос для проверки хоста по списку разрешенных адресов. Однако, если уязвимый компонент подвержен уязвимости типа TOCTOU («время проверки — время использования»), мы можем обойти эту проверку посредством DNS-ребиндинга.
- Хакер покупает свой домен и настраивает свой DNS-сервер для него.
- Этот DNS-сервер настроен так, чтобы отдавать ответы с очень коротким временем жизни (TTL=0 или 1 секунда).
- При первом запросе DNS-сервер атакующего возвращает легитимный публичный IP. Валидатор видит, что это не локальный адрес и пропускает его.
- При втором запросе TTL уже истёк. Приложению снова приходится справивать DNS. В этот второй раз DNS-сервер хакера возвращает 127.0.0.1 .
- Приложение думает что направляет запрос на внешний сайт, но отправляет запрос в свой локальный интерфейс.
Protocol smuggling (gopher://, file://)
Методика, при которой хакер использует альтернативные системные или сетевые протоколы, чтобы заставить сервер взаимодействовать с внутренними сервисами или локальной файловой системой.Gopher — это протокол прикладного уровня, предназначенный для распространения, поиска и получения документов через Интернет. Хотя HTTP быстро превзошел его по популярности благодаря появлению HTML и веб-браузеров, Gopher по-прежнему находит применение в определенных нишах - в частности, в сфере исследований безопасности и тестирования на проникновение. Gopher работает на 70 порту TCP и использует простую модель запрос-ответ. Он может возвращать: Файл, Директорию, Поисковой запрос.
Вы можете формировать «сырые» TCP-запросы с помощью Gopher и обходить определенные WAF или SSRF-фильтры.
gopher://127.0.0.1:11211/_%0d%0aset%20x%200%20900%205%0d%0ahello%0d%0afile – это протокол, для чтения локальных файлов. Если бэкенд-движок, выполняющий запросы, поддерживает схему file://, уязвимость SSRF мгновенно превращается в LFI.
Базовый payload для Linux:
file:///etc/passwdБазовый payload для Windows:
file:///C:/Windows/win.iniРазличные атаки на парсеры
Когда у вас есть доступ к исходному коду, задача не ограничивается поиском небезопасных функций. Более эффективный подход заключается в поиске десинхронизации логики. Подобные уязвимости называются parser differentials.Суть атаки заключается в том, что в современном веб-приложении обработкой одного URL-адреса обычно занимаются минимум два разных компонента.
- Валидатор: Код, который проверяет, безопасен ли URL
- Бизнес-логика: Библиотека или утилита, которая делает фактический запрос (cURL, urllib, requests)
Например, манипуляция с символом @:
http://example.com:80@localhost:8080/Манипуляция с символами-разделителями:
http://example.com\localhost или http://example.com#@localhostПространство имён и инъекция порта:
http://localhost:80#@example.com:80Эксплуатация: доступ к admin API
Если уязвимость типа SSRF позволяет обойти сетевые фильтры, конечной целью хакера становится проникновение во внутреннюю инфраструктуру. Одной из наиболее ценных целей при этом является внутренний API администрирования.
Рассмотрим конечную точку API, которая извлекает контент по URL-адресу, указанному пользователем:
NGINX:
POST /api/fetch-content
{
"url": "http://example.com/data"
}
NGINX:
{
"url": "http://localhost:8000/admin"
}
Извлечение sensitive endpoints
Поскольку разработчики часто считают, что внутренняя сеть находится в безопасности, административные интерфейсы (Admin API) внутри периметра часто лишены авторизации, но при этом детально документированы или имеют предсказуемую структуру.Современные разработчики редко пишут документацию вручную — за них это делают фреймворки. Если через SSRF удается дотянуться до внутреннего порта приложения, первым делом проверяется наличие автоматически сгенерированных схем API.
Если автоматической документации нет, эндпоинты приходится искать перебором. Для этого используются специализированные словари (api-endpoints.txt или common-api-endpoints).
Получение admin credentials из metadata service
Если приложение выполняется в облачной среде, уязвимость SSRF приобретает значительно более серьезные последствия. Облачные провайдеры предоставляют доступ к конечной точке метаданных, доступной исключительно изнутри самого инстанса. Эта точка содержит учетные данные IAM, SSH-ключи, конфигурацию инстанса, а также скрипты пользовательских данных, в которых зачастую хранятся секреты; именно поэтому облачные метаданные представляют собой наиболее высокооплачиваемый вектор эскалации привилегий через SSRF - и именно на эту угрозу команды реагирования реагируют быстрее всего. (AWS EC2 metadata service (IMDSv1))http://111.111.111.111/latest/meta-data/http://111.111.111.111/latest/meta-data/iam/security-credentials/Сначала перечислите доступные роли IAM, получив список учетных данных.
http://111.111.111.111/latest/meta-data/iam/security-credentials/{ROLE}В ответе возвращаются временные значения AccessKeyId, SecretAccessKey и Token - действительные учетные данные AWS, которые можно немедленно использовать в AWS CLI для дальнейшей эксплуатации.
Escalation до RCE
Поскольку тип атаки SSRF не достаточно гибок для RCE, то мы используем службы. Протокол gopher:// представляет собой одну из наиболее мощных доступных техник эскалации SSRF. В отличие от http://, который ограничен структурой HTTP-запросов, Gopher позволяет серверу отправлять произвольные «сырые» байты на любой TCP-порт. Именно такая техника служит мостом между SSRF и RCE при атаках на реальные цели. Вы можете взаимодействовать с Redis, MySQL, SMTP, FastCGI или любым другим протоколом.Экземпляры Redis, доступные на localhost без аутентификации, - частое явление в устаревших развертываниях и некорректно настроенных средах Docker. Redis позволяет записывать файлы в файловую систему с помощью команды CONFIG SET; если корневой каталог веб-сервера или директория crontab доступны для записи, это открывает возможность для удаленного выполнения кода (RCE).
При использовании инструмента Gopherus генерация полезной нагрузки выполняется одной командой:
gopherus --exploit redisПосле URL-кодирования в формат Gopher URL и передачи через параметр SSRF сервер устанавливает соединение с Redis на порту 6379.
PHP-FPM, прослушивающий порт 9000, представляет собой еще одну весьма ценную цель для Gopher. FastCGI позволяет задавать произвольные значения в конфигурации PHP (.ini), а также выполнять любой файл, присутствующий в файловой системе. Опция --exploit fastcgi инструмента Gopherus генерирует полезную нагрузку на основе указанного пути к любому .php-файлу на сервере.
Defense in depth для микросервисов
Если хакер взломает один контейнер, при отсутствии внутренней защиты он мгновенно захватит всю сеть («soft belly» эффект).
Network policies и segmentation
Главный принцип — микросервисы не должны видеть те сервисы, с которыми им не нужно общаться по бизнес-логике.- Внедрение инструментов вроде Istio, Linkerd или Consul первично. Они создают выделенный слой для управления трафиком.
- Шифрование всего трафика между микросервисами с проверкой сертификатов в режиме «каждый с каждым».
- Настройка сетевых плагинов (Calico, Cilium) для изоляции подов.
- Нельзя верить запросу только потому, что он пришел от соседнего сервиса.
- Каждый эндпоинт внутри периметра должен проверять права, а не просто доверять локальному IP.
SSRF-защита в коде (allow-list domains, схем)
Очевидно, что первый этап - ограничение выбора протокола – только http или https.Для NodeJS например, используется библиотека axios для такой реализации:
JavaScript:
const axios = require('axios');
const URL = require('url');
function safeFetch(userUrl) {
const parsedUrl = URL.parse(userUrl);
const allowedProtocols = ['http:', 'https:'];
if (!allowedProtocols.includes(parsedUrl.protocol)) {
throw new Error("Only HTTP or HTTPS.");
}
}
Если приложение должно отправлять запросы только на доверенные сторонние ресурсы, необходимо проверять хост по строгому списку разрешенных доменов.
Важно использовать следующий алгоритм проверки:
- Распарсить URL с помощью надёжного встроенного парсера языка программирования
- Извлечь чистый хост
- Проверить полное совпадение с элементами белого списка
Python:
from urllib.parse import urlparse
import requests
ALLOWED_DOMAINS = ["api.example.com", "api.github.com", "images.pictures.com"]
def safe_get_request(user_input_url):
try:
parsed_url = urlparse(user_input_url)
if parsed_url.scheme not in ["http", "https"]:
raise ValueError("Invalid protocol")
target_host = parsed_url.hostname
if target_host not in ALLOWED_DOMAIN
raise ValueError("Access Denied: Domain not allowed")
response = requests.get(user_input_url, timeout=5)
return response.text
except Exception as e:
return f"Error: {str(e)}"
Если приложение должно разрешать пользователям вводить любые внешние домены, обычный Allow-list доменов не поможет. Хакер может использовать свой домен, настроенный на DNS Rebinding.
Безопасный алгоритм для произвольных URL:
- Выделяем хост из URL.
- Программно преобразуем домен в IP-адрес до отправки HTTP-запроса.
- Убеждаемся, что полученный IP-адрес не является приватным.
- Делаем HTTP-запрос напрямую на проверенный IP-адрес, а исходный домен передаём исключительно в заголовке Host. Это лишает DNS Rebinding всякого смысла, так как повторного DNS-запроса уже не будет.
Runtime protection (WAF rules, egress monitoring)
Когда безопасность на уровне исходного кода невозможна, защита от SSRF переносится на уровень Runtime Protection.WAF работает на входном (Ingress) направлении. Его задача — проанализировать входящий HTTP-запрос от пользователя и заблокировать его до того, как он попадет в приложение, если в параметрах обнаружены признаки SSRF. Поскольку WAF видит только строку запроса, его правила (Signatures) в основном нацелены на блокировку альтернативных кодировок IP-адресов и опасных протоколов.
- Блокировка схем file:// и gopher://
- Блокировка обращений к локальной сети и метаданным.
- Блокировка шестнадцатеричных и десятичных IP.
В современных микросервисных средах (Kubernetes + Istio/Envoy) по умолчанию применяется подход Deny-All для исходящего трафика. Контейнерам запрещено инициировать соединения с внешним миром и другими сервисами, если это явно не разрешено.
Cloud-специфика (IMDSv2, VPC endpoints)
IMDS решает важную задачу безопасности для облачных пользователей, предоставляя доступ к временным и часто обновляемым учетным данным, а также устраняя необходимость жестко прописывать (hardcode) или вручную (либо программно) распространять конфиденциальные учетные данные непосредственно на экземпляры. Вторая версия Службы метаданных экземпляров (IMDSv2) добавляет дополнительные механизмы защиты; в частности, IMDSv2 использует сеансовую аутентификацию со следующими усовершенствованиями.- Для начала сеанса IMDSv2 требуется создание секретного токена посредством простого HTTP-запроса типа PUT; этот токен должен использоваться для получения информации при выполнении вызовов к IMDSv2.
- Токен сеанса IMDSv2 должен передаваться в качестве заголовка в последующих запросах к IMDSv2 для получения информации из службы метаданных. В отличие от статического токена или фиксированного заголовка, сеанс и соответствующий ему токен уничтожаются, как только завершается процесс, использующий этот токен. Сеансы IMDSv2 могут длиться до шести часов.
- Токен сеанса может быть использован только непосредственно с того экземпляра EC2, на котором был инициирован данный сеанс.
- Вы можете либо повторно использовать уже существующий токен, либо создавать новый токен для каждого отдельного запроса.
- Запросы PUT для создания токена сеанса блокируются, если они содержат заголовок X-forwarded-for.
Если хакер заперт внутри сети и не может вызвать внешний адрес 169.254.169.254, он начинает сканировать внутренний диапазон сети на предмет живых веб-интерфейсов.
Если в компании настроен S3 VPC Endpoint, атакующий через SSRF может обратиться к внутреннему DNS-имени этого эндпоинта. Если у роли, под которой запущено приложение, есть доступ к бакетам (чтение/запись), хакер сможет скачивать конфиденциальные файлы компании прямо из S3, используя SSRF как прокси, даже если сам бакет закрыт от всего интернета.
Литература
https://infosecwriteups.com/ssrf-in-apis-how-a-single-url-parameter-can-expose-internal-systems-63128bff63a4https://kariiem.medium.com/0dssrf-automate-finding-ssrf-external-service-interactions-open-redirects-944be6770a02
https://www.yeswehack.com/learn-bug-bounty/server-side-request-forgery-ssrf
https://medium.com/@zoningxtr/gopher-protocol-a-forgotten-protocol-with-modern-security-implications-932188d5c65e
https://www.intigriti.com/researchers/blog/hacking-tools/ssrf-a-complete-guide-to-exploiting-advanced-ssrf-vulnerabilities#2-bypassing-host-whitelists
https://blogs.jsmon.sh/source-code-analysis-exploiting-parser-differentials-in-ssrf-unicode/
https://iaraoz.medium.com/hacking-apis-attackers-exploiting-ssrf-57624d575987
https://bitpanic.medium.com/beginners-introduction-to-server-side-request-forgery-85c3a35eb726
https://aws.amazon.com/blogs/security/get-the-full-benefits-of-imdsv2-and-disable-imdsv1-across-your-aws-infrastructure/