Enumerating and Exploiting AWS with Pacu

Cloud Security
Time it takes to read this article 6 minutes.

Introduction / Overview

Disclaimer: This article is for educational purposes and authorized penetration testing only. Running these techniques against AWS accounts you do not own or have explicit written permission to test violates the AWS Acceptable Use Policy and applicable computer-misuse laws. Always operate within the scope of a signed engagement.

Once you have a foothold in an AWS environment — a leaked access key, an SSRF that reached the instance metadata service, or a CI/CD secret — the next question is always the same: what can this identity actually do, and can I get more? Manually answering that with dozens of aws iam, aws sts, and aws ec2 calls is slow and error-prone.

Pacu is the open-source AWS exploitation framework maintained by Rhino Security Labs. Think of it as the Metasploit of AWS: it manages credential sessions, ships a library of Pacu modules for enumeration, persistence, and privilege escalation, and stores everything in a local SQLite database so your findings survive restarts. This post walks through the core offensive loop — whoami, iam__enum_*, and the privesc scanner — and then weights the blue-team side equally.

How it works / Background

Pacu organizes work into sessions. A session is a named container holding a set of AWS credentials plus all the data Pacu collects (enumerated users, roles, EC2 instances, buckets, and the like). This lets you keep engagements separate and resume them later.

Each capability is a module, namespaced by category with a double underscore, for example:

  • iam__enum_users_roles_policies_groups — broad IAM enumeration.
  • iam__enum_permissions — resolves what the current principal can do.
  • iam__privesc_scan — checks for known IAM privilege-escalation primitives.
  • ec2__enum, s3__bucket_finder, iam__bruteforce_permissions, and many more.

Pacu's whoami is a built-in command (not a module) that prints the active session's identity and the data gathered so far. Under the hood the framework wraps Boto3, so it speaks the same APIs the AWS CLI does — sts:GetCallerIdentity, iam:ListUsers, iam:GetAccountAuthorizationDetails, etc.

Prerequisites / Lab setup

You need Python 3.7+ and a set of credentials to test against. Never practice on production. Build a deliberately vulnerable account with CloudGoat, also from Rhino, which deploys IAM privesc scenarios via Terraform.

Install Pacu (a virtual environment is strongly recommended):

python3 -m venv pacu-venv
source pacu-venv/bin/activate
pip install pacu
pacu
Bash

Or run it from source:

git clone https://github.com/RhinoSecurityLabs/pacu.git
cd pacu
pip install -r requirements.txt
python3 cli.py
Bash

Pacu stores its database and module state under ~/.local/share/pacu/ (the exact path is printed on first launch).

Walkthrough / PoC

1. Create a session and import credentials

On first run Pacu prompts for a session name. Inside the Pacu prompt, create or list sessions and set your keys:

Pacu (no session) > new_session engagement-01
Pacu (engagement-01:No Keys Set) > set_keys
Key alias [None]: leaked-key
Access key ID [None]: AKIAIOSFODNN7EXAMPLE
Secret access key [None]: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
Session token (Optional - for temp AWS keys only) [None]:
Plaintext

If you already have an AWS CLI profile, you can import it directly instead:

Pacu (engagement-01:No Keys Set) > import_keys my-profile
Plaintext

To list and switch sessions later:

Pacu > list_sessions
Pacu > swap_session engagement-01
Plaintext

2. Confirm who you are with whoami

Before touching anything noisy, establish identity. whoami reflects whatever Pacu currently knows; immediately after setting keys it mostly shows your raw credentials and ARN context.

Pacu (engagement-01:leaked-key) > whoami
Plaintext

This is the equivalent of aws sts get-caller-identity, telling you the account ID, the principal ARN, and whether you are a user or an assumed role. Note it for the report.

3. Enumerate the IAM landscape

If your principal has broad read access, map the whole account first:

Pacu (engagement-01:leaked-key) > run iam__enum_users_roles_policies_groups
Plaintext

This calls iam:GetAccountAuthorizationDetails (and falls back to discrete List* calls) to pull every user, role, group, and attached/inline policy into the session database. Review it later with:

Pacu (engagement-01:leaked-key) > data IAM
Plaintext

4. Resolve your own permissions

The single most important enumeration step is figuring out the effective permissions of the active principal:

Pacu (engagement-01:leaked-key) > run iam__enum_permissions
Plaintext

This module retrieves attached managed policies, inline policies, and group memberships for the current user/role, then stores the full permission set. When the identity lacks iam:Get*/iam:List* on itself, fall back to brute forcing — Pacu probes a wordlist of API actions and records which ones return success (or AccessDenied):

Pacu (engagement-01:leaked-key) > run iam__bruteforce_permissions
Plaintext

Be aware brute forcing generates a large volume of API calls — extremely visible in CloudTrail.

5. Hunt for privilege escalation

With permissions enumerated, run the privesc scanner. It compares your effective permissions against Rhino's catalogue of ~20 known IAM privesc methods (for example iam:CreatePolicyVersion, iam:AttachUserPolicy, sts:AssumeRole to an over-permissioned role, lambda:CreateFunction + iam:PassRole).

Pacu (engagement-01:leaked-key) > run iam__privesc_scan
Plaintext

If a method is confirmed, Pacu can attempt automated exploitation. For example, the CreateNewPolicyVersion primitive abuses the fact that iam:CreatePolicyVersion lets you set a new default version of a managed policy without iam:SetDefaultPolicyVersion:

aws iam create-policy-version \
  --policy-arn arn:aws:iam::123456789012:policy/example-policy \
  --policy-document file://admin.json \
  --set-as-default
Bash

where admin.json grants "Action": "*" on "Resource": "*". Pacu wires this together for you and re-runs iam__enum_permissions so whoami reflects the newly acquired rights.

6. Export and pivot

Once escalated, export the session for reporting or hand the keys back to the AWS CLI:

aws iam list-attached-user-policies \
  --user-name target-user \
  --profile leaked-key
Bash

From here typical follow-ons are ec2__enum, s3__bucket_finder, secrets in secretsmanager/ssm, and persistence modules — but always within scope.

Mermaid diagram

Enumerating and Exploiting AWS with Pacu diagram 1

The diagram shows the standard Pacu loop: establish a session, confirm identity, enumerate permissions (directly or by brute force), scan for privilege escalation, then escalate or pivot laterally.

Detection & Defense (Blue Team)

Pacu's activity is loud in CloudTrail because it relies on standard API calls. Defenders should focus on both detection and prevention, with equal priority to the offensive techniques above.

Detection signals

  • Enumeration bursts. A single principal calling GetAccountAuthorizationDetails, ListUsers, ListRoles, ListPolicies in quick succession is a strong enumeration signal. Brute forcing surfaces as a flood of AccessDenied errors — alert on a high ratio of errorCode = AccessDenied per principal over a short window.
  • GuardDuty. The findings PenTest:IAMUser/KaliLinux, PenTest:IAMUser/ParrotLinux, Recon:IAMUser/MaliciousIPCaller, and PrivilegeEscalation:IAMUser/AdministrativePermissions map directly to this tradecraft. Enable GuardDuty across all regions.
  • Privesc primitives. Alert on CreatePolicyVersion with setAsDefault=true, AttachUserPolicy/AttachRolePolicy adding AdministratorAccess, PassRole paired with lambda:CreateFunction or ec2:RunInstances, and any CreateAccessKey for a different user. CloudTrail Insights and Athena queries over the trail are effective here.
  • Untrusted networks. Long-lived AKIA... keys (not session tokens) suddenly used from a new ASN or VPN/Tor exit are suspect — correlate sourceIPAddress and userAgent (Pacu's Boto3 user agent is identifiable).

Mitigations

  • Eliminate long-lived keys. Prefer IAM Identity Center / SSO and IAM roles with sts:AssumeRole. The leaked-key scenario largely evaporates when there are no static AKIA credentials to leak.
  • Least privilege. Most Pacu privesc paths require a dangerous combination such as iam:CreatePolicyVersion, iam:PutUserPolicy, or unrestricted iam:PassRole. Run IAM Access Analyzer and remove these from non-admin roles.
  • Service Control Policies (SCPs). Use Organizations SCPs to deny IAM-modifying actions outside a break-glass path, and aws:RequestedRegion / PassedToService conditions to constrain PassRole.
  • Permissions boundaries. Attach a permissions boundary to delegated-admin roles so even if an attacker can attach policies, the boundary caps the effective privileges.
  • MFA and condition keys. Require aws:MultiFactorAuthPresent for sensitive actions; harden IMDS to IMDSv2 to cut off the SSRF-to-credentials path that often feeds Pacu in the first place.

For wider context see our notes on cloud SSRF and metadata abuse and AWS IAM privilege escalation paths, as well as the general CloudGoat lab walkthrough.

Conclusion

Pacu turns the tedious, multi-call AWS enumeration loop into a repeatable, session-based workflow: import keys, run whoami, enumerate with iam__enum_permissions, and let iam__privesc_scan surface the path to admin. The same speed that makes it valuable to attackers makes the activity highly visible — every action is a CloudTrail event. Blue teams that enforce least privilege, kill static keys, and alert on enumeration and privesc primitives neutralize most of what Pacu can do before it ever reaches escalation.

References

Comments

Copied title and URL