---
name: iam-privilege-escalation
domain: 06-cloud-security
description: Use when you have limited cloud credentials and need to check whether IAM misconfigurations let you reach higher privileges — mapping escalation paths and closing them.
difficulty: advanced
tags: [cloud, aws, iam, privilege-escalation, misconfiguration]
tools: [aws-cli, pmapper, enumerate-iam]
---
## Purpose
In the cloud, privilege escalation is rarely an exploit — it's a policy that grants one permission too many. `iam:PassRole` plus `lambda:CreateFunction`, or `iam:CreatePolicyVersion` on your own role, and a read-only identity becomes admin. This skill covers enumerating what a set of credentials can do and finding the path up, then removing it.
Scoped to AWS here because it's the most common; the reasoning (find a permission that grants more permissions) transfers to Azure and GCP.
## When to use it
Authorised cloud assessments, or auditing your own account for latent escalation paths. Assume-breach reviews especially: "if this CI role leaked, could it become admin?"
Only against accounts you own or are authorised to test. Enumerating IAM on someone else's account is unauthorised access.
## Procedure
1. Establish what identity you're operating as and confirm scope:
```
aws sts get-caller-identity
```
2. Enumerate the permissions attached to the identity. If you can read IAM, list the policies directly; if not, brute-force which API calls succeed:
```
aws iam list-attached-user-policies --user-name
aws iam get-user-policy --user-name --policy-name
# if IAM read is denied, probe what's allowed:
enumerate-iam --access-key ... --secret-key ...
```
3. Map the escalation paths automatically — this is the part you don't do by eye at scale:
```
pmapper graph create
pmapper query "preset privesc "
```
4. Reason about the high-signal permission combinations by hand as a cross-check. Classic AWS paths include:
- `iam:CreatePolicyVersion` — rewrite a policy you're attached to, granting yourself `*`.
- `iam:PassRole` + `lambda:CreateFunction`/`ec2:RunInstances` — run code as a more privileged role.
- `iam:AttachUserPolicy` — attach `AdministratorAccess` to yourself.
- `iam:CreateAccessKey` on another user — mint credentials for a bigger identity.
- `sts:AssumeRole` on an over-trusting role.
5. Validate a path carefully in an authorised test — demonstrate reachability (e.g. that `PassRole` accepts an admin role) without actually leaving persistent admin access behind. Clean up anything you create.
## Cheatsheet
```bash
aws sts get-caller-identity
aws iam list-attached-user-policies --user-name U
aws iam list-user-policies --user-name U
aws iam get-policy-version --policy-arn ARN --version-id v1
# automated
enumerate-iam --access-key AK --secret-key SK # what can these keys do?
pmapper graph create && pmapper query "preset privesc U" # escalation paths
# high-signal permissions to grep for in policies
iam:CreatePolicyVersion iam:SetDefaultPolicyVersion
iam:AttachUserPolicy iam:AttachRolePolicy iam:PutUserPolicy
iam:PassRole iam:CreateAccessKey sts:AssumeRole
iam:UpdateAssumeRolePolicy lambda:CreateFunction ec2:RunInstances
```
## Reading the output
- **`pmapper` returning a path to an admin node** is your finding, with the exact edges (which permission enables which hop) — that's what goes in the report.
- **A wildcard `Action: "*"` or `iam:*`** on a non-admin principal is an obvious over-grant.
- **`iam:PassRole` with `Resource: "*"`** is a red flag — it lets the identity hand *any* role to a service it can invoke.
- **A role trust policy with a broad `Principal`** (a whole account, or `*`) means anyone in that scope can assume it.
## The fix
Least privilege, and remove the permissions that grant permissions:
- Strip wildcard actions and resources. Grant the specific API calls a role needs, scoped to specific ARNs.
- Constrain `iam:PassRole` to the exact roles a service legitimately needs, never `Resource: "*"`.
- Keep the permission-granting IAM actions (`Create*Policy*`, `Attach*Policy`, `PutUserPolicy`, `CreateAccessKey`, `UpdateAssumeRolePolicy`) inside a small, monitored admin boundary — use **permission boundaries** and SCPs to cap what any principal can reach even if its policy says otherwise.
- Tighten role trust policies to specific principals with conditions (`aws:SourceArn`, external ID).
- Alert on the escalation-enabling calls in CloudTrail so an attempt is visible.
## Pitfalls
- **Reading policies without evaluating boundaries.** An allow can be capped by a permission boundary or SCP — check the effective permissions, not just the attached policy.
- **Leaving admin access behind after a test.** If you demonstrate a path, revert it. Document instead of persist.
- **Chasing single permissions.** Escalation usually needs a *combination*; that's why graph tooling beats eyeballing.
- **Ignoring roles you can assume.** The path often runs through `AssumeRole` into a more privileged identity, not a direct policy edit.
## References
- AWS IAM best practices documentation
- Principal Mapper (pmapper) documentation
- Rhino Security Labs — AWS IAM privilege escalation methods
- CWE-269 (Improper Privilege Management)