npx skills add mukul975/Anthropic-Cybersecurity-SkillsMITRE ATT&CK
When to Use
- When conducting authorized penetration testing of AWS IAM configurations
- When validating that IAM policies follow the principle of least privilege
- When assessing the blast radius of a compromised AWS credential
- When building security reviews for IAM role and policy changes in CI/CD pipelines
- When evaluating cross-account trust relationships for privilege escalation risks
Do not use for unauthorized testing against AWS accounts, for assessing non-IAM attack vectors (SSRF, application vulnerabilities), or as a substitute for comprehensive cloud penetration testing. Always obtain written authorization before testing.
Prerequisites
- Written authorization for privilege escalation testing in the target AWS account
- Test IAM user or role with limited permissions as the starting point
- Pacu installed (
pip install pacu) - CloudFox installed (
go install github.com/BishopFox/cloudfox@latest) - PMapper (Principal Mapper) installed (
pip install principalmapper) - AWS CLI configured with test credentials and CloudTrail logging enabled for audit trail
Workflow
Step 1: Enumerate Starting Permissions
Establish the baseline permissions of the test principal before attempting escalation.
# Get current identity
aws sts get-caller-identity
# Enumerate inline and attached policies for the current user
aws iam list-user-policies --user-name test-user
aws iam list-attached-user-policies --user-name test-user
# Get group memberships and group policies
aws iam list-groups-for-user --user-name test-user
for group in $(aws iam list-groups-for-user --user-name test-user --query 'Groups[*].GroupName' --output text); do
echo "=== Group: $group ==="
aws iam list-group-policies --group-name "$group"
aws iam list-attached-group-policies --group-name "$group"
done
# Simulate specific API calls to map effective permissions
aws iam simulate-principal-policy \
--policy-source-arn arn:aws:iam::ACCOUNT:user/test-user \
--action-names iam:CreateUser iam:AttachUserPolicy iam:PassRole \
lambda:CreateFunction ec2:RunInstances sts:AssumeRole \
--query 'EvaluationResults[*].[EvalActionName,EvalDecision]' --output tableStep 2: Scan for Privilege Escalation Paths with Pacu
Use Pacu's privilege escalation scanner to identify known IAM escalation techniques.
# Start Pacu session
pacu
# Create session and set credentials
Pacu (new:session) > set_keys --key-alias privesc-test
# Enumerate IAM configuration
Pacu > run iam__enum_users_roles_policies_groups
Pacu > run iam__enum_permissions
# Run privilege escalation scanner
Pacu > run iam__privesc_scan
# The scanner checks for 21+ known escalation methods including:
# - iam:CreatePolicyVersion (create admin policy version)
# - iam:SetDefaultPolicyVersion (revert to permissive older version)
# - iam:AttachUserPolicy / iam:AttachRolePolicy (attach admin policy)
# - iam:PutUserPolicy / iam:PutRolePolicy (create inline admin policy)
# - iam:PassRole + lambda:CreateFunction (Lambda with admin role)
# - iam:PassRole + ec2:RunInstances (EC2 with admin instance profile)
# - iam:CreateLoginProfile / iam:UpdateLoginProfile (set console password)
# - iam:CreateAccessKey (create keys for other users)
# - sts:AssumeRole (assume more privileged roles)
# - glue:CreateDevEndpoint + iam:PassRole (Glue with admin role)Step 3: Map Privilege Escalation Graphs with PMapper
Use Principal Mapper to build a graph of all IAM principals and identify escalation edges.
# Collect IAM data for graph construction
pmapper graph create --account ACCOUNT_ID
# Query for paths to admin
pmapper query 'who can do iam:AttachUserPolicy with * on *'
pmapper query 'who can do sts:AssumeRole with arn:aws:iam::ACCOUNT:role/AdminRole'
# Find all principals that can escalate to admin
pmapper analysis
# Visualize the privilege escalation graph
pmapper visualize --filetype png
# Check specific escalation paths
pmapper query 'can arn:aws:iam::ACCOUNT:user/test-user do iam:CreatePolicyVersion with *'
pmapper query 'can arn:aws:iam::ACCOUNT:user/test-user do sts:AssumeRole with arn:aws:iam::ACCOUNT:role/*'Step 4: Test Cross-Account Role Assumption
Evaluate cross-account trust policies for misconfigured role assumptions that allow unauthorized escalation.
# List all roles and their trust policies
aws iam list-roles --query 'Roles[*].[RoleName,Arn]' --output text | while read name arn; do
trust=$(aws iam get-role --role-name "$name" --query 'Role.AssumeRolePolicyDocument' --output json 2>/dev/null)
# Check for wildcards or broad trust
echo "$trust" | python3 -c "
import json, sys
doc = json.load(sys.stdin)
for stmt in doc.get('Statement', []):
principal = stmt.get('Principal', {})
condition = stmt.get('Condition', {})
if isinstance(principal, dict):
aws_princ = principal.get('AWS', '')
else:
aws_princ = principal
if '*' in str(aws_princ) or 'root' in str(aws_princ):
has_external_id = 'sts:ExternalId' in str(condition)
has_mfa = 'aws:MultiFactorAuthPresent' in str(condition)
print(f'ROLE: $name')
print(f' Principal: {aws_princ}')
print(f' ExternalId required: {has_external_id}')
print(f' MFA required: {has_mfa}')
if not has_external_id and not has_mfa:
print(f' WARNING: No ExternalId or MFA condition - confused deputy risk')
" 2>/dev/null
done
# Test role assumption
aws sts assume-role \
--role-arn arn:aws:iam::TARGET_ACCOUNT:role/CrossAccountRole \
--role-session-name privesc-test \
--duration-seconds 900Step 5: Enumerate CloudFox Attack Paths
Use CloudFox to identify additional attack surfaces including resource-based policies and service-specific escalation paths.
# Run all CloudFox checks
cloudfox aws --profile target-account all-checks -o ./cloudfox-output/
# Specific privilege escalation checks
cloudfox aws --profile target-account permissions
cloudfox aws --profile target-account role-trusts
cloudfox aws --profile target-account access-keys
cloudfox aws --profile target-account env-vars # Lambda environment variables with secrets
cloudfox aws --profile target-account instances # EC2 with instance profiles
cloudfox aws --profile target-account endpoints # Exposed servicesStep 6: Document Findings and Remediation
Compile all discovered escalation paths with proof-of-concept steps and remediation recommendations.
# Generate a consolidated report
cat > privesc-report.md << 'EOF'
# AWS Privilege Escalation Assessment Report
## Tested Escalation Vectors
| Vector | Status | Starting Principal | Escalated To | Risk |
|--------|--------|--------------------|--------------|------|
| iam:CreatePolicyVersion | EXPLOITABLE | test-user | AdministratorAccess | Critical |
| iam:PassRole + lambda:CreateFunction | EXPLOITABLE | dev-role | LambdaAdminRole | Critical |
| sts:AssumeRole (cross-account) | EXPLOITABLE | test-user | ProdAdminRole | High |
| iam:AttachUserPolicy | BLOCKED | test-user | N/A | N/A |
| ec2:RunInstances + iam:PassRole | BLOCKED | test-user | N/A | N/A |
## Remediation
1. Apply permission boundaries to all IAM users and roles
2. Remove iam:CreatePolicyVersion from non-admin principals
3. Add sts:ExternalId condition to all cross-account role trust policies
4. Implement SCP guardrails preventing privilege escalation actions
EOFKey Concepts
| Term | Definition |
|---|---|
| IAM Privilege Escalation | Exploiting overly permissive IAM policies to gain higher-level access than originally granted to a principal |
| Permission Boundary | IAM policy that sets the maximum permissions a principal can have, regardless of identity-based policies attached to it |
| iam:PassRole | IAM action allowing a principal to pass an IAM role to an AWS service, enabling the service to act with that role's permissions |
| Confused Deputy | Attack where an attacker tricks a trusted service into performing actions on their behalf using cross-account role assumption without external ID validation |
| Service Control Policy | AWS Organizations policy that sets maximum permissions for member accounts, providing guardrails against privilege escalation |
| Principal Mapper | Open-source tool that models IAM principals and their escalation paths as a directed graph for analysis |
Tools & Systems
- Pacu: AWS exploitation framework with 21+ privilege escalation modules for automated detection and exploitation
- Principal Mapper: Graph-based IAM analysis tool that maps escalation paths between principals
- CloudFox: AWS enumeration tool focused on identifying attack paths from an attacker's perspective
- IAM Policy Simulator: AWS-native tool for testing effective permissions against specific API actions
- AWS Access Analyzer: Service that identifies resource policies granting external access and validates IAM policy changes
Common Scenarios
Scenario: Developer Role with iam:CreatePolicyVersion Leads to Admin Access
Context: During an authorized assessment, a tester discovers that a developer role has the iam:CreatePolicyVersion permission, which allows creating a new version of any customer-managed policy with arbitrary permissions.
Approach:
- Enumerate policies attached to the developer role using
iam__enum_permissionsin Pacu - Identify that the role can call
iam:CreatePolicyVersionon its own attached policy - Create a new policy version with
"Action": "*", "Resource": "*", "Effect": "Allow" - Set the new version as the default policy version
- Verify admin access by calling
iam:ListUsers,s3:ListBuckets, etc. - Document the escalation chain and recommend removing
iam:CreatePolicyVersionand implementing permission boundaries
Pitfalls: AWS limits managed policies to 5 versions. If all 5 exist, you must delete a version before creating a new one. Always record the original default version to restore it during cleanup. Permission boundaries prevent this escalation if properly configured, so verify boundary policies before declaring a finding.
Output Format
AWS Privilege Escalation Assessment Report
=============================================
Account: 123456789012 (Production)
Assessment Date: 2026-02-23
Starting Principal: arn:aws:iam::123456789012:user/test-user
Starting Permissions: S3 read-only, Lambda invoke, EC2 describe
Authorization: Signed by CISO, engagement #PT-2026-014
ESCALATION PATHS DISCOVERED: 4
[PRIVESC-001] iam:CreatePolicyVersion -> Admin
Severity: CRITICAL
Starting Permission: iam:CreatePolicyVersion on policy/dev-policy
Escalation: Created policy version 6 with Action:* Resource:*
Time to Exploit: < 2 minutes
Remediation: Remove iam:CreatePolicyVersion, apply permission boundary
[PRIVESC-002] iam:PassRole + lambda:CreateFunction -> LambdaAdminRole
Severity: CRITICAL
Starting Permission: iam:PassRole, lambda:CreateFunction
Escalation: Created Lambda function with AdminRole, invoked to get admin credentials
Time to Exploit: < 5 minutes
Remediation: Restrict iam:PassRole to specific role ARNs with condition key
[PRIVESC-003] sts:AssumeRole -> Cross-Account Admin
Severity: HIGH
Starting Permission: sts:AssumeRole on arn:aws:iam::987654321098:role/SharedRole
Escalation: Role trust policy allows any principal in source account
Remediation: Add sts:ExternalId condition and restrict Principal to specific roles
TOTAL ESCALATION PATHS: 4 (2 Critical, 1 High, 1 Medium)
PERMISSION BOUNDARIES IN PLACE: 0 / 47 IAM principals
SCP GUARDRAILS BLOCKING ESCALATION: 0 / 3 tested vectorsReferences and resources
Everything below is rendered for inspection. Script files are read-only and never run.
References 1
api-reference.md2.6 KB
API Reference: Performing AWS Privilege Escalation Assessment
AWS IAM API (boto3)
| Method | Description |
|---|---|
iam.list_users() |
Enumerate all IAM users |
iam.list_attached_user_policies(UserName) |
List managed policies attached to user |
iam.list_user_policies(UserName) |
List inline policies on a user |
iam.get_policy_version(PolicyArn, VersionId) |
Get policy document for analysis |
iam.list_roles() |
Enumerate all IAM roles |
iam.list_attached_role_policies(RoleName) |
List managed policies on a role |
iam.list_groups_for_user(UserName) |
List group memberships for a user |
iam.simulate_principal_policy(PolicySourceArn, ActionNames) |
Test permissions |
AWS STS API
| Method | Description |
|---|---|
sts.get_caller_identity() |
Identify current principal (user/role/account) |
sts.assume_role(RoleArn, RoleSessionName) |
Assume a role for privilege escalation test |
Pacu Modules (CLI)
| Module | Description |
|---|---|
iam__enum_users_roles_policies_groups |
Full IAM enumeration |
iam__privesc_scan |
Scan for 21+ privilege escalation vectors |
iam__backdoor_users_keys |
Test access key creation ability |
lambda__backdoor_new_roles |
Test Lambda-based escalation |
Key Libraries
- boto3 (
pip install boto3): AWS SDK for IAM, STS, and service enumeration - pacu (
pip install pacu): AWS exploitation framework (CLI-based) - pmapper (Principal Mapper): Graph-based IAM privilege analysis
- cloudfox: Cloud penetration testing tool for AWS enumeration
Dangerous IAM Actions
| Action | Escalation Vector |
|---|---|
iam:CreatePolicyVersion |
Create new policy version with admin permissions |
iam:AttachUserPolicy |
Attach AdministratorAccess to self |
iam:PassRole + lambda:CreateFunction |
Create Lambda with privileged role |
iam:PutUserPolicy |
Add inline admin policy to self |
sts:AssumeRole |
Assume more-privileged role |
iam:UpdateAssumeRolePolicy |
Modify role trust to allow self-assumption |
Configuration
| Variable | Description |
|---|---|
AWS_PROFILE |
AWS CLI profile with test credentials |
AWS_DEFAULT_REGION |
Default AWS region for API calls |
References
Scripts 1
agent.py7.5 KB
#!/usr/bin/env python3
"""
AWS Privilege Escalation Assessment Agent — AUTHORIZED TESTING ONLY
Assesses AWS IAM configurations for privilege escalation paths using boto3
and enumerates dangerous policy combinations.
WARNING: Only use with explicit written authorization on approved AWS accounts.
"""
import json
from datetime import datetime, timezone
import boto3
from botocore.exceptions import ClientError
def get_caller_identity() -> dict:
"""Get current AWS identity information."""
sts = boto3.client("sts")
identity = sts.get_caller_identity()
return {
"account": identity["Account"],
"arn": identity["Arn"],
"user_id": identity["UserId"],
}
def enumerate_iam_users() -> list[dict]:
"""Enumerate all IAM users and their attached policies."""
iam = boto3.client("iam")
users = []
paginator = iam.get_paginator("list_users")
for page in paginator.paginate():
for user in page["Users"]:
username = user["UserName"]
attached = iam.list_attached_user_policies(UserName=username)
inline = iam.list_user_policies(UserName=username)
groups = iam.list_groups_for_user(UserName=username)
users.append({
"username": username,
"arn": user["Arn"],
"attached_policies": [p["PolicyArn"] for p in attached["AttachedPolicies"]],
"inline_policies": inline["PolicyNames"],
"groups": [g["GroupName"] for g in groups["Groups"]],
"has_console": user.get("PasswordLastUsed") is not None,
})
return users
def enumerate_iam_roles() -> list[dict]:
"""Enumerate IAM roles and their trust policies."""
iam = boto3.client("iam")
roles = []
paginator = iam.get_paginator("list_roles")
for page in paginator.paginate():
for role in page["Roles"]:
trust = role.get("AssumeRolePolicyDocument", {})
attached = iam.list_attached_role_policies(RoleName=role["RoleName"])
roles.append({
"role_name": role["RoleName"],
"arn": role["Arn"],
"trust_policy": trust,
"attached_policies": [p["PolicyArn"] for p in attached["AttachedPolicies"]],
})
return roles
def check_dangerous_permissions(users: list[dict]) -> list[dict]:
"""Identify users with dangerous permission combinations for privilege escalation."""
iam = boto3.client("iam")
escalation_paths = []
dangerous_actions = [
"iam:CreatePolicyVersion", "iam:SetDefaultPolicyVersion",
"iam:PassRole", "iam:CreateRole", "iam:AttachUserPolicy",
"iam:AttachRolePolicy", "iam:PutUserPolicy", "iam:PutRolePolicy",
"iam:AddUserToGroup", "iam:UpdateAssumeRolePolicy",
"sts:AssumeRole", "lambda:CreateFunction", "lambda:InvokeFunction",
"lambda:UpdateFunctionCode", "ec2:RunInstances",
"cloudformation:CreateStack", "glue:CreateDevEndpoint",
"datapipeline:CreatePipeline", "ssm:SendCommand",
]
for user in users:
user_dangerous = []
for policy_arn in user["attached_policies"]:
try:
policy = iam.get_policy(PolicyArn=policy_arn)
version_id = policy["Policy"]["DefaultVersionId"]
version = iam.get_policy_version(PolicyArn=policy_arn, VersionId=version_id)
statements = version["PolicyVersion"]["Document"].get("Statement", [])
for stmt in statements:
if stmt.get("Effect") != "Allow":
continue
actions = stmt.get("Action", [])
if isinstance(actions, str):
actions = [actions]
for action in actions:
if action == "*" or action in dangerous_actions:
user_dangerous.append({
"policy": policy_arn,
"action": action,
"resource": stmt.get("Resource", "*"),
})
except ClientError:
continue
if user_dangerous:
escalation_paths.append({
"username": user["username"],
"dangerous_permissions": user_dangerous,
"escalation_risk": "HIGH" if any(
d["action"] == "*" for d in user_dangerous
) else "MEDIUM",
})
return escalation_paths
def check_role_chaining(roles: list[dict], account_id: str) -> list[dict]:
"""Identify role chaining opportunities for privilege escalation."""
chains = []
for role in roles:
trust = role.get("trust_policy", {})
for statement in trust.get("Statement", []):
if statement.get("Effect") != "Allow":
continue
principal = statement.get("Principal", {})
aws_principal = principal.get("AWS", [])
if isinstance(aws_principal, str):
aws_principal = [aws_principal]
for p in aws_principal:
if p == f"arn:aws:iam::{account_id}:root" or p == "*":
chains.append({
"role": role["role_name"],
"trust_principal": p,
"risk": "HIGH" if p == "*" else "MEDIUM",
"policies": role["attached_policies"],
})
return chains
def generate_report(identity: dict, users: list, escalation: list, chains: list) -> str:
"""Generate privilege escalation assessment report."""
lines = [
"AWS PRIVILEGE ESCALATION ASSESSMENT — AUTHORIZED TESTING ONLY",
"=" * 65,
f"Account: {identity['account']}",
f"Assessed As: {identity['arn']}",
f"Date: {datetime.now(timezone.utc).strftime('%Y-%m-%d %H:%M UTC')}",
"",
f"IAM Users Enumerated: {len(users)}",
f"Escalation Paths Found: {len(escalation)}",
f"Role Chaining Risks: {len(chains)}",
"",
"PRIVILEGE ESCALATION PATHS:",
"-" * 40,
]
for path in escalation:
lines.append(f" [{path['escalation_risk']}] {path['username']}")
for perm in path["dangerous_permissions"][:5]:
lines.append(f" - {perm['action']} on {perm['resource']}")
if chains:
lines.extend(["", "ROLE CHAINING RISKS:", "-" * 40])
for chain in chains:
lines.append(f" [{chain['risk']}] {chain['role']} trusts {chain['trust_principal']}")
return "\n".join(lines)
if __name__ == "__main__":
print("[!] AWS PRIVILEGE ESCALATION ASSESSMENT — AUTHORIZED TESTING ONLY\n")
identity = get_caller_identity()
print(f"[*] Account: {identity['account']}, Identity: {identity['arn']}")
users = enumerate_iam_users()
print(f"[*] Enumerated {len(users)} IAM users")
roles = enumerate_iam_roles()
print(f"[*] Enumerated {len(roles)} IAM roles")
escalation = check_dangerous_permissions(users)
chains = check_role_chaining(roles, identity["account"])
report = generate_report(identity, users, escalation, chains)
print(report)
output = f"aws_privesc_{identity['account']}_{datetime.now(timezone.utc).strftime('%Y%m%d')}.json"
with open(output, "w") as f:
json.dump({"identity": identity, "users": users, "escalation_paths": escalation,
"role_chains": chains}, f, indent=2, default=str)
print(f"\n[*] Results saved to {output}")