Exploit AWS IAM Privilege Escalation

Simulate a compromised credential and escalate to full AWS admin using Pacu.

Introduction

30 Second Summary

Every security breach has a moment where an attacker with limited access finds a way to become an administrator. Understanding how these escalation paths work is what separates defenders who write effective detection rules from those who miss critical alerts.

In this project, you will simulate a real-world AWS privilege escalation attack from start to finish. You will build a vulnerable IAM environment, exploit it using an industry-standard red team framework, and then analyze the attack from a defender's perspective.

What You'll Build

A hands-on AWS red team lab where you compromise a low-privilege IAM credential and escalate to full admin access using Pacu, the open-source AWS exploitation framework.

By the end of this project, you'll have:

  • A deliberately vulnerable IAM user with a CreatePolicyVersion privilege escalation path ready to exploit.
  • A Pacu session showing automated enumeration results and discovered escalation vectors.
  • A successfully exploited escalation from limited S3-read permissions to full AdministratorAccess, with CloudTrail evidence analyzed from the blue team's perspective.
  • Secret Mission: Chain a second escalation path (AttachUserPolicy) and compare detection signatures across both attack methods.

Are there any prerequisites?

You will need an AWS account with admin-level access (a dedicated practice or lab account, not production). You should also be comfortable with basic Linux command-line navigation and understand what IAM access keys and policies are at a high level.

Set Up Your Attack Environment

Every red team engagement starts with the same question: what can this compromised credential actually do? To answer that systematically, you need an exploitation framework in an isolated environment.

In this step, you will install Pacu, the industry-standard AWS exploitation framework, inside a Python virtual environment. You will also verify that your AWS CLI admin credentials are working before building the vulnerable lab.

In this step, get ready to:
  • Install Pacu in an isolated Python virtual environment.
  • Verify your AWS admin credentials are active and correctly configured.
  • Create a working directory for policy documents you will use in the next steps.
Create a Python virtual environment and install Pacu

Pacu depends on the Python awscli package (version 1), which can conflict with a system-level AWS CLI v2 installation. Installing Pacu inside a virtual environment keeps it completely isolated from your system tools.

  • Create the lab directory and set up a virtual environment inside it by running these commands:
cd ~
mkdir pacu-lab && cd pacu-lab
python3 -m venv venv
source venv/bin/activate

What do these commands do?

  • cd ~ moves you to your home directory so the lab folder has a consistent location.
  • mkdir pacu-lab && cd pacu-lab creates the main lab directory and moves into it.
  • python3 -m venv venv creates a self-contained Python environment in a folder called venv.
  • source venv/bin/activate activates the environment so all packages you install stay isolated here.
  • Check your terminal prompt. You should see (venv) at the beginning, confirming the virtual environment is active.

Don't see (venv) in your prompt?

Make sure you typed source venv/bin/activate exactly. If you are using a shell other than bash (like zsh or fish), the activate script path may differ. For zsh, the same command works. For fish, use source venv/bin/activate.fish instead.

help me activate my Python virtual environment

  • Install Pacu by running this command:
pip install -U pacu
  • Verify Pacu installed correctly by running:
pacu --help
  • You should see Pacu's help output listing available CLI arguments. This confirms version 1.7.0 is installed and ready to use.

Seeing a build error during pip install?

Pacu's jq dependency may fail to compile if your system is missing C/C++ compilers. Install them and retry:

sudo apt install gcc g++
pip install -U pacu

help me fix a pip install build error for Pacu

Why a virtual environment?

Pacu installs the Python awscli package (AWS CLI version 1) as a dependency. Without isolation, this would overwrite your system's AWS CLI v2 binary.

The virtual environment keeps Pacu's dependencies contained. Your system aws command remains untouched outside the venv.

Verify your AWS CLI is configured and working

Before building the vulnerable lab, you need to confirm your admin credentials are active. The aws sts get-caller-identity command returns the account and IAM user associated with your configured credentials.

  • Confirm your admin credentials are active by running this command:
aws sts get-caller-identity

What should I see?

You should see JSON output with three fields: UserId, Account, and Arn.

The Arn field should contain arn:aws:iam::<account-id>:user/<your-username>. If you see :root in the ARN instead of :user/, you are signed in as the root account. Create a separate IAM admin user before continuing.

  • Confirm the Arn field shows :user/ (not :root). This proves you are operating as an IAM user with admin privileges.

Seeing 'Unable to locate credentials'?

This means no AWS credentials are configured. Run aws configure and enter your admin IAM user's Access Key ID and Secret Access Key. Set the default region to your preferred region (for example, us-east-1).

help me configure my AWS CLI credentials

Create a working directory for lab policy files

In the next steps, you will write JSON policy documents that define the permissions for your vulnerable test user. A dedicated directory keeps these files organized and easy to reference.

  • Create the policies directory by running this command:
mkdir policies
  • Confirm the directory was created by running:
ls
  • You should see both policies and venv listed in the output.

Your attack environment is ready. Next up, you will build the deliberately vulnerable IAM user that gives Pacu something to exploit.

Build the Vulnerable IAM Environment

Your attack environment is ready with Pacu installed and your admin credentials confirmed. Now you need a target to attack.

In a real engagement, you would start with a compromised credential found through phishing, leaked repos, or metadata services. For this lab, you will build that target yourself: an IAM user with a subtle misconfiguration that opens the door to full admin access.

In this step, get ready to:
  • Create a customer managed IAM policy with a hidden privilege escalation path.
  • Create a test IAM user and attach the vulnerable policy.
  • Configure a dedicated AWS CLI profile for the test user's credentials.
Create a customer managed policy with limited permissions

The policy you are about to write looks harmless at first glance. It grants read-only S3 access plus one extra permission: iam:CreatePolicyVersion.

That single permission is the vulnerability. A user who can create a new version of their own attached policy can rewrite it to grant themselves anything.

  • Create the policy JSON file inside your policies folder by running this command:
cat > policies/vulnerable-policy.json << 'EOF'
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:List*",
        "s3:Get*",
        "iam:CreatePolicyVersion"
      ],
      "Resource": "*"
    }
  ]
}
EOF

What does this policy grant?

  • s3:List* and s3:Get* allow the user to browse and download S3 objects. This is the "cover story" that makes the policy look normal.
  • iam:CreatePolicyVersion lets the user push a new version of any customer managed policy. If the user's own policy is customer managed, they can rewrite it to grant Action: * on Resource: *.
  • Resource: "*" means these permissions apply across the entire account.
  • Confirm the file was created by running:
cat policies/vulnerable-policy.json

You should see the full JSON policy document printed in your terminal.

Seeing "No such file or directory"?

  • Make sure you are inside the ~/pacu-lab directory. Run pwd to confirm your location.
  • Check that the policies folder exists by running ls. If it is missing, create it with mkdir policies and try again.

help me fix a file creation error in my pacu lab directory

✔️ Awesome, I've got everything!

Great. Make sure the JSON is valid before moving on.

ⓧ I'd like to double check the full code

Here is the complete vulnerable-policy.json file:

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

Now push this policy document to AWS so it becomes a real IAM policy your test user can be assigned.

  • Create the policy in your AWS account by running this command:
aws iam create-policy --policy-name LabVulnerablePolicy --policy-document file://policies/vulnerable-policy.json

You should see JSON output containing a Policy object with fields including PolicyName, Arn, and DefaultVersionId.

  • Copy the Arn value from the output and save it somewhere (a text file or sticky note). It looks like arn:aws:iam::123456789012:policy/LabVulnerablePolicy with your own account ID.

Why save the ARN?

You will use this ARN in the next command to attach the policy to your test user. It is also needed later during cleanup to delete the policy.

Seeing "MalformedPolicyDocument"?

  • Run cat policies/vulnerable-policy.json and check for missing commas, mismatched braces, or extra trailing commas after the last array item.
  • Make sure Version is set to 2012-10-17 exactly. Any other value is rejected.

help me fix a MalformedPolicyDocument error when creating an IAM policy

Create the victim IAM user and attach the vulnerable policy

With the policy created, you now need a user to wear it. This user represents a compromised credential you might find during a real engagement.

  • Create the test user by running this command:
aws iam create-user --user-name redteam-target-user

You should see JSON output with UserName showing redteam-target-user and an Arn for the new user.

  • Attach the vulnerable policy to this user by running this command:
aws iam attach-user-policy --user-name redteam-target-user --policy-arn [[POLICY_ARN="arn:aws:iam::123456789012:policy/LabVulnerablePolicy"]]

What does attaching a policy do?

Attaching a managed policy to a user grants them all the permissions defined in that policy. Your test user now has S3 read access and the dangerous iam:CreatePolicyVersion permission.

This command produces no output on success. No news is good news here.

Seeing "NoSuchEntity" or "PolicyNotFound"?

  • Double check you pasted the full ARN including arn:aws:iam:: at the start and /LabVulnerablePolicy at the end.
  • Make sure the user name matches exactly: redteam-target-user. Names are case-sensitive.

help me fix a NoSuchEntity error when attaching an IAM policy to a user

Now create access keys so you can authenticate as this user from the command line.

  • Generate access keys for the test user by running this command:
aws iam create-access-key --user-name redteam-target-user

You should see JSON output containing AccessKeyId and SecretAccessKey.

Save these credentials now

The SecretAccessKey is shown only once. If you lose it, you will need to delete and recreate the access key.

Copy both the AccessKeyId and SecretAccessKey to a temporary text file or note. You will use them in the next substep.

Configure the test user's credentials as a separate AWS CLI profile

Rather than overwriting your admin credentials, you will store the test user's keys in a named profile. This lets you switch between your admin identity and the compromised identity by adding a --profile flag to any AWS CLI command.

  • Set up the new profile by running this command:
aws configure --profile redteam-target

What will this command ask?

The command prompts you for four values one at a time:

  • AWS Access Key ID — paste the AccessKeyId you saved from the previous command.
  • AWS Secret Access Key — paste the SecretAccessKey you saved.
  • Default region name — enter the same region your admin profile uses (for example us-east-1).
  • Default output format — enter json.
  • Enter each value when prompted and press Enter after each one.

Once all four prompts are answered, the profile is saved.

  • Verify the profile works by running this command:
aws sts get-caller-identity --profile redteam-target

You should see output showing UserId, Account, and an Arn ending in user/redteam-target-user. This confirms you can now authenticate as the test user.

Seeing "InvalidClientTokenId"?

  • This means the access key ID is wrong. Run aws configure --profile redteam-target again and carefully re-paste the AccessKeyId from your saved output.
  • If you lost the credentials, delete the old key with aws iam delete-access-key --user-name redteam-target-user --access-key-id YOUR_OLD_KEY_ID and run aws iam create-access-key --user-name redteam-target-user again.

help me fix an InvalidClientTokenId error with my AWS CLI profile

Your vulnerable lab environment is fully built. You have a limited IAM user with a hidden escalation path, ready to be compromised. Next up, you will import these credentials into Pacu and enumerate what the "attacker" can see.

Enumerate Permissions with Pacu

You have a compromised credential (the test user's access keys) and a configured AWS CLI profile. In a real engagement, this is often where you start. You have keys, but you don't know what they can do.

In this step, you will load those credentials into Pacu and use its enumeration modules to automatically discover what permissions the compromised user has. This is the reconnaissance phase of any AWS privilege escalation attack.

In this step, get ready to:
  • Launch Pacu and create a session for this engagement.
  • Import the test user's access keys and enumerate their permissions.
  • Confirm the starting permissions are limited and identify the dangerous combination.
Start Pacu and create a new session

A Pacu session stores all credentials, enumerated data, and module results for a single engagement. Creating a dedicated session keeps your lab work isolated.

  • Make sure your virtual environment is still active (you should see (venv) in your terminal prompt). Launch Pacu by running:
pacu

What happens when Pacu launches?

Pacu starts an interactive shell. On first launch, it asks you to name a new session. This session acts like a project folder for all the credentials and data you collect during this engagement.

  • Pacu will prompt you to name a new session. Type iam-privesc-lab and press Enter.

Your prompt should now show the session name:

Pacu (iam-privesc-lab:No Keys Set) >
  • Import the test user's access keys by typing the following command inside the Pacu prompt:
set_keys

What does set_keys ask for?

Pacu will walk you through four prompts. You need the access keys you saved from the redteam-target-user in the previous step.

  • Key alias: enter redteam-target (a nickname to reference these keys).
  • Access key ID: paste the AccessKeyId you saved earlier.
  • Secret access key: paste the SecretAccessKey you saved earlier.
  • Session token: press Enter to skip (these are long-term keys, not temporary credentials).

You should see the confirmation message and your prompt updates to show the key alias:

Keys saved to database.

Pacu (iam-privesc-lab:redteam-target) >

Seeing a key alias error?

Pacu requires the key alias to be at least 2 characters. Make sure you typed redteam-target and not a single character.

If you pasted the wrong access key, run set_keys again to overwrite with the correct values.

help me fix my Pacu set_keys configuration

Run IAM enumeration to discover what the compromised user can do

With the keys loaded, you can now ask Pacu to query AWS and discover exactly what permissions this credential has. This is the equivalent of running reconnaissance on a compromised account.

  • Run the permissions enumeration module by typing this in the Pacu prompt:
run iam__enum_permissions

What does iam__enum_permissions do?

This module queries the IAM API to discover all policies attached to the current user. It pulls both inline policies and managed policies, then stores the effective permissions in the Pacu database.

On a real engagement, this is your first move after obtaining credentials. You need to know what you can do before you can figure out how to escalate.

The module will output a summary showing the attached policies and their permissions. You should see your LabVulnerablePolicy listed.

  • Now check what Pacu has collected about the current identity by running:
whoami

The whoami output shows the user ARN, account ID, and all discovered permissions in one summary view.

What should I see?

The whoami output should display your user name (redteam-target-user), the account ID, and the permissions collected from the enumeration. You should see s3:List*, s3:Get*, and iam:CreatePolicyVersion listed as the effective permissions.

Module returned no permissions?

If the enumeration returns empty results, confirm you pasted the correct access keys. Run set_keys again and double-check the AccessKeyId and SecretAccessKey match what you saved from the aws iam create-access-key output in Step 2.

Also verify the keys are still active by running aws sts get-caller-identity --profile redteam-target in a separate terminal.

help me troubleshoot why Pacu enumeration returned no permissions

Confirm the starting permissions are limited

Take a moment to read the permissions Pacu discovered. The test user can only do three things: list S3 buckets, read S3 objects, and create new versions of IAM policies.

  • Verify that Pacu shows only s3:List*, s3:Get*, and iam:CreatePolicyVersion in the permissions output.
  • Confirm there is no iam:* or AdministratorAccess anywhere in the results. This user appears limited.

Why is iam:CreatePolicyVersion dangerous?

The iam:CreatePolicyVersion permission lets the user create a new version of any customer managed policy they have access to. Combined with the --set-as-default flag, this means the user can overwrite the policy currently attached to them.

The attack is simple: write a new policy version that grants "Action": "*" on "Resource": "*" and set it as the default. The limited S3-read user instantly becomes a full admin. This is one of the most common IAM privilege escalation paths in real AWS environments.

Your reconnaissance is complete. You know exactly what the compromised credential can do, and you have identified the escalation path. Next, you will exploit this CreatePolicyVersion permission to escalate from a limited user to full administrator access.

Exploit the Privilege Escalation

In the previous step, you enumerated the permissions of your compromised credential and confirmed that redteam-target-user has iam:CreatePolicyVersion access.

Now it is time to act on that finding. You will use Pacu's automated privilege escalation scanner to confirm the attack path, then manually exploit it to understand exactly what happens under the hood.

In this step, get ready to:
  • Run Pacu's privilege escalation scanner to identify exploitable paths.
  • Exploit the CreatePolicyVersion path to overwrite your limited policy with full admin.
  • Verify that the test user now has unrestricted access.
Run Pacu's privilege escalation scanner

Pacu's iam__privesc_scan module checks for 21+ known IAM escalation methods automatically. It analyzes the permissions you already enumerated and identifies which ones can be chained into an escalation.

  • Return to your Pacu session by running:
pacu --session iam-privesc-lab

What does this command do?

The --session flag tells Pacu to load your existing iam-privesc-lab session with the test user's keys and enumeration results already in memory.

  • Run the privilege escalation scanner by entering this command in the Pacu shell:
run iam__privesc_scan

What does this module check?

The iam__privesc_scan module scans for permission misconfigurations that enable privilege escalation. It checks 21+ methods including CreatePolicyVersion, AttachUserPolicy, PutUserPolicy, PassRole combinations, and more.

Available attack paths are presented to you. Because your test user has iam:CreatePolicyVersion, the scanner identifies it as an exploitable vector. The user can rewrite their own attached policy to grant themselves admin.

  • When Pacu asks if you want to run iam__enum_permissions, select y to confirm.
  • Review the output. You should see CreatePolicyVersion listed as an identified privilege escalation method.

Why is CreatePolicyVersion dangerous?

A user with iam:CreatePolicyVersion can create a new version of any customer managed policy attached to them. With the --set-as-default flag, the new version becomes the operative version immediately. This means the user can replace their limited permissions with a policy granting full admin access.

  • After reviewing the scan results, run whoami to confirm Pacu has recorded the escalation path for your session.
whoami

Scanner not finding any paths?

Make sure you ran iam__enum_permissions in the previous step. The privesc scanner relies on those results to identify exploitable permissions.

If Pacu says no escalation methods were found, verify that your LabVulnerablePolicy includes iam:CreatePolicyVersion by running aws iam get-policy-version with your admin profile.

help me debug why Pacu's iam__privesc_scan isn't finding any escalation paths for my test user

Exploit the CreatePolicyVersion path manually

Now you will perform the escalation manually to understand exactly what Pacu automates. The attack writes a new policy version that grants unrestricted access, then sets it as the default version for the attached policy.

  • Exit the Pacu shell so you can work with the AWS CLI directly:
exit
  • Navigate to your policies directory by running:
cd ~/pacu-lab/policies
  • Create the malicious policy document that grants full admin access by running:
cat > admin-policy.json << 'EOF'
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "*",
      "Resource": "*"
    }
  ]
}
EOF

What does this policy do?

This policy document grants "Action": "*" on "Resource": "*". That is full administrative access to every AWS service and every resource in the account. This is what the attacker wants to inject as a replacement for the limited S3-only permissions.

  • Confirm the file was created by running:
cat admin-policy.json

You should see the JSON document with "Action": "*" and "Resource": "*" printed in your terminal.

  • Now execute the privilege escalation. Use the test user's profile to create a new policy version and set it as the default by running:
aws iam create-policy-version --policy-arn [[POLICY_ARN="arn:aws:iam::<your-account-id>:policy/LabVulnerablePolicy"]] --policy-document file://admin-policy.json --set-as-default --profile redteam-target

What is happening here?

This command runs as the redteam-target-user (via --profile redteam-target). The user has iam:CreatePolicyVersion permission, so AWS allows the call.

The --set-as-default flag makes the new version (with Action:*) the operative version immediately. The old limited version still exists as a non-default version, but the policy now grants full admin to anyone it is attached to.

You should see a JSON response with "IsDefaultVersion": true confirming the new version is active.

Seeing an access denied error?

Make sure you are using --profile redteam-target (the test user), not your admin profile. The test user needs to be the one creating the policy version for the escalation to be realistic.

If the error says MalformedPolicyDocument, double check the JSON in admin-policy.json matches the format above exactly.

If you see a message about the maximum number of policy versions, you have hit the 5-version limit. Delete an old version with your admin profile first.

help me fix the access denied error when running create-policy-version with my redteam-target profile

Verify the escalation succeeded

The identity has not changed. You are still redteam-target-user. But the permissions attached to that identity have been silently upgraded to full admin.

  • Confirm you are still the same user by running:
aws sts get-caller-identity --profile redteam-target

The output still shows redteam-target-user. No new credentials were created. The same access key now has elevated permissions.

  • Test your new admin privileges by listing all IAM users in the account:
aws iam list-users --profile redteam-target

This command would have failed before the escalation because the test user only had S3 read permissions. It now succeeds, proving redteam-target-user has full administrative access.

Why does this matter?

The test user started with read-only access to S3 buckets. A single API call turned that into unrestricted admin access across the entire AWS account. The user's identity did not change, no new credentials were issued, and no password was stolen. This is what makes IAM privilege escalation so dangerous in real-world cloud environments.

List-users still returning access denied?

IAM policy changes take effect immediately, so there is no propagation delay. If aws iam list-users still fails, verify the create-policy-version command succeeded. Look for "IsDefaultVersion": true in its output.

You can also verify from your admin profile which version is currently default:

help me verify that my policy version escalation actually took effect on redteam-target-user

You have just completed the full privilege escalation chain. Next up, you will examine the CloudTrail evidence this attack left behind and learn how defenders can detect it.

Analyze the Attack from CloudTrail

You have just escalated from a limited S3-read user to full admin access. In a real engagement, every API call you made left a trace.

In this step, you will switch to the blue team's perspective and examine CloudTrail logs. You will see exactly what your privilege escalation looked like to a defender monitoring the account.

In this step, get ready to:
  • Query CloudTrail for the test user's full event history.
  • Examine the CreatePolicyVersion event JSON from the defender's perspective.
  • Understand the detection signals that reveal this attack.
Query CloudTrail for the attack events

CloudTrail automatically records every API call made in your AWS account. It stores the last 90 days of management events for free. This means your entire attack chain is already logged and waiting to be queried.

  • Query CloudTrail for all events performed by redteam-target-user by running this command:
aws cloudtrail lookup-events --lookup-attributes AttributeKey=Username,AttributeValue=redteam-target-user

What does this command do?

  • aws cloudtrail lookup-events queries the CloudTrail event history for your account.
  • --lookup-attributes AttributeKey=Username,AttributeValue=redteam-target-user filters events to only those made by your test user.
  • The output is sorted with the most recent event first.

You should see a JSON response containing an Events array. Each event has an EventName field showing the API action that was called.

  • Scan through the EventName fields in the output.
  • Look for CreatePolicyVersion in the list of events. This is the API call that overwrote the limited policy with full admin access.

What events should I see?

You should see events like CreatePolicyVersion alongside other calls the test user made (such as GetCallerIdentity or ListUsers). The CreatePolicyVersion event is the smoking gun. It proves the user modified their own policy.

Not seeing any events?

CloudTrail events can take up to 15 minutes to appear after the API call is made. If you just ran the escalation, wait a few minutes and try again.

Make sure you are running this command with your admin credentials (default profile), not the redteam-target profile. Your admin credentials have permission to query CloudTrail.

help me troubleshoot why CloudTrail lookup-events is returning empty results for my test user

Read the CloudTrail event like a defender

Each event in the output includes a CloudTrailEvent field. This field is a JSON string containing the full details of the API call. It holds everything a defender needs to reconstruct what happened.

  • Find the event where EventName is CreatePolicyVersion.
  • Look at the CloudTrailEvent string for that event. Inside it, identify these key fields:
  • eventName confirms the API action (CreatePolicyVersion).
  • requestParameters contains the new policy document the user submitted. This is where you see "Action": "*" and "Resource": "*" in the request.
  • sourceIPAddress shows where the API call originated from.
  • userAgent shows which tool made the call (you will see aws-cli because you used the AWS CLI).

Why is this event suspicious?

A non-admin user calling CreatePolicyVersion is unusual on its own. Most legitimate users never modify policy versions directly.

What makes it a clear attack indicator is the requestParameters field showing a new policy document with "Action": "*" on "Resource": "*". A low-privilege user granting themselves unrestricted access is a textbook privilege escalation.

Reading the CloudTrailEvent field

The CloudTrailEvent field is returned as an escaped JSON string. Copy it into a text editor and format it, or pipe the output through a JSON parser to make it readable.

Understand detection opportunities

Now that you have seen what the attack looks like in the logs, consider how a security team would detect it in real time.

  • The CreatePolicyVersion event with setAsDefault=true in the requestParameters is a high-fidelity detection signal. Legitimate policy changes rarely come from non-admin users.
  • GuardDuty would flag this activity as PrivilegeEscalation:IAMUser/AdministrativePermissions. This finding fires when an IAM user gains admin-level permissions through an anomalous policy change.
  • Defenders should alert on any CreatePolicyVersion call where the new policy document contains "Action": "*". This pattern catches the exact attack you just performed.

What is GuardDuty?

Amazon GuardDuty is a threat detection service that continuously monitors CloudTrail management events, VPC Flow Logs, and DNS logs. It uses machine learning to identify anomalous API activity.

For IAM privilege escalation attacks, GuardDuty correlates the API call sequence (enumeration followed by policy modification) to generate high-confidence findings without any manual rule writing.

Why is this a high-fidelity detection?

Most detection rules generate false positives. This one does not. A non-admin IAM user calling CreatePolicyVersion with setAsDefault=true and a wildcard policy document is always malicious or a severe misconfiguration. Either way, it demands immediate investigation.

As a red teamer, knowing this detection exists helps you anticipate the blue team's response and plan your timing accordingly.

You have now seen your own attack through the defender's eyes. Next up, you will clean up all lab resources so nothing lingers in your AWS account.

Clean Up All Lab Resources

You successfully escalated from a limited user to full admin and analyzed the attack from the defender's perspective. Now it is time to tear down the lab environment completely.

Leaving test users with admin access keys in your account is a real-world security risk. In this step you will methodically delete every resource you created, leaving zero footprint in your AWS account.

In this step, get ready to:
  • Delete the test user's access keys and detach the vulnerable policy.
  • Delete the IAM user and the custom policy.
  • Remove the AWS CLI profile and local lab files.
Delete the test user's access keys and detach the policy

AWS requires you to remove all attached items from an IAM user before you can delete the user itself. Start by deleting the access keys and detaching the managed policy.

  • Delete the test user's access keys by running this command (replace the access key ID with the one you saved earlier):
aws iam delete-access-key \
    --access-key-id [[ACCESS_KEY_ID="your redteam-target-user access key ID"]] \
    --user-name redteam-target-user

What does this command do?

The --access-key-id flag targets the specific key pair to revoke. The --user-name flag specifies which user owns that key. This command produces no output on success.

  • Detach the LabVulnerablePolicy from the user by running:
aws iam detach-user-policy \
    --user-name redteam-target-user \
    --policy-arn [[POLICY_ARN="your LabVulnerablePolicy ARN"]]

What does this command do?

This removes the managed policy attachment from the user without deleting the policy itself. You must detach all policies before AWS allows you to delete the user or the policy.

Neither command produces output on success. If you see no error, both commands worked correctly.

Seeing an error about the entity not existing?

Double-check that the --policy-arn value matches the exact ARN you noted when you created the policy in Step 2. ARNs are case-sensitive and must include your account ID.

Help me troubleshoot a detach-user-policy error in my IAM cleanup.

Delete the IAM user and the custom policy

With the access key deleted and policy detached, the user has no remaining attachments. You can now safely delete both the user and the policy.

  • Delete the IAM user by running:
aws iam delete-user --user-name redteam-target-user

No output means success. The user is now permanently removed from your account.

  • Before you can delete the policy, you need to remove all non-default versions. List the existing versions by running:
aws iam list-policy-versions \
    --policy-arn [[POLICY_ARN="your LabVulnerablePolicy ARN"]]

What should I see?

You should see two versions listed. The version with "IsDefaultVersion": true is v2 (the escalated admin version you created in Step 4). The version with "IsDefaultVersion": false is v1 (the original limited policy).

  • Delete the non-default version (v1) by running:
aws iam delete-policy-version \
    --policy-arn [[POLICY_ARN="your LabVulnerablePolicy ARN"]] \
    --version-id v1

Why delete non-default versions first?

AWS does not allow you to delete the default version directly. The default version is automatically removed when you delete the policy itself in the next command. You must remove all other versions before the policy can be deleted.

  • Delete the policy itself by running:
aws iam delete-policy \
    --policy-arn [[POLICY_ARN="your LabVulnerablePolicy ARN"]]

Getting a DeleteConflict error?

This means the policy still has non-default versions remaining or is still attached to a user. Run the list-policy-versions command again to check for leftover versions. Verify you detached the policy from the user in the previous substep.

Help me resolve a DeleteConflict when deleting my IAM policy.

Remove the AWS CLI profile and local files

The IAM resources are gone from AWS. Now clean up the local files on your machine so no stale credentials remain.

  • Open ~/.aws/credentials in a text editor and delete the [redteam-target] section (the profile header and the two lines beneath it).
  • Open ~/.aws/config and delete the [profile redteam-target] section if it is present.
  • Delete the working directory and all policy JSON files by running:
rm -rf ~/pacu-lab
  • Verify the cleanup is complete by running:
aws iam list-users

You should no longer see redteam-target-user in the output. Your AWS account is back to its pre-lab state with zero leftover resources.

Still seeing redteam-target-user in the list?

If the user still appears, one of the earlier delete commands may have failed silently. Check the error message carefully for what attachment still exists (access key, inline policy, or managed policy).

aws iam delete-user --user-name redteam-target-user

Help me figure out why my test user still exists after cleanup.

Your lab environment is fully torn down. Every IAM resource, access key, and local file has been removed. You have completed a full red team engagement cycle: setup, enumeration, exploitation, detection analysis, and cleanup.

Secret mission

Chain Two Privilege Escalation Paths

You have already exploited one IAM privilege escalation vector. Real-world AWS environments often have multiple misconfigurations stacked together. In this mission, you will create a second vulnerable user with the iam:AttachUserPolicy permission, use Pacu to discover the new vector, exploit it, and compare both attack signatures in CloudTrail.

Clean Up Your Resources

Clean Up Your Resources

Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project runs entirely on free AWS services (IAM, STS, and CloudTrail management events). Your only remaining resource is the local project directory containing Pacu and the virtual environment.

Resources you used:

  • ~/pacu-lab/ project directory (Python virtual environment, Pacu installation, policy JSON files, Pacu session data).
  • Test IAM users and custom policies (already cleaned up in Step 6 and the Secret Mission).
  • AWS CLI profiles redteam-target and redteam-target2 (already removed from ~/.aws/credentials and ~/.aws/config).

Keep everything running

No action needed. Choose this if you want to keep your Pacu lab environment ready for future AWS red team exercises.

  • Your ~/pacu-lab/ directory stays as a self-contained lab you can reactivate anytime.
  • Pacu session data from iam-privesc-lab and iam-privesc-lab2 is preserved so you can review past results.
  • There are no running processes or ongoing costs to worry about.

Pause - I'll come back to this later

Since this project is entirely local (no running servers or cloud resources), pausing is the same as keeping. There are no processes to stop or costs accumulating.

  • If your virtual environment is still active, deactivate it by running:
deactivate

This returns your terminal to the system Python. You can reactivate later with:

source ~/pacu-lab/venv/bin/activate
  • Everything else stays in place until you're ready to return.

Delete - I don't want to use this again

Remove all local project files and the Pacu installation. Since IAM resources and CLI profiles were already cleaned up in Step 6 and the Secret Mission, this is the final step.

  • If your virtual environment is still active, deactivate it first:
deactivate
  • Delete the entire project directory by running:
rm -rf ~/pacu-lab/
  • Verify the directory is gone by running:
ls ~/pacu-lab/

You should see a "No such file or directory" message confirming the deletion.

  • Confirm no test IAM users remain by running:
aws iam list-users

You should not see redteam-target or redteam-target-user2 in the output. Only your admin user should appear.

Nice Work!

Nice Work!

Nice work! You just built a full AWS red team lab from scratch, escalated from a limited IAM user to unrestricted admin access, and analyzed the entire attack chain from both sides of the fence.

You've learned how to:

  • Built a deliberately vulnerable IAM environment with a known CreatePolicyVersion privilege escalation path and exploited it to achieve full admin access using Pacu.
  • Enumerated IAM permissions from a compromised credential using automated exploitation tools, discovering exploitable paths that a manual review might miss.
  • Analyzed CloudTrail logs from the defender's perspective, identifying high-fidelity detection signals that reveal privilege escalation attempts.
  • Secret Mission: Chained a second escalation path (AttachUserPolicy) and compared detection signatures across both attack methods.

Ready to quiz yourself?