Reading width
Wide uses the full column for everything, text, diagrams, code, and exercises. Narrow keeps the standard reading width.
Text size
Scales the body text. Headings and code blocks keep their size.
In this section
0.5 How Tests Are Practiced Here
Introduction
The attacker leads in every lesson, and this lesson explains how the course turns that into practice. Each lesson follows the order of a purple team round: the plan, the operator's procedure, what it left, the variant the operator would try next, and then the defender's half, worked from the recording one record at a time.
Each lesson ends with a case you work in the console and a lab you run in your own environment. Three staged assessments and a course exam check the work along the way.
The course practices in two places on purpose. The recording gives everyone the same answers, so a lesson can show you a result and you can check your reading against it.
Your own lab gives you the real experience of running a procedure and finding out what your defense does with it, which no recording can. Each is weak where the other is strong, and the course uses both in every module from Module 3 onward.
This lesson also counts what the engagement's operator actually ran: the kinds of procedure, the lookalikes and the retests. Those counts are a fair picture of what a working purple team does in a fortnight, and they set expectations for what you will do yourself.
Plan the round
The rules every lesson followsThe course's own rules, the ones every lesson keeps:
The decision line is a promise the course makes to you. Every number in a lesson came from a query, and the query is printed above it; every query runs in the console; the result you get is the result the lesson shows. If a lesson ever disagrees with what the console returns, the lesson is wrong, and the console is how you find out.
Every lesson walks the same sections in the same order, so after the first few you will know where to look for each part:
1 Plan the round
2 The attack
3 Run it
4 The variant
5 Detection follows
6 to 9 The lesson's subject
10 Validate
11 Adapt
Case and lab
The sections are numbered on the page, and the numbering is stable: section 1 is always the plan, section 10 is always the validation. A student who wants to revise how the course reads a rule repair can open section 10 of any lesson in Module 7 and find a first try, its flaw and the refined query, every time.
The rules also explain what the course leaves out. There is no exploit development and no evasion tradecraft, because the procedures are documented and run in the open, and a purple team's skill is in choosing and reading them. There is no vendor marketing either: the range's rules are small enough to read, and every one of them is shown in full wherever it matters.
The attack: a masquerade, and the ordinary activity beside it
Atomic T1036.003 test 5, and the lookalike that tests its repairHow tests are practiced here is easiest to see in one pair. On Thursday 24 September the operator ran Atomic Red Team's T1036.003 test 5, Masquerading, powershell.exe running as taskhostw.exe, GUID ac9d0fc3-8aa8-4ab5-b11f-682cd63b40aa:
copy %windir%\System32\windowspowershell\v1.0\powershell.exe ^
%APPDATA%\taskhostw.exe /Y
cmd.exe /K %APPDATA%\taskhostw.exe
It copies PowerShell into the user's roaming profile under the name of a Windows task host and runs it, the trick an intruder uses to hide a tool among system processes. Thirty minutes later the operator ran a lookalike: an ordinary monthly update started through the update orchestrator, which runs a genuine Windows binary from outside System32, the thing the repaired rule must not alert on.
PS C:\> $g = 'ac9d0fc3-8aa8-4ab5-b11f-682cd63b40aa'
PS C:\> $log = 'C:\PurpleArtifacts\art.csv'
PS C:\> Invoke-AtomicTest T1036.003 -TestGuids $g -ExecutionLogPath $log
PS C:\> Invoke-AtomicTest T1036.003 -TestGuids $g -Cleanup
PS C:\> UsoClient StartInstall
Every procedure in the course is one of four kinds, and the pair shows two of them. The test log, grouped by kind:
From the operator's seat the engagement was four kinds of procedure. The test log, grouped by kind:
PurpleTestLog_CL
| where TimeGenerated < datetime(2026-09-30)
| summarize Tests = count() by Kind = case( isnotempty(AtomicTestGuid),
"Atomic test by GUID", AtomicTestName startswith "Caldera", "Caldera operation",
AtomicTestName startswith "Lookalike", "Lookalike", "Custom procedure")
| order by Tests desc
Four kinds, most of them Atomic tests run by their GUID:
Kind Tests
------------------- -----
Atomic test by GUID 52
Custom procedure 20
Caldera operation 4
Lookalike 2
The proportions are typical. Most of a purple team's tests are single published procedures, because they are quick, documented and repeatable; a smaller number are adaptations to the estate, because no public library knows your tenant's roles or your server's names; and a few are chained operations, because some questions are about sequence rather than single steps.
Atomic Red Team supplies the majority: small documented tests, each identified by a GUID, each with its own cleanup, run through Invoke-AtomicTest. A test run by GUID today is exactly the same procedure next month, which is what makes a retest meaningful.
Custom procedures are the next largest group: Atomic tests adapted to the range, such as a role assignment ported to Microsoft Graph, and the operator's own variants, each with its exact command in the test log.
Every procedure the course runs is chosen from a public source or derived from one, and the test log names the source. That matters beyond the course: a team that runs its own exercises should be able to say, for every test, where the procedure came from and why it was chosen, and the habit starts with the first test you log.
Caldera supplies the chained operations, where an agent on the workstation runs a sequence of abilities under a planner, one link at a time. The lookalikes are the smallest group and in some ways the most important: ordinary activity, run on purpose, to prove that a repaired rule leaves it alone.
Run it: the test and its lookalike, side by side
What each left, and what each raisedThe two runs, as the workstation recorded them, with the rule that answered each:
union
(DeviceProcessEvents
| where FileName in ("taskhostw.exe", "powershell.exe")
| where FolderPath !startswith @"C:\Windows\System32"
| project T = Timestamp, Record = FileName, Detail = FolderPath),
(SecurityAlert | where AlertName startswith "PU-R15"
| project T = TimeGenerated, Record = "Alert", Detail = AlertName)
| where T between (datetime(2026-09-24T10:00:00Z) .. datetime(2026-09-24T10:45:00Z))
| order by T asc
The masquerade and the update, each with its process, its folder and the alert that followed:
Time Record Detail
-------- -------------- ----------------------------------------------
10:00:07 taskhostw.exe C:\Users\pt.operator\AppData\Roaming\taskho...
10:05:06 Alert PU-R15 Windows program running outside Syst...
10:36:00 powershell.exe C:\Windows\WinSxS\amd64_microsoft-windows-p...
10:41:00 Alert PU-R15 Windows program running outside Syst...
PU-R15 version 2 alerted on the masquerade five minutes later, which is the repair working. It also alerted on the update, eleven minutes after it, which is the repair's false positive: servicing runs PowerShell from the component store, outside System32, and version 2 had not been told.
Version 3 was written that day. Neither result would be known without the lookalike, logged with its own row so the defender knew when the ordinary activity happened. The lookalikes in the recording:
The lookalikes are where the operator's discipline is easiest to see. Both of them:
PurpleTestLog_CL
| where TimeGenerated < datetime(2026-09-30)
| where AtomicTestName startswith "Lookalike"
| project TimeGenerated, TestId, AtomicTestName
Two lookalikes in the whole recording, and both on the retest day:
Time TestId Test
---------------- ------- ----------------------------------------------------------
2026-09-24 10:30 PT-0804 Lookalike for PU-R15 v2: the monthly cumulative update ...
2026-09-24 09:30 PT-0802 Lookalike for PU-R16 v2: one account retrying an old pa...
Running a lookalike is a deliberate act with its own row in the test log, because the defender needs to know when the ordinary activity happened in order to check the rule ignored it. A lookalike that is not logged leaves the defender guessing which of the day's ordinary records was the one meant to stay silent.
Each lookalike was run beside the repaired rule it was meant to test, and each is named for that rule.
One is a user retrying an old password through one client from several addresses, which a spray rule must not mistake for a spray; the other is a monthly Windows update, which a masquerade rule must not mistake for a renamed binary. Both are the kind of thing that happens every day in a real estate and that a hasty repair would alert on.
The two run here are deliberately ordinary, which is harder than it sounds. A lookalike invented to be easy for the rule to ignore proves nothing; one copied from what the estate really does every week proves that the rule will survive contact with production. The operator picks lookalikes from the recording's own background wherever possible.
The range also has lookalikes that nobody runs: the nightly inventory task, the helpdesk's directory queries, Group Policy writing its settings. They are in the recording as background, and every repair in the course is tested against them as well as against the operator's two.
The variant: the same pair, in your own lab
How every practice in the course is runEvery lab in the course asks you to run the operator's procedure in your own isolated lab, and then the ordinary activity that tests your rule. For this pair:
PS C:\> $log = 'C:\PurpleArtifacts\art.csv'
PS C:\> Invoke-AtomicTest T1036.003 -TestGuids $g -ExecutionLogPath $log
PS C:\> Invoke-AtomicTest T1036.003 -TestGuids $g -Cleanup
PS C:\> UsoClient StartInstall
The first two lines are the attack and its cleanup; the third is the lookalike, which on your own workstation can be any genuine update or servicing run you start on purpose and note the time of.
Your records will differ from the range's, and the labs are written so that a different result is something you interpret, not a failure. The operator has a reason for putting this half first in every lesson:
Every lesson puts the operator's half first, and the operator has a reason for insisting on it:
The first line is the one that changes how a defender works. A dashboard shows what fired, and so it shows only the tests the defense noticed. Starting from the operator's record shows every test, including the ones that left no alert, and those are where the exercise is worth its time.
The order also protects the defender from a quieter error: reading the defense's records with the conclusion already in mind. A defender who starts from an alert looks for evidence that the alert was right. One who starts from the operator's row looks for whatever the test left, and is as ready to find a silence as an alert.
The variant is the operator's contribution to every repair. A defender who fixes a rule against the procedure that beat it has closed one door; the operator's variant asks whether the next door is open, and a lesson that ends without one has stopped halfway.
Detection follows: the verdicts
What the defense decided, countedThe defender's half of every lesson ends at the verdict, and the engagement's verdicts are a useful first picture of the defense:
SecurityIncident
| where CreatedTime < datetime(2026-09-30)
| summarize Incidents = count() by Classification
Twenty-three incidents, by the classification each was closed with:
Classification Incidents
-------------- ---------
BenignPositive 8
TruePositive 14
FalsePositive 1
Fourteen true positives, eight benign positives and one false positive. The count alone looks healthy, and it hides what the course cares about.
Among the benign positives are verdicts like PT-0104's, right in conclusion and weak in basis, and at least one that was simply wrong: an analyst who closed a masquerade test as the real program it imitated. Reading every comment is the only way to find them, and the course does it for every incident it quotes.
The false positive is worth a word as well. It is the one incident in which a rule fired on activity that was neither the test nor what the rule was written for, and it is the kind of verdict a repair can cause if it is broader than it needs to be. The course's negative tests exist to catch that before deployment rather than after.
Alerts that never became incidents are not in this count at all. Lesson 0.1's PT-0103 is one of them. A purple team counts those separately, because an alert nobody opened is a different gap from an incident closed wrongly.
Practice in your own lab
The procedures, run where you can see everythingFrom Module 3 onward each lesson ends with a lab in your own environment. You build a small range of your own in Lessons 0.7 to 0.11, at the end of this module: a Windows endpoint, a domain and a Linux host, the platforms that record them, and Atomic Red Team and Caldera, each part proved by an attack.
The build covers two stacks: Microsoft Defender with Sentinel, if you can get a trial, and a free stack built on Wazuh, with Splunk Free for the course's SPL forms and Elastic as an alternative.
The two stacks, and what each gives you:
Either stack works for every lab in the course. The Microsoft stack lets you paste the course's KQL directly; the free stack asks you to translate, which is good practice and is why every rule is also given in Sigma. Choose the one you can run reliably, because a lab that is down when you need it teaches less than a smaller one that is always ready.
Your lab will not produce the recording's results, and it should not. Different hardware, different versions and a different configuration mean that the same Atomic test can leave a different record, or none, and finding that out is the point.
The labs ask you to run a procedure, read what your environment did with it, and compare that with what the recording shows the range did. The differences are where you learn how your own defense behaves.
Each lab follows the same three steps: emulate, investigate, validate. You run the procedure as the operator, read what your environment recorded and alerted as the defender, and then check your reading against the recording's version of the same test. The lab's page tells you what the range produced, so you can see where your lab agreed and where it did not.
Every lab is designed so that a missing alert, missing telemetry or a blocked test is a result you interpret, never a failure of the exercise. A lab that produces nothing in your environment has still told you something: which step your defense cannot see.
Staged assessments and the exam
Three recorded days you have not seen, and one examThree times in the course the practice is checked on a recorded day you have not seen, in the platform's staged assessment console:
The assessments are optional in the sense that the course does not stop you from moving on without them, and essential in the sense that they are the only place the course checks your reading on a day you have never seen. Taking each one at the end of its module, while the lessons are fresh, is the best way to find out which habits have stuck.
Each staged assessment is a day the lessons never quote, so it is a genuine first look. Its stages follow the lessons' order, one of them always in the operator's seat, and the stages that ask you to repair a rule mark your rule by what it returns on the day, not by its wording: any repair that returns the right records and leaves the lookalikes alone passes.
The course exam comes at the end. It asks one question per teaching module, each answered by writing a query against the recording, and it issues a certificate on a pass. Nothing in the exam is printed in a lesson or in a resource page; every answer is something you find.
Three forms of every detection
KQL, SPL and Sigma, on the same eventsEvery rule the course writes or repairs is given in three forms. One of the range's rules, as every lesson shows it:
DeviceEvents
| where ActionType == "ScheduledTaskCreated"
| extend TaskName = tostring(parse_json(AdditionalFields).TaskName)
| where not(AccountName == "SYSTEM" and TaskName startswith @"\Microsoft\")
| project Timestamp, DeviceName, AccountName, TaskName, InitiatingProcessFileName
index=defender sourcetype="ms:defender:eventhub/deviceevents"
ActionType="ScheduledTaskCreated"
| spath input=AdditionalFields path=TaskName output=TaskName
| search NOT (AccountName="SYSTEM" TaskName="\\Microsoft\\*")
| table _time DeviceName AccountName TaskName InitiatingProcessFileName
title: 'PU-R02 Scheduled task created, by any means (version 2)'
id: bf5a4f4f-8feb-5c75-aa36-e3f0171c7e84
status: experimental
description: The Sigma source of PU-R02-v2. KQL and SPL are its deployed forms.
author: Ridgeline Cyber
date: 2026-10-30
tags:
- attack.execution
- attack.persistence
- attack.t1053.005
logsource:
product: windows
service: security
detection:
selection:
EventID: 4698
filter_builtin:
SubjectUserSid: 'S-1-5-18'
TaskName|startswith: '\Microsoft\'
condition: selection and not filter_builtin
falsepositives:
- Software that registers its own tasks outside \Microsoft\
level: medium
KQL is the form the range runs, in its Sentinel and Defender workspace. SPL is the same rule for a Splunk deployment, over the recording's Splunk form. Sigma is the portable source, which converts to either. The course's rule checker runs every form over the same events and fails if any of them disagree, so the three tabs always describe one detection.
Sigma's role is easy to underrate. A team that writes its detections in Sigma first can move them between platforms, review them without knowing the target query language, and keep one history for a rule that runs in several places. The course's repairs are written so that the Sigma form is readable on its own, and its KQL and SPL forms are what each platform actually runs.
You do not need all three languages to take the course. The lessons default to KQL, explain each SPL and Sigma form where it matters, and the case questions can be answered in KQL. If your own lab runs Splunk, Elastic or Wazuh, the SPL and Sigma forms are the ones you will translate from.
Retests
How a repair is provedA repair is not finished until the procedure that found the gap is run again and the defense answers it. The engagement's retests, each named for what it repeats:
PurpleTestLog_CL
| where TimeGenerated < datetime(2026-09-30)
| where AtomicTestName startswith "Retest of"
or AtomicTestName has "rerun"
| project TimeGenerated, TestId, AtomicTestName
| order by TimeGenerated asc
The tests named as retests or reruns of an earlier test:
Time TestId Test
---------------- ------- --------------------------------------------------------
2026-09-24 09:00 PT-0801 Retest of PT-0602: the MSOLSpray split across five so...
2026-09-24 11:30 PT-0806 Retest of PT-0607 step 2: user consent to a multi-ten...
2026-09-24 13:00 PT-0807 Retest of PT-0604: a client secret added to the repor...
2026-09-24 15:00 PT-0808 Retest of PT-0608: Entra sign-in from a new address, ...
2026-09-29 10:40 PT-1105 Service Installation CMD (rerun after the audit fix)
A retest is also the point where the two seats' records meet most directly. The operator's row says the same procedure ran again; the defender's records say what the defense did with it this time; and the comparison with the original is the result. Nothing in a retest is new except the outcome, which is exactly what makes the outcome trustworthy.
Naming each retest for its original is what makes the before and after a query rather than a memory. The course's repairs all end this way, and the capstone's last phase is a day of them. Every repaired rule keeps its old version beside the new one, and several carry the version in their alert names, so a reader can see which version fired on which day:
SecurityAlert
| where TimeGenerated < datetime(2026-09-30)
| where AlertName matches regex @"^PU-R\d+ v\d"
| summarize Alerts = count() by Version = extract(@"^(PU-R\d+ v\d)", 1, AlertName)
| order by Version asc
The rule versions that have alerted, each under its own name:
Version Alerts
--------- ------
PU-R02 v2 2
PU-R12 v2 3
Version names also make the recording's history honest. A count of PU-R02 alerts that mixed version 1 and version 2 would credit the repair with alerts the old rule raised, or blame it for silences the old rule caused. Keeping the version in the name, or in the rule's file and its live date, keeps the two apart.
The course's repairs are small: usually one condition changed per defect, with the rest of the rule kept. That keeps each version's history readable and makes its retest meaningful.
Validate
A run by its count, and by its targetsThe obvious way to describe a run is by how many tests it had:
PurpleTestLog_CL
| where Run == 1
| countPurpleTestLog_CL
| where Run == 1
| summarize Tests = count() by TargetHostThe same habit applies to everything the course counts. Seventy-eight tests says little; seventy-eight tests across three hosts and a tenant, fifty-two of them repeatable by GUID, two of them lookalikes and several of them retests, says what the engagement could and could not show. Every count in the course is followed by the breakdown that gives it meaning.
The refined read is the course's habit of describing work by what it covers rather than how much of it there is. On the chain both seats use, the course's practice reads:
Outcome chain
How the course practicesWhat the course asks of you
In every module from Module 1.
- Run documented procedures and record them exactly.
- Read the records, the rules and the verdicts, in that order.
- Prove every repair on its attack, its lookalike and its retest.
A method practiced in two places: the recording for the answers, your lab for the experience.
Keep the chain in mind as you start Module 1. Its rows are the steps every lesson walks, in the same order.
Adapt: four kinds of procedure
And what each leaves in the operator's recordThe four kinds of procedure leave different records for the defender to reconcile:
Atomic test by GUID
Custom procedure
Caldera operation
Lookalike
Knowing which kind a test is tells the defender where to look for its execution evidence before looking for anything else. An Atomic test's first stop is the execution log; a custom procedure's is the first process or audit record its command produces; a Caldera operation's is its link records; a lookalike's is the ordinary record it was meant to produce.
An Atomic test is repeatable by its GUID and records its own exit code in the execution log. A custom procedure is repeatable from its exact command, and its outcome is read from the defense's records.
A Caldera operation records each link's timing and status, and is repeated from its adversary profile and settings rather than exactly. A lookalike is repeatable and records nothing of its own, because it is meant to look like nothing. You will run all four in your lab before the capstone.
See how the engagement was practiced
The case is short, as Module 0's are, and it is the last before the course's own modules begin. From Module 1 each case starts with a step in the operator's seat and ends with the defender's verdict, in the order this lesson has described.
The case below counts what the operator ran, the lookalikes, the verdicts and the retests. Work in the platform's Advanced hunting console with the Purple Range selected.
The third answer is the one to revisit after Module 8, when you have read the comments behind those verdicts; the count will look different once you have.
Practice
Plan how you will work the course your labThe practice is in the console, against the recording; your own lab is built in Lessons 0.7 to 0.11.
Choose a stack
Microsoft Defender with Sentinel, or Wazuh or Elastic, for the lab you build in Lessons 0.7 to 0.11.
Check access
That you can run Atomic Red Team on an isolated Windows machine you control.
Plan the assessments
When you will take each staged assessment, at the end of Modules 5, 7 and 10.
Pick a language
KQL, SPL or Sigma as your main form, and the one you will translate from.
What you should end up with: A short plan: your stack, your lab, your assessment dates and your query language.
Resources
Publishers revise these pages; where a page and this lesson disagree, the page is newer.