Perimeter Leak

Challenge Description

Table of Contents

Solution Overview

This challenge demonstrates a multi-stage cloud security exploit chain involving:

  1. Spring Boot Actuator Exposure - Discovering misconfigured management endpoints

  2. SSRF Vulnerability - Exploiting a proxy endpoint to access internal resources

  3. IMDS Access - Bypassing IMDSv2 protections to retrieve EC2 instance credentials

  4. S3 Enumeration - Using temporary IAM credentials to access cloud storage

  5. VPCE Bypass - Leveraging presigned URLs to circumvent VPC endpoint restrictions

Key Vulnerability: A misconfigured Spring Boot application with an exposed proxy endpoint allows Server-Side Request Forgery (SSRF), enabling access to the AWS EC2 Instance Metadata Service (IMDS), retrieval of temporary IAM credentials, and bypass of S3 bucket policies using presigned URLs.

Enumerating Spring Boot Application

Initial reconnaissance reveals the target application:

Curling the index page suggests this is a proxy server:

However, initial path enumeration doesn't reveal any accessible endpoints.

Discovering Spring Boot Actuator Endpoints

Spring Boot applications often expose management endpoints through Spring Boot Actuator, which provides built-in endpoints for monitoring and managing applications. Common Actuator endpoints include:

  • /actuator - Lists all available actuator endpoints

  • /actuator/env - Displays environment properties

  • /actuator/health - Shows application health status

  • /actuator/mappings - Shows all request mappings

Let's check if the /actuator endpoint is exposed:

Success! The actuator endpoint is accessible and reveals several management endpoints:

Note: Exposing Spring Boot Actuator endpoints without proper authentication is a common misconfiguration that can leak sensitive information about the application's configuration, environment variables, and internal structure.

Analyzing Endpoint Mappings

Examining the /actuator/mappings endpoint reveals the application's route configuration. Filtering out the noise, we identify two interesting endpoints:

  1. /proxy - Accepts a url parameter (potential SSRF vector)

  2. Standard actuator endpoints

Testing the /proxy endpoint:

Initial access attempt returns a 401 Unauthorized error:

Attempting to proxy http://example.com reveals a verbose error message with valuable information:

Testing with example.com:

Response:

Key findings from the error message:

  1. The proxy accepts a url parameter

  2. The proxy passes along headers and different request types (HTTP methods)

  3. The proxy only allows URLs containing:

    • IP addresses (e.g., 169.254.169.254)

    • Hostnames containing amazonaws.com

  4. This restriction is intended to limit the proxy to AWS services only

This configuration creates a Server-Side Request Forgery (SSRF) vulnerability that can be exploited to access internal AWS metadata services!

Exploiting SSRF to Access IMDS

Understanding IMDSv2

The AWS Instance Metadata Service (IMDS) is accessible at http://169.254.169.254 from within EC2 instances. It provides information about the instance, including:

  • Instance ID and type

  • Security credentials (IAM role credentials)

  • Network configuration

  • User data

AWS introduced IMDSv2 (Instance Metadata Service Version 2) as a defense-in-depth measure against SSRF attacks. IMDSv2 requires a session token obtained via a PUT request, which traditional SSRF attacks cannot easily perform.

Initial IMDS access attempt:

Attempting to access IMDS directly returns a 401 Unauthorized error, confirming IMDSv2 is enabled:

Bypassing IMDSv2 Protection

Remember from the error message: "This proxy passes along headers and different request types"

This is critical! Since the proxy forwards:

  • HTTP headers

  • Different HTTP methods (GET, PUT, etc.)

We can exploit this to perform the IMDSv2 token request flow through the proxy!

Step 1: Request an IMDSv2 session token using PUT

Parameters explained:

  • -X PUT - Uses HTTP PUT method (required for IMDSv2 token request)

  • X-aws-ec2-metadata-token-ttl-seconds: 21600 - Requests a token valid for 6 hours (21600 seconds)

  • Target: http://169.254.169.254/latest/api/token - IMDSv2 token endpoint

Response:

Success! We received a valid IMDSv2 session token.

Step 2: Use the token to access IMDS metadata

Response:

Excellent! The metadata endpoint is now accessible. From the output, we can see an IAM instance profile is attached to this EC2 instance, which means we can retrieve temporary IAM credentials.

Retrieving IAM Credentials

IAM instance profiles provide temporary security credentials to EC2 instances. Let's retrieve them:

Step 1: List available IAM roles

This reveals the IAM role name: challenge01-5592368

Step 2: Retrieve the IAM security credentials

Retrieved credentials:

Credential details:

Perfect! We now have temporary IAM credentials consisting of:

  • AccessKeyId - AWS access key

  • SecretAccessKey - AWS secret key

  • Token - Session token (required for temporary credentials)

  • Expiration - When the credentials expire (valid for ~6 hours)

Utilizing Temporary Credentials

Now that we have valid AWS credentials, let's configure the AWS CLI to use them.

Configuring AWS CLI

Enumerating S3 Buckets

Since the challenge description mentions an S3 bucket, let's attempt to enumerate S3 resources:

The aws s3 ls command fails with an access denied error. The IAM role doesn't have permission to list all S3 buckets.

Alternative approach: Recall that earlier, when enumerating /actuator/env, we discovered environment variables containing sensitive configuration data. Let's check if there's an S3 bucket name in the environment:

Excellent! The environment variables reveal the S3 bucket name: challenge01-470f711

Note: Exposing environment variables through /actuator/env is dangerous as they often contain sensitive information like database credentials, API keys, and resource names.

Accessing the S3 Bucket

With the bucket name in hand, let's list its contents:

Success! We can see two files:

  • hello.txt - A test file

  • private/flag.txt - The flag (in a private/ directory)

Attempting to download all files:

Interesting findings:

  • hello.txt downloaded successfully

  • private/flag.txt failed with Access Denied

There's an explicit deny policy preventing access to files in the private/ directory. Let's investigate the bucket policy to understand this restriction.

Analyzing S3 Bucket Policy

Let's retrieve and examine the bucket policy:

Bucket Policy:

Policy Analysis:

  • Effect: Deny - This is an explicit deny (takes precedence over any allow statements)

  • Principal: * - Applies to all principals (users, roles, services)

  • Action: s3:GetObject - Blocks downloading objects

  • Resource: arn:aws:s3:::challenge01-470f711/private/* - Only affects files in the /private/ directory

  • Condition: StringNotEquals with aws:SourceVpce - Only allows access from a specific VPC endpoint

Understanding VPC Endpoints (VPCE):

A VPC Endpoint (VPCE) allows resources within a VPC to connect to AWS services (like S3) privately, without traversing the public internet. The condition aws:SourceVpce: vpce-0dfd8b6aa1642a057 means:

  • Requests from VPC Endpoint vpce-0dfd8b6aa1642a057Allowed

  • Requests from anywhere else (including our web s) → Denied

Since the EC2 instance is in the VPC and uses this VPC endpoint, requests made through the proxy will satisfy this condition!

Bypassing VPCE Restrictions with Presigned URLs

The Challenge:

  • We have valid IAM credentials

  • We can access the proxy (which uses the VPC endpoint)

  • We need to retrieve private/flag.txt through the VPC endpoint

The Solution: AWS S3 Presigned URLs

A presigned URL is a temporary URL that grants access to a specific S3 object. It includes:

  • Authentication information (embedded in query parameters)

  • Expiration time

  • Specific permissions (e.g., GET access)

When someone uses a presigned URL, they inherit the permissions of the IAM principal who generated it!

Step 1: Generate a presigned URL

Generated presigned URL:

Step 2: URL encode the presigned URL

Since we're passing the presigned URL as a query parameter to the proxy, we need to URL encode it. We can use CyberChef or any URL encoder:

Step 3: Access the flag through the proxy

Success!

Summary:

  1. The presigned URL contains our IAM credentials (embedded in the URL parameters)

  2. The request goes through the proxy server

  3. The proxy uses the VPC endpoint (vpce-0dfd8b6aa1642a057)

  4. The S3 bucket policy allows requests from this VPC endpoint

  5. We successfully retrieve the flag!

Flag: WIZ_CTF_Presigned_Urls_Are_Everywhere

Last updated