Scenario
Miren Vale attends a Suncourt meeting where officers are deciding who will guard the east road. A false story is already spreading: one of Stormbound's captains supposedly sold the road schedule to Vaultrune. By the time Miren arrives, the rumor has reached the commanders as a formal accusation. By morning, the captain's unit may get pulled from the road, leaving the supply carts without guards. Miren can't accuse Lady Seralyne, the woman who runs Suncourt, in front of the room. The officers would call it gossip, and the order would still go out. Miren has to find who started the rumor and who paid to spread it.
Enumeration
First thing I did was point my AWS CLI at the challenge's custom endpoint and load up the credentials I'd been given.
With my identity confirmed, I scanned the supply-road-settlements table to find the record marked LIVE, since that was supposedly the accusation actively in play.
Digging through the results, I isolated the active row, ROAD-3D9C:
That row handed me my next lead: an IAM role called supply-road-scanner, the external ID needed to assume it, and an S3 bucket to go poke at.
Assuming the Scanner Role & Discovering S3 Redaction
I used sts-assume-role to pivot into supply-road-scanner:
Once I'd exported the temporary credentials, I recursively listed the supply-road-manifests bucket.
That turned up a manifest file matching my settlement ID, manifests/ROAD-3D9C.json. But when I pulled it down, most of the interesting fields had been stamped REDACTED under something called a "COMPLIANCE_HOLD." Not the end of the road — just an obstacle.
Bypassing Redaction via S3 Versioning
I've seen this pattern before: redaction on the current object often doesn't touch older versions if versioning is enabled on the bucket. So I checked.
Sure enough, there was an earlier version sitting there, noticeably larger than the redacted one — VersionId: 8febdfd1-9bef-4c49-91f0-4ecbdbc52c80. I grabbed it directly.
Decrypting the KMS Payload
The unredacted manifest wasn't plaintext — it was wrapped in a kms:v3:... ciphertext blob. But since the scanner role I was wearing had decrypt permissions, I just handed the blob straight to KMS.
That gave me the plaintext I was after:
Now I had real names to chase: a secret holding the payout, a user called road-messenger, and a role called supply-road-runner.
IAM Privilege Escalation & Lateral Movement
I tried reading the payout secret straight away as the scanner role — denied. Expected, but worth ruling out.
So I checked what else the scanner role could touch, and found something I could work with: it had permission to mint new access keys for the road-messenger user.
I grabbed the new AccessKeyId and SecretAccessKey, loaded them into my environment, and just like that I was operating as road-messenger.
Final Pivot
Even as the messenger, the secret was still out of reach. But between the decrypted manifest and my original DynamoDB scan, I had the last piece: road-messenger was the trusted identity for assuming supply-road-runner.
So I assumed it, using the external ID I'd noted all the way back in my initial access.
With runner privileges in hand, I finally had clearance to pull the payout secret from Secrets Manager.
Output:
Trail's end. The payout record was proof enough — the rumor had a price tag on it, and now I had the receipt.