AWS: IAM AssumeRole Privilege Escalation
As more and more organizations are relying on cloud services, it becomes critical to understand the complexity of the cloud environments and misconfigurations that can lead to resource and account compromise. This guide will cover the most serious security threat in the AWS environments that is the privilege escalation via role assumption, a scenario where a user with limited IAM permissions can gain the elevated access to the resources using a misconfigured IAM role.
Table of Contents
Introduction to AWS IAM
IAM Key Terms
About AssumeRole
Lab Setup and Prerequisite
Part 1: Vulnerable IAM Lab Setup
- Provisioning a Low- Privileged IAM User
- Provisioning a High Privileged IAM Role
- Setting up an S3 Bucket
Part 2: IAM Enumeration and Exploitation
- How could a user gain access to a High -Privilege IAM Role
- Enumeration IAM Role with Enumerate-iam Python Script
- Enumeration IAM Role with AWS CLI
- IAM AssumeRole Privilege Escalation
Analysis
Recommendation
Conclusion
Introduction to AWS IAM
AWS Identity and Access Management (IAM) is a web service that helps you securely control access to AWS resources. Specifically, with IAM, you can manage permissions that control which AWS resources users can access. In other words, you use IAM to control who is authenticated (signed in) and authorized (has permissions) to use resources. Furthermore, IAM provides the infrastructure necessary to control authentication and authorization for your AWS accounts.
IAM Key Terms
- Principal: Umbrella term for IAM identities
- IAM User: Principal with long-term credentials
- Programmatic access via Access Key ID and Secret Access Key
- Web console access via username and password
- IAM Role: Principal that can be assumed by others
- IAM Policy: Permissions that can be assigned to a principal or group
About AssumeRole
Role assumption is the act of temporarily taking on the permissions of an IAM role. When a user (or another role/service) assumes a role, AWS provides them with temporary security credentials consist of an access key ID, a secret access key, and a session token. These credentials allow them to perform actions defined by the role they assumed.
This is commonly used within the same account or across accounts (cross-account access). The AssumeRole action is an API operation in AWS Identity and Access Management (IAM) that makes this possible.
Role assumption helps follow the principle of least privilege, allowing users to switch into roles with only the permissions they need without having to manage multiple sets of permanent credentials.
Key Components of Role Assumption:
- Trust Policy – Defines who is allowed to assume the role.
- Permissions Policy – Defines what actions the role can perform.
- Temporary Credentials – Issued by AWS STS when a role is assumed.
AWS Security Token Service (STS) is a service that issues temporary security credentials (access key, secret key, and session token) to users or roles that need to access AWS resources for a limited time.
Lab Setup and Prerequisites:
- An AWS Account
- VM Kali Linux
If you are new to AWS platform, it is recommended to go through the AWS Lab setup here,
Part 1: Vulnerable IAM Lab Setup
Here are the instructions for setting up the environment. We will access the AWS web console and configure the Command Line Interface (CLI) along with the creation of restricted access IAM user, high privileged IAM role and setting up an s3 bucket.
Provisioning a Low- Privileged IAM User
Firstly, In the AWS services search box, type “IAM” and select the IAM service that appears in the results.
Then, In the left navigation menu, click the Users link under the Access Management section.
Then, on the Users page, press Create user to create a new user.
Give the user a User name (e.g. lgt_lowpriv) and press Next.
Configure the lgt_lowpriv user’s permissions. On the Set permissions page, select Attach policies directly from the Permissions options.
Under Permission Policies, Select the policy name AmazonEC2FullAccess. The name of the policy must match this exactly
- AmazonEC2FullAccess – This policy will allow the user to have full access for EC2 and manage it (example read and write operation on EC2).
- Then, attach another policy AmazonS3ReadOnlyAccess – It allows our user to view S3 buckets and their contents, but explicitly prevents them from making changes or deleting anything.
“This limitation will be a key part of our privilege escalation demonstration”.
- IAMReadOnlyAccess – This permission will enable our user to inspect IAM configurations, which is often a critical step in discovering potential vulnerabilities.
Finally, click Next, then Create user.
Once completed, click on the newly created user and view its details.
Select “Create access key“. These access keys (an Access Key ID and a Secret Access Key) are essential for interacting with AWS programmatically using tools like the AWS Command Line Interface (CLI).
Then, Select “Command Line Interface (CLI)” as the use case.
Click “Create access key”.
Now download the .csv file containing the Access Key ID and Secret Access Key. Keep these credentials secure.
Provisioning a High Privileged IAM Role
Then, we’ll create a powerful IAM role. This role embodies the elevated permissions that our lgt_lowpriv user will temporarily gain during our demonstration.
Step 1: Navigate to IAM Roles
Back in the IAM dashboard, click “Roles” under “Access management”, then click “Create role“.
This is where you manage the “uniforms” that other entities can temporarily wear.
Step 2: Configure Role Details
For the “Trusted entity type,” select “AWS account”. This means we’re setting up this role to be assumed by an entity within an AWS account.
Choose “This account”. Click “Next”. This indicates that an entity within your current AWS account will be allowed to assume this role.
Permissions policies: Search and select “AdministratorAccess”.This policy grants comprehensive control over virtually all AWS services and resources, making it our “high-privileged” target for the lab.
Click “Next”.
Role name: Enter admin_role. Click “Create role”.
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::123456789012:root" }, "Action": "sts:AssumeRole" } ] }
Verify admin_role is created.
Step 3: Modify Role Trust Policy
Select admin_role from the roles list.
Go to the “Trust relationships” tab.
Click “Edit trust policy”
Modify the JSON policy to allow lgt_lowpriv to assume this role. Replace the “Principal” ARN with the ARN of your lgt_lowpriv user:
This is the core of our lab setup. By adding lgt_lowpriv to the Principal and allowing the sts:AssumeRole action, we’re explicitly granting our low-privileged user the ability to step into this powerful role.
Click “Update policy”.
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::123456789012:<Change for Trusted Username> " }, "Action": "sts:AssumeRole" } ] }
Setting up an S3 Bucket
To make our demonstration tangible, we’ll create an S3 bucket containing a “sensitive” file. Our lgt_lowpriv user initially won’t be able to fully control this bucket, but will gain that capability after assuming the admin_role.
Step 1: Create an S3 Bucket
Search “S3” in the AWS console and select “S3 – Scalable Storage in the Cloud”. S3 is AWS’s object storage service, perfect for holding our demonstration file.
Click “Create bucket”.
Bucket name: Enter a unique name, e.g., igt-bucket. Remember, S3 bucket names need to be globally unique across all AWS accounts.
For “Object Ownership,” ensure “ACLs disabled” is selected. This is the modern, recommended way to manage S3 permissions primarily through IAM policies.
Block Public Access settings for this bucket: Uncheck “Block all public access”. Acknowledge the warning. For this specific lab, we want to precisely control access through IAM policies, and this allows us that granular control. In a real environment, you’d typically keep public access blocked unless absolutely necessary.
Click “Create bucket”.
Verify igt-bucket is created
Step 2: Upload a File to the S3 Bucket
Select your igt-bucket. Click “Upload”.
Click “Add files” and upload a file named secrets.txt (or similar). This file will be our target to demonstrate the change in permissions
Click “Upload”.
Part 2: IAM Enumeration & Exploitation
How Could a User Gain Access to a High-Privilege IAM Role?
In real-world scenarios, privilege escalation often begins with access to a low-privileged user account. From there, the user may be able to escalate privileges if they are allowed to assume a more powerful IAM role. This can happen due to overly permissive policies or misconfigured trust relationships or IAM user secret got leaked over internet through GitHub or phishing.
Enumeration IAM Role with Enumerate-iam Python script- Method 1
Firstly, on your Kali Linux machine, open a terminal and clone the enumerate-iam tool: This tool is excellent for uncovering IAM-related permissions and potential escalation paths.
git clone https://github.com/andresriancho/enumerate-iam.git cd enumerate-iam
Then, create and activate a Python virtual environment: This isolates the project’s Python dependencies, keeping your system clean. Install requirements.
python3 -m venv iam source iam/bin/activate pip install -r requirements.txt
Then, Run the enumerate-iam.py script using the Access Key ID and Secret Access Key of low privileged IAM user lgt_lowpriv.
enumerate-iam.py
The output should show AmazonEC2FullAccess, IAMReadOnlyAccess, and AmazonS3ReadOnlyAccess.
The script output will also reveal IAM Role Details assigned to IAM user (Igt_lowpriv).
Since the output we can see IAM Role name is admin_role assigned to our compromised IAM user (Igt_lowpriv) that has the attached policy of Administrator Access.
Enumeration IAM Role with AWS CLI- Method 2
Install AWS CLI: The AWS Command Line Interface (AWS CLI) is an open source tool that enables you to interact with AWS services using commands in your command-line shell.
All IaaS (infrastructure as a service) AWS administration, management, and access functions in the AWS Management Console are available in the AWS API and AWS CLI.
apt install awscli
Configure AWS CLI profile with your low-privileged user’s credentials:
- Firstly, Enter Access Key ID and Secret Access Key.
- Then, Set Default region name (e.g., ap-south-1).
- Furthermore, Leave Default output format This step stores lgt_lowpriv’s credentials, allowing you to easily execute commands as this specific user.
aws --version aws configure --profile lgt_lowpriv
Verify the credentials are saved in ~/.aws/credentials.
cat credentials
List IAM roles: aws iam list-roles. You should see admin_role and its trust policy. Confirming it’s a potential target.
aws iam list-roles
List policies attached to admin_role: It should show AdministratorAccess.
aws iam list-attached-role-policies --role-name admin_role
Get the admin_role’s assume role policy document: This confirms lgt_lowpriv can assume admin_role.
aws iam get-role --role-name admin_role --query 'Role.AssumeRolePolicyDocument' --output text
List S3 buckets: You should see igt-bucket.
List content of igt-bucket: You should see secrets.txt.
Copy secrets.txt from S3. And view content.
Attempt to delete the file (should fail due to S3ReadOnlyAccess): You will get an “AccessDenied” error. This is a critical moment in our demonstration: despite being able to read the file, lgt_lowpriv cannot delete it, showcasing the “read-only” constraint.
aws s3 ls aws s3 ls s3://igt-bucket/ aws s3 cp s3://igt-bucket/secrets.txt out_secrets.txt cat out_secrets.txt aws s3 rm s3://igt-bucket/secrets.txt
This sets the stage for our privilege escalation.
IAM AssumeRole Privilege Escalation
Now for the key action: assume admin_role! Execute: This command is the “exploit” itself. It requests temporary credentials from the AWS Security Token Service (STS) for the admin_role.
The role-session-name is just a label for this specific session. Upon successful execution, AWS will provide a new set of Access Key ID, Secret Access Key, and a Session Token.
aws sts assume-role --role-arn arn:aws:iam::<YOUR_ACCOUNT_ID>:role/admin_role --role-session-name "ExploitSession”
Export the temporary credentials as environment variables:
export AWS_ACCESS_KEY_ID="<AccessKeyId from previous output>" export AWS_SECRET_ACCESS_KEY="<SecretAccessKey from previous output>" export AWS_SESSION_TOKEN="<SessionToken from previous output>"
This tells your AWS CLI to use these powerful temporary credentials for all subsequent commands.
Verify assumed identity: The ARN should now reflect the assumed role.
aws sts get-caller-identity
Then, Delete the S3 file (now successful with AdministratorAccess)
aws s3 rm s3: // igt-bucket/secrets.txt
Finally, verify the deletion by the following command and bucket should now be empty.
aws s3 ls s3: // igt-bucket/
Analysis
This lab demonstrates a classic IAM misconfiguration where a non-privileged user is allowed to assume a highly privileged role without sufficient restrictions. The escalation vector was:
lgt_lowpriv → assumes admin_role (via sts:AssumeRole) → trust policy allows it → STS issues temp. creds → admin_role has AdministratorAccess → user gains full admin privileges
Such misconfigurations can occur due to:
- Overly permissive trust policies
- Lack of condition checks (aws:MultiFactorAuthPresent, aws:SourceIp)
- Improper role separation
Recommendation
- Avoid allowing AssumeRole to roles with AdministratorAccess unless absolutely necessary.
- Use conditions in trust policies:
"Condition": { "Bool": { "aws:MultiFactorAuthPresent": "true" } }
- Use Resource-based policies and Service Control Policies (SCPs) in organizations.
- Audit AssumeRole usage via CloudTrail and Config Rules.
Conclusion
This lab successfully demonstrates a privilege escalation scenario in AWS using the sts:AssumeRole API and a misconfigured trust policy. It emphasizes the need for cautious IAM role delegation and strict privilege boundaries in cloud environments.
Author: Fatima Aziz is an accomplished cybersecurity professional with expertise in cloud security, holding certifications like CCSK, GIAC and GPCS. Contact Fatima Aziz on LinkedIn.