Prerequisites
- Target system, dependencies and environment configured.
Usage
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
- Establish what identity you're operating as and confirm scope:
aws sts get-caller-identity
- 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 <u>
aws iam get-user-policy --user-name <u> --policy-name <p>
# if IAM read is denied, probe what's allowed:
enumerate-iam --access-key ... --secret-key ...
- Map the escalation paths automatically — this is the part you don't do by eye at scale:
pmapper graph create
pmapper query "preset privesc <principal>"
- 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.
- 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
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
enumerate-iam --access-key AK --secret-key SK # what can these keys do?
pmapper graph create && pmapper query "preset privesc U" # escalation paths
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)
Inputs
- Relevant source code, logs, network traces, or system specifications.
Outputs
- Analysis findings, security audit report, or generated code artifacts.
1---2name: iam-privilege-escalation3description: 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.4---5678## Prerequisites9- Target system, dependencies and environment configured.1011## Usage12### Purpose1314In 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.1516Scoped to AWS here because it's the most common; the reasoning (find a permission that grants more permissions) transfers to Azure and GCP.1718### When to use it1920Authorised cloud assessments, or auditing your own account for latent escalation paths. Assume-breach reviews especially: "if this CI role leaked, could it become admin?"2122Only against accounts you own or are authorised to test. Enumerating IAM on someone else's account is unauthorised access.2324### Procedure25261. Establish what identity you're operating as and confirm scope:27 ```28 aws sts get-caller-identity29 ```302. Enumerate the permissions attached to the identity. If you can read IAM, list the policies directly; if not, brute-force which API calls succeed:31 ```32 aws iam list-attached-user-policies --user-name <u>33 aws iam get-user-policy --user-name <u> --policy-name <p>34 # if IAM read is denied, probe what's allowed:35 enumerate-iam --access-key ... --secret-key ...36 ```373. Map the escalation paths automatically — this is the part you don't do by eye at scale:38 ```39 pmapper graph create40 pmapper query "preset privesc <principal>"41 ```424. Reason about the high-signal permission combinations by hand as a cross-check. Classic AWS paths include:43 - `iam:CreatePolicyVersion` — rewrite a policy you're attached to, granting yourself `*`.44 - `iam:PassRole` + `lambda:CreateFunction`/`ec2:RunInstances` — run code as a more privileged role.45 - `iam:AttachUserPolicy` — attach `AdministratorAccess` to yourself.46 - `iam:CreateAccessKey` on another user — mint credentials for a bigger identity.47 - `sts:AssumeRole` on an over-trusting role.485. 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.4950### Cheatsheet5152```bash53aws sts get-caller-identity54aws iam list-attached-user-policies --user-name U55aws iam list-user-policies --user-name U56aws iam get-policy-version --policy-arn ARN --version-id v15758enumerate-iam --access-key AK --secret-key SK # what can these keys do?59pmapper graph create && pmapper query "preset privesc U" # escalation paths6061iam:CreatePolicyVersion iam:SetDefaultPolicyVersion62iam:AttachUserPolicy iam:AttachRolePolicy iam:PutUserPolicy63iam:PassRole iam:CreateAccessKey sts:AssumeRole64iam:UpdateAssumeRolePolicy lambda:CreateFunction ec2:RunInstances65```6667### Reading the output6869- **`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.70- **A wildcard `Action: "*"` or `iam:*`** on a non-admin principal is an obvious over-grant.71- **`iam:PassRole` with `Resource: "*"`** is a red flag — it lets the identity hand *any* role to a service it can invoke.72- **A role trust policy with a broad `Principal`** (a whole account, or `*`) means anyone in that scope can assume it.7374### The fix7576Least privilege, and remove the permissions that grant permissions:7778- Strip wildcard actions and resources. Grant the specific API calls a role needs, scoped to specific ARNs.79- Constrain `iam:PassRole` to the exact roles a service legitimately needs, never `Resource: "*"`.80- 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.81- Tighten role trust policies to specific principals with conditions (`aws:SourceArn`, external ID).82- Alert on the escalation-enabling calls in CloudTrail so an attempt is visible.8384### Pitfalls8586- **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.87- **Leaving admin access behind after a test.** If you demonstrate a path, revert it. Document instead of persist.88- **Chasing single permissions.** Escalation usually needs a *combination*; that's why graph tooling beats eyeballing.89- **Ignoring roles you can assume.** The path often runs through `AssumeRole` into a more privileged identity, not a direct policy edit.9091### References9293- AWS IAM best practices documentation94- Principal Mapper (pmapper) documentation95- Rhino Security Labs — AWS IAM privilege escalation methods96- CWE-269 (Improper Privilege Management)9798## Inputs99- Relevant source code, logs, network traces, or system specifications.100101## Outputs102- Analysis findings, security audit report, or generated code artifacts.