Frontend Labs
⋯

Chapter 10 — Hands-on: attack and defend a cloud account

Brief

Run a complete offense-then-defense cycle against a deliberately-vulnerable AWS environment in your sandbox: walk an attack path from a low-privileged credential to customer data, then close every edge and prove the path is dead, then add detection for the residual risk. This is the MODEL -> ATTACK -> DETECT -> DEFEND loop from Chapter 0.2 at full size.

Setup

   * Sandbox AWS account (its own; budget alarm at $5, stop at $20).
   * Deploy CloudGoat's `iam_privesc_by_rollback` and
     `ec2_ssrf` scenarios, OR BishopFox `IAM Vulnerable`, OR build the
     SecureShop-mini stack from this guide's repo (a VPC, an EC2 "web"
     host with an image-proxy SSRF, an over-broad instance role, an
     `ss-exports` bucket with a fake PII file, IMDSv1 enabled).
   * Tools: awscli, pacu, CloudFox, PMapper, cloudsplaining, Prowler,
     ScoutSuite, Stratus Red Team.

Part 1 — Model (30 min)

   1. From the starting creds, run CloudFox (`cloudfox aws all-checks`)
      and enumerate-iam. Build the node/edge list (Ch 1).
   2. Run PMapper: `pmapper graph create`, then
      `pmapper argquery --preset privesc` and
      `pmapper query "who can do s3:GetObject with arn:aws:s3:::ss-exports/*"`.
   3. Draw the attack-path graph from `[external:anon]` and from
      `[creds:starting-role]` to `[data:ss-exports]`. Mark the chokepoint.

Part 2 — Attack (60 min)

   Walk at least one full path end to end, documenting each command and
   its output:
   [ ] SSRF path: hit the image-proxy with
       url=http://169.254.169.254/latest/meta-data/iam/security-credentials/
       -> get role creds (IMDSv1) -> configure them -> `aws s3 ls
       s3://ss-exports` -> download the fake PII file.
   [ ] IAM privesc path: use a privesc primitive (Ch 6) to reach admin,
       then read the bucket "legitimately".
   [ ] Note for each step: what permission/misconfig enabled it, and how
       noisy it is (would anything log/alert today?).

Part 3 — Defend (60 min)

   Close every edge, cheapest chokepoint first, re-testing after each:
   [ ] Enforce IMDSv2 hop-limit-1 on the instance (and add the SCP so new
       instances can't regress). Re-run SSRF -> creds no longer reachable.
   [ ] Allowlist the image-proxy's destination host + block link-local /
       RFC1918 / metadata IPs after DNS resolution (G1 Ch 44 + Ch 33 here).
       Re-test.
   [ ] Scope the instance role: `s3:GetObject` on
       `arn:aws:s3:::ss-public-assets/*` only; move exports to a bucket
       only `exports-worker-role` can read; add `aws:sourceVpce` condition.
   [ ] Kill the privesc primitive (scope `iam:PassRole`, add a permission
       boundary, add SCP denies).
   [ ] Turn on S3 Block Public Access (account-wide), SSE-KMS with a
       customer CMK, and default EBS encryption.
   [ ] Re-run PMapper and CloudFox -> confirm no path from anon or from
       the starting creds reaches `ss-exports`.

Part 4 — Detect (30 min)

   For the residual risk (someone with valid `exports-worker-role` creds
   misusing them), add detection:
   [ ] GuardDuty enabled; generate sample findings; confirm
       `UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration` and
       `Exfiltration:S3/AnomalousBehavior` reach the security account.
   [ ] A CloudTrail metric filter / EventBridge rule: `exports-worker-role`
       session used from a `sourceIPAddress` outside your VPC/NAT ranges,
       OR a `GetObject` volume spike on `ss-exports`. Alarm -> SNS.
   [ ] Re-run the (now-broken) attack with valid creds from an external
       IP; confirm the alert fires and note latency.

Deliverable

~/sec-lab/adv/reports/p2-cloud.md: the attack-path graph (before/after), every attack command with output, every fix with the re-test that proves the edge is cut, and the detection rules with their fire evidence and latency. Plus a one-paragraph "what was the chokepoint and why".

Definition of done

  • At least one full attack path walked and documented from creds/anon to data.
  • Every edge on that path closed, each with a passing re-test.
  • PMapper/CloudFox show no remaining path to the sensitive bucket.
  • IMDSv2, Block Public Access, SSE-KMS, scoped PassRole, and a permission boundary all in place (as Terraform, ideally).
  • GuardDuty + at least one custom near-real-time detection, both proven to fire.
  • Everything torn down; budget checked.

Rubric (/100)

   Attack-path model (nodes/edges/chokepoint) ..... 15
   Attack executed and clearly documented ......... 20
   Every edge closed with a proving re-test ....... 30
   Guardrails as code (SCP + Terraform) .......... 15
   Detection built and proven (fidelity+latency) .. 15
   Report quality ................................ 5

Further reading

  • Practice: CloudGoat (Rhino), flaws.cloud / flaws2.cloud, BishopFox IAM Vulnerable, pwnedlabs.io, AWS "CIRT" workshops.
  • Tools: Pacu (AWS exploitation framework) docs; CloudFox (BishopFox); PMapper; Stratus Red Team; Prowler + ScoutSuite for the defensive sweep.
  • Reading: "Lesser Known Techniques for Attacking AWS" (Rhino); the Capital One breach technical post-mortems (re-read now with the full IAM picture); hackingthe.cloud.
  • Defense: AWS "Incident Response" whitepaper; the "AWS Customer Playbook Framework" repo.

End of Part 2 — Milestone check

  • I can draw the shared-responsibility line for IaaS/PaaS/FaaS and name the pieces of the identity plane
  • I can recite AWS policy evaluation order and what an explicit Deny does
  • I have escalated from low-priv to admin in a lab two ways, then broken both paths and confirmed with PMapper
  • I can design a multi-account structure and a denylist SCP set, and say why the management account runs nothing
  • I can build a default-deny VPC with private endpoints and FQDN egress control, and explain why egress control is the exfil control
  • I can implement envelope encryption with a per-tenant key hierarchy and explain crypto-shredding
  • I completed the attack-and-defend cloud lab end to end with proven detection

Generated from real-life-security-guide-v1.md · 8 Oct 2026 16:36