IAM Privilege-Escalation Lab
The grant that hands an attacker the account rarely looks dangerous on its own — it is one iam:PassRole next to a compute-create, a CreatePolicyVersion on a policy attached to you, an UpdateAssumeRolePolicy on a role you can then assume. Work a queue of cloud IAM grants, read each one against the account context, and decide: correctly scoped, or the start of a privilege-escalation chain — then pick the fix that breaks it (scope the PassRole, deny the policy-version write, condition the trust policy). You are scored on chains found against false positives, because flagging a correctly-scoped grant — a pinned PassRole, a read-only assume — is its own failure. Find the pivot, name it, close it.
The real job. More noise, a tighter clock.
IAM grant queue
Read each grant with its account context: call it safe, or name the escalation primitive — then pick the fix that breaks the chain.
#1
CI deployer — PassRole to Lambda
user/ci-deployer
account context
- ·Role lambda-exec-admin exists with AdministratorAccess attached.
- ·lambda-exec-admin’s trust policy allows lambda.amazonaws.com to assume it.
purpose: Deploy app Lambda functions from CI.
#2
App dev — write a new policy version
user/app-dev
account context
- ·AppDevPolicy is attached to user/app-dev (the caller) and defines their own permissions.
purpose: Let developers tweak their own scoped policy.
#3
Help desk — attach user policies
user/helpdesk
account context
- ·The AWS-managed AdministratorAccess policy is available in the account.
purpose: Attach standard job-function policies to onboard users.
#4
Reporting role — read S3 reports
role/reporting-reader
account context
- ·No iam:* actions. No sts:AssumeRole. No PassRole.
purpose: Read generated finance reports for a dashboard.
#5
Support — mint access keys
user/support
account context
- ·The user/* resource includes break-glass admin users.
purpose: Help users who have lost their access keys.
#6
Onboarding — add users to groups
user/onboarding
account context
- ·Group Administrators exists with AdministratorAccess attached to it.
purpose: Place new hires into their team groups.
#7
Deployer — scoped PassRole to ECS
user/deployer
account context
- ·app-runtime-role grants only s3:GetObject on one bucket — no IAM, no admin.
purpose: Register ECS task definitions that run as the app runtime role.
#8
Analyst — assume the billing-admin role
user/analyst
account context
- ·billing-admin holds full billing access plus iam:* .
- ·billing-admin’s trust policy Principal is arn:aws:iam::111122223333:root — any principal in the account may assume it.
purpose: Let an analyst pull billing data by assuming a shared role.
#9
Dev — set the default policy version
user/dev2
account context
- ·DevBoundary is attached to user/dev2.
- ·DevBoundary has 5 stored versions; v1 (not currently default) grants *:* .
purpose: Allow developers to roll their policy back to a previous version.
#10
Build role — put its own inline policy
role/build-role
account context
- ·build-role is assumed by CodeBuild and by the caller during builds.
purpose: Let the build role manage its own scoped inline permissions.
#11
Sec-ops — update an assume-role policy
user/sec-ops
account context
- ·org-admin has AdministratorAccess.
- ·org-admin’s trust currently allows only a specific CI role to assume it.
purpose: Maintain trust relationships for security automation.
#12
Lambda dev — create functions, no PassRole
user/lambda-dev
account context
- ·The caller has NO iam:PassRole on any role.
- ·Existing functions can only be invoked, not re-pointed at a new execution role.
purpose: Develop and test Lambda functions in a sandbox account.
#13
Infra — PassRole with RunInstances
user/infra
account context
- ·Instance profile ec2-admin-profile wraps a role with AdministratorAccess.
purpose: Launch EC2 instances with their standard instance profiles.
#14
IT admin — reset console passwords
user/it-admin
account context
- ·user/* includes a break-glass admin console user.
purpose: Reset console passwords for locked-out staff.
Pivots found vs. false positives
Call each grant, then grade. So far 0/14 called, 0/11 pivots identified, 0 false positive(s).
How it is scored
A pivot counts only when you name the exact primitive and pick the fix that breaks the chain.
A right primitive with the wrong fix is a light penalty; a false positive on a safe grant takes a bigger hygiene bite.
Harder tiers add subtler chains and deliberate traps: scoped PassRole, compute-create with no PassRole, read-only IAM, a scoped cross-account assume.
Live arena
4 activeadversary staging…
What this lab is
- A free, browser-based IAM privilege-escalation lab: work a queue of ~20 cloud IAM grants and, reading each one against the surrounding account facts, decide whether it is safe or forms an escalation chain.
- Pivots seeded across the queue are real, documented AWS IAM primitives: iam:PassRole into Lambda/EC2/CloudFormation, CreatePolicyVersion and SetDefaultPolicyVersion, attaching an admin managed policy, putting an inline admin policy, sts:AssumeRole into a higher-privilege role, UpdateAssumeRolePolicy trust rewrites, access-key / login-profile takeover, and AddUserToGroup.
- For every grant you flag as a pivot, you also pick the remediation that actually breaks the chain — scope PassRole, deny the policy-version write, tighten the target role’s trust, deny trust rewrites, and so on.
- You are graded on how many chains you find with the right primitive and the right fix, weighed against false positives — flagging a correctly-scoped grant takes an extra hygiene penalty.
- Difficulty tiers add subtler chains and deliberate traps: a correctly-scoped PassRole, compute-create with no PassRole, read-only IAM introspection, and a scoped cross-account assume into a read-only role.
Frequently asked questions
What is the IAM Privilege-Escalation Lab?
A free, in-browser exercise where you work a queue of cloud IAM grants — the actions, the resource, any condition, how the statement is attached, plus the surrounding account facts (which roles are admin, what a trust policy allows, which policy is attached to whom) — and decide whether each grant is correctly scoped or is a privilege-escalation pivot. When it is a pivot you also name the exact primitive (for example iam:PassRole to a privileged compute role, or iam:CreatePolicyVersion on a policy attached to yourself) and pick the remediation that breaks the chain. It focuses specifically on identity-based escalation, not generic cloud misconfiguration.
How is it graded?
Each grant has one correct verdict and, where it is a pivot, one remediation that actually breaks the chain. A pivot counts as caught only when you name the right primitive and choose the right fix. A correct identification with the wrong fix is a light penalty; a false positive — flagging a correctly-scoped grant — carries a bigger hygiene penalty, because a report that cries wolf on clean grants is as useless as one that misses real escalation. A perfect run calls every grant exactly right, safe ones included.
Does it touch a real AWS account?
No. Nothing connects to AWS and no real policies are read. The grants are authored, realistic field snapshots bundled with the page, with their surrounding account context written in, and every verdict is judged against a fixed ground truth so the queue is deterministic. It runs entirely in your browser — no account, no install, nothing sent anywhere.
Who is it for?
Cloud and platform engineers, security teams reviewing IAM, red and blue teamers, and anyone preparing for a cloud-security or infrastructure interview who wants to feel why an unscoped iam:PassRole beside a compute-create, a CreatePolicyVersion on your own attached policy, or an UpdateAssumeRolePolicy on a role you can then assume is a path to account admin — and why a PassRole pinned to one low-privilege role, or a cross-account assume into a read-only role, is not.