TollBooth / OpenDoor

Scenario 1 of 2 · Reactive DFIR

TollBooth — investigate the breach

A web server's credentials leaked. Find how, follow the leaked key into the cloud, and write the incident report.

Setup (do this once)

1. Open a terminal. 2. cd ~/tollbooth. 3. Start the agent: claude. 4. Paste each prompt below, in order, in the same chat, so it remembers. Type only the prompt text — no quotes.

~20 min per visit. Do the CORE phases (1, 2, 5) for the full story. DEEP phases (3, 4) are for a quiet moment or to run later — this page is yours to keep. No agent? Terminal fallback commands are at the bottom.

Phase 1 Core

Network forensics

Paste this, then Enter:

Using your cybersecurity skills, investigate lab-tollbooth.pcap: find how the web server's credentials leaked, extract the leaked AccessKeyId (it starts with ASIA), and tell me which external IP sent the malicious request. List the skills you used.

You will see: an SSRF request to 169.254.169.254 and a leaked key starting with ASIA.

Checkpoint — on track when you see

SSRF: GET /proxy?url=http://169.254.169.254/... → a JSON cred blob with an AccessKeyId starting ASIA, and exactly one external attacker IP.

Reveal the answer

SSRF on /proxy (10.0.1.50) forced a fetch of 169.254.169.254 (IMDSv1) → role creds leaked. Key ASIAJ7A6EXAMPLEK3Y99 (role acme-webapp-role). Injector: 203.0.113.66.

Phase 2 Core

Cloud forensics — the pivot

Same chat:

Now use your CloudTrail and S3 skills on the cloudtrail/ folder: with that leaked AccessKeyId, list everything the attacker did and which files they stole from the S3 bucket.

You will see: recon calls, then 6 GetObject downloads of customer data by the leaked key.

Checkpoint — on track when you see

The same key does recon (GetCallerIdentity, ListBuckets, IAM listing) then a burst of GetObject — arriving from an OUTSIDE IP, unlike the legit calls from the instance itself.

Reveal the answer

Same key from 203.0.113.66 (external) vs 10.0.1.50 (legit): recon, then 6× GetObject on acme-customer-data (payment_tokens.csv, ssn_index.parquet, db-dump). Attacker IP in pcap and CloudTrail = proof of pivot.

Phase 3 Deep

Baseline vs. anomaly

Same chat:

Separate the attacker from normal use: what does legitimate activity on this account look like, and what makes the attacker's calls stand out? Could you have caught them WITHOUT already knowing the key?

You will see: legit calls come from the instance's own IP; the attacker's come from outside — catchable by origin, not just the key.

Checkpoint — on track when you see

Legit baseline = the instance's own IP / console. Attacker = same key, different origin. The tell is location + burst, not the key value — so yes, findable without it.

Reveal the answer

Legit calls originate from the instance / console; the attacker reuses the key from an external IP in a tight burst. Detectable by origin + rate even with the key unknown.

Phase 4 Deep

Map it — and check the agent

Same chat:

Map the full attack to MITRE ATT&CK technique IDs, then add the NIST CSF 2.0 categories and MITRE D3FEND techniques that are relevant to this incident. Skip MITRE ATLAS and NIST AI RMF - this is not an AI-system attack, so they do not apply; say so rather than forcing a mapping. Check whether MITRE F3 (fraud) applies given the stolen payment data, and say if it does not. For every ID in every framework: is it directly evidenced in THIS data, or are you inferring it?

You will see: a clean ATT&CK chain, plus CSF categories (PR.AA / PR.PS / DE.CM) and D3FEND countermeasures (D3-ITF / D3-OTF / D3-NTA) — and watch it correctly skip ATLAS/AI RMF instead of forcing them in, and catch it if it over-maps ("exfiltration/T1567" when the data only shows reads = T1530). Correct any of these — this is the whole point of the exercise.

Checkpoint — on track when you see

A per-step chain of ATT&CK IDs. The agent may over-map (S3 reads tagged as exfiltration/T1567). Correct read = T1530 (data from cloud storage). The catch is the learning.

Reveal the answer

ATT&CK: T1552.005 (IMDS) → T1078.004 (stolen key) → T1580 / T1087.004 (discovery) → T1530 (S3 read). Not T1567 — no exfil-OUT event exists here; that's the agent's classic over-map to catch.

CSF 2.0: PR.AA (credential/identity exposure), PR.PS (platform-hardening gap = IMDSv1), DE.CM (nothing alerted on the burst — the real detection gap).

D3FEND: D3-ITF / D3-OTF (traffic-filtering fixes), D3-NTA (the detection approach itself).

ATLAS / AI RMF: do not apply — no AI system in this incident; the agent should say so, not force a tag.

F3 (fraud): a judgment call given the stolen payment tokens — "maybe, but this attack is not a fraud-scheme TTP" is the strong answer.

Phase 5 Core

Incident report

Same chat:

Write a short incident report: the full attack chain, the VERIFIED ATT&CK IDs, and the single change that would have stopped it.

You will see: SSRF → stolen creds → discovery → S3 read, and "enforce IMDSv2" as the one fix.

Checkpoint — on track when you see

One chain, an ID per step, and a single fix (IMDSv2) that breaks the whole thing.

Reveal the answer

Enforce IMDSv2 (HttpTokens=required) — breaks the entire chain at step one.

Explore without spoiling it

Want to poke at the raw data yourself, agent aside?

cat cloudtrail/*.json | jq -r '.Records[].sourceIPAddress' | sort -u        # who is talking?
cat cloudtrail/*.json | jq -r '.Records[].userIdentity.accessKeyId' | sort | uniq -c

Terminal fallbacks (no agent)

tshark -r lab-tollbooth.pcap -Y 'http.request.uri contains "169.254"' -T fields -e ip.src
tcpdump -nA -r lab-tollbooth.pcap | grep -A6 AccessKeyId    # the leaked JSON
cat cloudtrail/*.json | jq \
  '.Records[]|select(.userIdentity.accessKeyId=="ASIAJ7A6EXAMPLEK3Y99")|{t:.eventTime,e:.eventName}'

Advanced — does it scale? (optional, if a queue is thin)

python3 generate-bigdata.py --events 1000000 --days 3
python3 bigquery.py --build
python3 bigquery.py --key ASIAJ7A6EXAMPLEK3Y99   # same 12 events out of ~1,000,000, in seconds
python3 bigquery.py --anomaly                     # finds the needle WITHOUT the key

Authorized & lawful use only. All data is synthetic and self-contained; no live systems are touched. Promotes the open-source Anthropic Cybersecurity Skills library (Apache-2.0); not affiliated with Anthropic PBC.

Next → Scenario 2: OpenDoor