Tabletop Scenario: Account Compromise¶
A SnowOps incident-response tabletop (
K5) — discussion-based, no real consoles. The facilitator reveals injects one at a time; participants respond by citing the matching runbook step. Facilitation method:facilitation-guide.md. Pack overview:README.md.
Exercises runbook: ../incident/compromise.md — Account Compromise.
| Field | Value |
|---|---|
| Scenario | Account Compromise — privileged user, impossible travel |
Incident class (K1) |
compromise |
| Duration | 60 min |
| Participants | 4–8 |
| Difficulty | standard (+1 curveball) |
| Last run | <YYYY-MM-DD> |
Objective¶
Validate that on-call can detect, contain, investigate, and recover from a
compromised privileged Entra ID account using
../incident/compromise.md, and surface gaps in the
runbook, the K3 SOAR "isolate account" playbook, and the comms plan.
Success looks like: the team confirms the compromise out-of-band, revokes
sessions and contains the account within the timebox, scopes what the attacker
touched in Azure, and ends with named K4 follow-ups (e.g. enforce
phishing-resistant MFA for privileged roles).
Scope & assumptions¶
- In scope: the prod Azure tenant; one privileged user (
<j.okafor@snowops.io>, holds an eligible PIM role forContributoron the prod subscription). - Out of scope: the corp laptop fleet (EDR is a separate team), customer tenants.
- Assumptions (state at kickoff):
K2on-call paging is live;K3SOAR playbooks are deployed in dry-run mode; Sentinel (J3) + Defender for Identity are ingestingSigninLogs/AuditLogs; Conditional Access is enabled. - Standing rule: discussion only — no real session revokes, no real paging.
Roles¶
| Role | Played by | Responsibility |
|---|---|---|
| Incident Commander (IC) | <name> |
Declares severity, owns the response. |
| On-call responder | <name> |
Drives compromise.md. |
| Identity SME | <name> |
Entra ID / PIM / Conditional Access knowledge. |
| Communications | <name> |
Internal + (if data touched) client updates. |
| Scribe (optional) | <name> |
Timeline + decisions for the after-action. |
Injects (timeline)¶
Reveal one at a time, in order.
T+is minutes from inject 1.
| # | T+ | Inject (read to the room) | Maps to K1 phase |
Facilitator notes (don't read aloud) |
|---|---|---|---|---|
| 1 | 0 min | Sentinel incident: "Impossible travel" sign-in for j.okafor@snowops.io — successful interactive login from Lagos, NG at 02:14, then Frankfurt, DE 40 min later. Both MFA-satisfied. |
Identification | If the team calls Jane: she is asleep at home in Lagos, did not log in from Frankfurt, and got an MFA push she "approved to make it stop" (MFA fatigue). |
| 2 | ~8 min | Defender for Identity fires: the account added a new authenticator app and an Entra ID app registration was granted a client secret by this user 12 min ago. | Containment | The Frankfurt session is still active. The new app secret is the attacker's persistence. |
| 3 | ~16 min | AuditLogs show the user activated their eligible PIM role (Contributor, prod sub) 6 min ago and added themselves to the prod-keyvault-admins group. |
Eradication & Investigation | Privilege escalation. Pull them toward the runbook's KQL + Activity Log review. |
| 4 | ~26 min | AzureActivity shows a Key Vault secret list/get burst against kv-snowops-prod from the elevated session, then a storage account network ACL was set to Allow on stsnowopsprod. |
Recovery | Now it's also a potential data-exfil vector — does the team pivot to data-leak.md? |
| 5 | ~34 min | Sessions revoked, password reset, rogue app secret removed, PIM activation revoked. No further malicious activity for 30 min. | Post-Incident | Drive Lessons-Learned: MFA was satisfied — what changes? |
| 6 | ~40 min | Curveball: the Identity SME is the one who is unreachable (on a plane). Who does the Entra ID work now? Is it documented? | any | Hold for stretch; tests bus-factor + runbook self-sufficiency. |
Discussion Questions (by K1 phase)¶
Push the team into
../incident/compromise.md— they must cite the step.
Phase 1 — Identification¶
- The runbook's Identification "Immediate Action" says confirm out-of-band. How do you reach Jane if her account is the compromised one — what channel, whose number, is it in the runbook?
- Impossible travel with MFA satisfied — what does that tell you about the attack (MFA fatigue / token theft)? Is this one incident class or could it become two?
Phase 2 — Containment¶
- Walk the runbook's Containment steps in order: revoke sessions → reset password → block sign-in → remove unfamiliar MFA methods. Who is authorised to do each in prod, and would you block sign-in given Jane needs the account back?
- Would you trigger the
K3"isolate account" SOAR playbook? In dry-run or enforce — and what exactly does enforce do here? What's the blast radius of blocking aContributor-eligible identity?
Phase 3 — Eradication & Investigation¶
- Run the runbook's
SigninLogsKQL for this UPN over 7 days — what are you looking for (IPs, locations, app IDs)? Then theAuditLogsreview: what admin actions does the runbook tell you to hunt for? (You'd find the app-secret add and the PIM activation.) - The runbook says review Azure Activity Logs for resource changes. What did the elevated session touch (Key Vault, storage ACL), and what must you now treat as compromised?
Phase 4 — Recovery¶
- Per the runbook: unblock the account only after credentials + MFA are secured
and changes reverted. What specifically do you revert here (rogue app secret,
group membership, storage network ACL, rotate Key Vault secrets that were
get-ed)? - The runbook says monitor for 72 hours. What signal would make you re-open the incident?
Phase 5 — Post-Incident / Lessons Learned¶
- The runbook asks: was MFA bypassed (fatigue)? It recommends phishing-resistant MFA (FIDO2 / Windows Hello). Do we enforce that for all privileged/PIM-eligible roles? Who owns that change?
- Were any Key Vault secrets read by the attacker? If so, does this also trigger
the Data Leak runbook's notification obligations? Which finding becomes a tracked
K4action item, with owner and due date?
Evaluation Rubric¶
Score 1–4 per dimension; total /20.
| Dimension | 1 — Ad hoc | 2 — Partial | 3 — Solid | 4 — Strong | Score |
|---|---|---|---|---|---|
| Detection & triage | Treated as benign | Spotted late | Identified, confirmed with Jane out-of-band | Fast + recognised MFA-fatigue vector | |
| Runbook fluency | Didn't open it | Improvised | Followed compromise.md steps |
Followed + caught a gap (e.g. no OOB contact list) | |
| Containment decisions | Left session live | Revoked sessions only | Sessions + password + MFA + rogue app | All that + correct K3 decision, scoped blast radius |
|
| Roles & comms | Role confusion | IC late | Clear IC + identity SME | Crisp roles + escalation to data-leak comms when KV touched | |
| Recovery & learning | None | Re-enabled blindly | Reverted changes + monitor | Validated + FIDO2 mandate + K4 items |
|
| Total | /20 |
After-Action¶
Fill live; expand into
after-action-template.mdand route trackable findings toK4(apps/post-incident-review/).
- Date / facilitator / attendees:
<…> - Rubric total:
<n>/20 - What went well:
<…> - Top gaps found (cite runbook step):
<e.g. compromise.md has no out-of-band contact list for the affected user; no guidance on PIM-escalation revocation> - Improvement items:
<item — owner — due date — destination>