The Hitchhiker's Guide to Running an Adversary-Emulation Plan on the Range

The operator's walkthrough for Phase 01. The WARMUP explains the concepts (the lifecycle, the three lenses, ATT&CK, the Pyramid of Pain, the CTI→plan workflow, purple teaming). This guide shows you how to build and run an emulation plan on your own authorized range: pick a named actor from CTI, select ATT&CK techniques, write procedures with success criteria and stop conditions, run Atomic-Red-Team-style tests against the OWNED range, observe the telemetry, score detection coverage, and run the purple-team replay. Then tear it down.

Authorization is the whole job. Everything here happens on the owned range from the README range diagram, under the Phase 00 Rules of Engagement, with stop conditions and a deconfliction contact named before any technique runs. If you cannot name the owner, scope, stop conditions, and deconfliction contact for a step, you do not run it. Nothing in this guide is a live target, a payload, or a weapon — the labs themselves reason over synthetic metadata only.


0. The loop you are about to run

   pick actor (CTI)  →  select ATT&CK techniques  →  write procedures + success criteria + stop conditions
          │                                                          │
          ▼                                                          ▼
   build the plan (Lab 01)  ───────────────────────────────►  RUN on the OWNED range (Atomic-style)
          │                                                          │
          ▼                                                          ▼
   observe telemetry  →  score detection coverage  →  PURPLE-TEAM REPLAY (detect-tune-rerun-confirm)
          │                                                          │
          ▼                                                          ▼
   reconstruct the campaign (Lab 02)  →  evidence packet  →  TEARDOWN

This is one pass of threat-informed defense: emulate FIN-LATTICE, find the gaps in Meridian's detections, write the missing detections, confirm they fire, and leave them behind.


1. Stand up the authorized range

Use the isolated range from the README. The minimum for this phase:

Range zoneHostsRole in this phase
operatora Linux box you ownruns the emulation plan / Atomic-style tests
victimone Windows host (+ optional DC), one Linux hostwhere procedures execute; owned, snapshot-first
detectiona SIEM (Wazuh/Elastic) with Sysmon + ETW + Zeek/Suricatacollects telemetry; where you score coverage and write detections

Hard preconditions (Phase 00):

  • The range is isolated — no bridge to home, corporate, or public networks.
  • Snapshot every victim host before the run; you will revert after.
  • No real credentials, customer data, or personal data in any fixture, capture, or screenshot.
  • The deconfliction contact and stop conditions are written into the run sheet before step 1.
  • Egress is deny-by-default; the only "C2" is your owned framework to an owned host.

Verify telemetry is actually flowing before you attack (you cannot score coverage on a sensor that is not collecting):

operator → run a benign marker (e.g., `whoami` in a new shell on the victim)
detection → confirm Sysmon EID 1 (process create) for that shell arrived in the SIEM

If the marker does not show up, fix collection first. A blind sensor produces a false "gap."


2. Pick the actor and pull the CTI

For Operation Cedar Lattice the actor is FIN-LATTICE, a financially-motivated intrusion set. Pull its profile the way you would in a real engagement:

  • the actor's ATT&CK Group page (its documented techniques),
  • a CTID Adversary Emulation Plan if one exists for a comparable group,
  • vendor intel and M-Trends for sector relevance,
  • map each documented procedure up to a technique id (WARMUP Chapter 4).

FIN-LATTICE's profile for this run:

T1566  Phishing                       (initial-access)
T1059  Command and Scripting Interp.  (execution)
T1003  OS Credential Dumping          (credential-access)
T1021  Remote Services                (lateral-movement)
T1071  Application Layer Protocol C2  (command-and-control)
T1486  Data Encrypted for Impact      (impact)

That flat list is not the plan — it is the input to Lab 01.


3. Build the plan (Lab 01)

Feed the profile to the builder. The builder orders the techniques along the lifecycle, attaches a procedure stub + the telemetry each emits + a detection idea + success criteria, and computes coverage and gaps.

cd lab-01-emulation-plan-builder
LAB_MODULE=solution python3 -c "
import solution as s
for step in s.build_plan(['T1486','T1566','T1021','T1059','T1071','T1003']):
    print(step['step'], step['tactic'], step['technique'], '-', step['name'])
print('coverage:', s.coverage_summary(['T1566','T1059','T1003','T1021','T1071','T1486']))
print('gaps:', s.coverage_gaps(['T1566','T1059','T1003','T1021','T1071','T1486']))
"

Expected (deterministic, ordered along the lifecycle):

1 initial-access     T1566 - Phishing
2 execution          T1059 - Command and Scripting Interpreter
3 credential-access  T1003 - OS Credential Dumping
4 lateral-movement   T1021 - Remote Services
5 command-and-control T1071 - Application Layer Protocol
6 impact             T1486 - Data Encrypted for Impact
coverage: {'initial-access': 1, 'execution': 1, 'credential-access': 1, 'lateral-movement': 1, 'command-and-control': 1, 'impact': 1}
gaps: ('reconnaissance', 'resource-development', 'persistence', 'privilege-escalation', 'defense-evasion', 'discovery', 'collection', 'exfiltration')

Read the gaps line as a finding, not noise. It says: an emulation of FIN-LATTICE alone never tests Meridian's discovery, persistence, or exfiltration detections. That is a blind spot in your assessment (distinct from a blind spot in the defense) — and naming it is the staff-level move (WARMUP Chapter 5).


4. Turn each step into a run sheet entry

For every plan step, before you run anything, write down:

FieldExample (step 3, T1003)
Procedurerun the documented credential-access check against the owned host's marker store
Owned targetVICTIM-WIN-01 (snapshotted)
Telemetry expectedSysmon EID 10 — a handle opened to lsass.exe with suspicious access
Detection ideaCredential Guard; LSASS PPL; alert on LSASS handle opens
Success criteriaprocedure executes AND EID 10 observed; record detected / gap
Stop conditionone host only; read-only marker store; abort on any prod-adjacent signal; revert on completion
Deconflictionnamed SOC contact + run window; ping before and after

This is the run sheet. No step runs without all seven fields filled.


5. Run the procedures — Atomic-Red-Team style, on the OWNED range

You execute each technique as a small, scoped, ATT&CK-mapped test against your owned victim host — the Atomic Red Team model. The point is to emit the behavior the sensor sees, not to cause harm:

  • T1566 Phishing — deliver a seeded benign pretext from owned infra to a seeded mailbox in the range. (No live recipients, ever.)
  • T1059 Execution — run a benign loader-shaped command in a new shell on the victim.
  • T1003 Credential Access — run the documented check against a marker credential store (synthetic), so EID 10 fires without touching real secrets.
  • T1021 Lateral Movement — authenticate from the operator host to a second owned victim over an authorized admin protocol, producing a type-3 logon.
  • T1071 C2 — beacon from your owned C2 framework to an owned host over its documented profile.
  • T1486 Impact — model the impact stage with a benign marker (rename a canary file, delete a test shadow copy) — never real encryption, never real data.

After each, ping the deconfliction contact ("step N complete"). Snapshot/revert between destructive- shaped steps.


6. Observe the telemetry

For each step, go to the detection range and confirm the expected data source actually produced the event:

StepExpected eventWhere to look
T1566mail-gateway message metadata; mail-client child processgateway logs; Sysmon EID 1
T1059process-create + command lineSysmon EID 1; PowerShell 4104
T1003handle to lsass.exeSysmon EID 10
T1021logon type 3; SMB/RDP/WinRM flowEID 4624; Zeek conn log
T1071beacon periodicity; TLS fingerprintproxy/DNS logs; Zeek/Suricata; JA3/JA4
T1486mass file-rename; VSS deletionSysmon EID 11/23; EID 524

Record one of three outcomes per step (WARMUP Chapter 5):

DETECTED      data source present AND a rule fired
VISIBLE-ONLY  data source present, NO rule fired      → detection gap (costs a rule)
BLIND         data source NOT present                  → visibility gap (costs a sensor)

7. Score detection coverage

Build the coverage scorecard from the per-step outcomes. The simplest honest artifact is the ATT&CK Navigator layer colored by outcome:

T1566  DETECTED       (gateway flagged the pretext)         green
T1059  VISIBLE-ONLY   (EID 1 present, no analytic)          yellow → detection gap
T1003  DETECTED       (LSASS-handle rule fired)             green
T1021  VISIBLE-ONLY   (logon present, no lateral analytic)  yellow → detection gap
T1071  BLIND          (no egress/proxy logging on that VLAN) red    → visibility gap
T1486  DETECTED       (VSS-delete rule fired)               green

This scorecard is the Phase 01 portfolio artifact (alongside the plan). It is evidence, not belief — because it came from a live run, not a guess (WARMUP Chapters 5, 11).


8. Reconstruct the campaign (Lab 02)

Feed the observed events — scattered and out of order, as the SOC really sees them — to the reconstructor to produce the campaign narrative, the furthest stage reached, the earliest break point, and the Diamond pivot.

cd ../lab-02-killchain-campaign-reconstructor
LAB_MODULE=solution python3 -c "
import solution as s
evs = [
  s.Event('e5',500,'T1486',infrastructure='203.0.113.7',capability='LatticeCrypt'),
  s.Event('e1',100,'T1566',infrastructure='mail.evil.test',capability='LatticeLoader'),
  s.Event('e3',300,'T1021',capability='LatticeLoader'),
  s.Event('e2',200,'T1059'),
  s.Event('e4',400,'T1071',infrastructure='203.0.113.7'),
]
print('order:', [r['event_id'] for r in s.reconstruct(evs)])
print('furthest:', s.furthest_tactic(evs))
print('earliest break:', s.earliest_break(evs))
print('pivot on infra:', s.pivot(evs, on='infrastructure'))
print('pivot on capability:', s.pivot(evs, on='capability'))
"

Expected:

order: ['e1', 'e2', 'e3', 'e4', 'e5']
furthest: impact
earliest break: {'tactic': 'initial-access', 'technique': 'T1566', 'break_control': 'phishing-resistant MFA; SPF/DKIM/DMARC; user reporting'}
pivot on infra: (('e4', 'e5'),)
pivot on capability: (('e1', 'e3'),)

Read it as the report does: the actor reached impact; the cheapest place to have stopped it was initial-access (phishing-resistant MFA — "defend left"); and the Diamond pivot links the C2 event to the impact event (shared C2 203.0.113.7) and the phish to the lateral move (shared LatticeLoader), so the SOC should have connected those alerts into one campaign.


9. The purple-team replay

Now collapse the gaps. Sit red and blue together and run the per-technique loop (WARMUP Chapter 11) for every VISIBLE-ONLY and BLIND outcome from §7:

for each gap technique:
  1. red re-runs the Atomic-style test on the owned range
  2. blue watches their tooling live
  3. BLIND        → deploy/configure the sensor, then go to (1)
     VISIBLE-ONLY → write the detection rule now (Sigma-style)
  4. red RE-RUNS the technique → confirm the rule fires (regression)
  5. flip the Navigator cell yellow/red → green; record the rule id

Example for T1059 (visible-only → detection):

detection: process_creation where parent in (winword.exe, outlook.exe)
           and child in (powershell.exe, cmd.exe, wscript.exe)
red re-runs T1059 from a doc-shaped parent → rule fires → cell goes green → KEEP this rule

The durable output is the set of new, regression-confirmed detections the client keeps — the difference between "we got domain admin" and "you now detect FIN-LATTICE's techniques."


10. Evidence packet and teardown

Evidence packet (the sanitized, public-safe portfolio artifact):

  • the emulation plan (Lab 01 output): ordered steps, procedures, telemetry, detections, success criteria, stop conditions;
  • the ATT&CK Navigator layer: coverage + the gap map (§3) and the post-replay colored scorecard (§7);
  • the campaign reconstruction (Lab 02 output): order, furthest stage, earliest break, Diamond pivot;
  • the new detections written in the purple replay (§9), with their regression results;
  • a short narrative mapping the run to the Mandiant lifecycle for the executive briefing.

Hash every artifact at collection; record source, time, collector, timezone, and any transformation. Never include real targets, credentials, personal data, or any C2/payload artifact.

Teardown:

1. revert every victim host to its pre-run snapshot
2. tear down the owned C2 and phishing infra in the range
3. confirm deny-by-default egress is restored
4. ping the deconfliction contact: engagement window closed
5. archive the evidence packet to the isolated management network only

11. Expected observations (so you know it worked)

  • The plan comes back ordered along the lifecycle and deterministic — same input, same plan.
  • Every step ships a procedure, telemetry, a detection, and a success criterion (the pairing).
  • The gap line correctly lists the tactics FIN-LATTICE never exercises (recon, persistence, privesc, defense-evasion, discovery, collection, exfiltration, resource-development).
  • The campaign reconstructs to e1..e5; furthest = impact; earliest break = initial-access / T1566; the Diamond pivot links the two C2/impact events and the two loader events.
  • Each technique you ran produced its expected data source in the SIEM (or you found and fixed the visibility gap first).
  • After the purple replay, every VISIBLE-ONLY cell that you wrote a rule for flips to DETECTED on re-run — the regression proves the detection is real.

12. Common false claims (and the truthful version)

False claimWhy it's wrongTruthful version
"We emulated FIN-LATTICE." (ran a grab-bag of tests)emulation is actor-driven, ordered, intel-mapped"We ran the actor's documented TTPs in lifecycle order, mapped to ATT&CK."
"We have coverage of T1003 — it's green." (never ran it)belief is not evidence"On a live run the LSASS-handle rule fired; here is the SIEM event."
"No coverage of T1071." (sensor wasn't collecting)that's a visibility gap, not a detection gap"T1071 was BLIND — no egress logging on that VLAN; deploy the sensor, then re-test."
"Shared C2 proves it's the same actor."pivoting is evidence, not proof"These events pivot on shared infra 203.0.113.7; that links them; attribution needs more."
"We blocked the malware hash, so we're protected."bottom of the Pyramid of Pain — trivial to change"We added a behavioral detection for the technique; the actor can't evade it by recompiling."
"The purple session is done — we were all in the room."the loop is the point, not the room"For each gap we wrote a rule and re-ran the technique until it fired (regression-confirmed)."
"We reached impact, so the engagement succeeded."reaching impact is table stakes"We reached impact and identified the earliest break point and left tested detections."

If you can run this loop end to end on your own range — pick the actor, build the plan, run it safely, score honest coverage, reconstruct the campaign, and walk away with regression-confirmed detections — you have done the core of what Operation Cedar Lattice asks of Phase 01, and the core of what a Mandiant red team consultant does on a real adversary-emulation engagement.