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
One Detection, Four Surfaces: Sigma, PowerShell, KQL, SPL
You already know that the same idea can be said in different languages without changing what it means. A detection is no different. This sub shows one Kerberoast detection said four ways, so that when the course renders every detection across four tabs, you read them as one thing in four dialects rather than four things to learn.
Scenario
You work out a clean Kerberoast detection: a service-ticket request using RC4 for an account that is not krbtgt. Then reality intrudes. Your controllers can be queried directly with PowerShell. Half the company's logs sit in Splunk. The cloud team just stood up Sentinel and wants the same rule there. A colleague at another firm asks you to share it. Do you write and maintain four separate detections that drift apart over time, or is there a way to express the logic once and render it wherever it has to run?
This is the practical problem the four-surface model solves, and the previous subs set up the answer: write the detection once in a vendor-neutral form, then render it into the stacks you actually run.
This sub makes it concrete. You walk a single detection, the Kerberoast you just designed, across all four surfaces, so that when you meet detection tabs in every later module they are already familiar.
None of this is busywork. The first time you see a detection you wrote for Sentinel rendered as the Splunk search a colleague can run, the four-surface idea stops being a teaching device and becomes the thing that lets your work outlive the tool you happened to build it in.
The four surfaces are not arbitrary. Each exists because a real defender works in it. Sigma is the canonical, portable rule. Windows PowerShell with Get-WinEvent is the universal floor that runs on a controller with nothing installed. Sentinel KQL is for the Microsoft cloud SIEM. Splunk SPL is for the dominant enterprise SIEM.
Cover those four and you have covered how the overwhelming majority of defenders read Windows security telemetry, from the smallest under-instrumented shop to the largest SOC.
Think about who lives in each. The small manufacturer from the last sub has only the PowerShell floor, and it is enough. A Microsoft-centric enterprise runs everything through Sentinel and wants KQL. A large bank standardized on Splunk a decade ago and is not moving. And the detection-engineering community shares rules as Sigma, because no one can assume which of the others a reader uses. Four surfaces is not thoroughness for its own sake, it is the set you actually meet in the field.
The same Kerberoast, four ways
Below is the RC4 Kerberoast detection in all four surfaces. Read the Sigma first as the statement of intent, then notice that each of the others is the same three conditions, event is a service-ticket request, encryption is RC4, service is not krbtgt, in that tool's syntax.
The tabs here behave exactly like the ones throughout the course: click between surfaces, and the runnable ones execute against the lab corpus you meet in the next sub.
title: Kerberoasting - RC4 Service Ticket Requested
status: stable
logsource:
product: windows
service: security
detection:
selection:
EventID: 4769
TicketEncryptionType: '0x17'
filter_krbtgt:
ServiceName: 'krbtgt'
condition: selection and not filter_krbtgt
falsepositives:
- Legacy applications negotiating RC4
level: high
tags:
- attack.credential_access
- attack.t1558.003
Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4769} | ForEach-Object {
$d = ([xml]$_.ToXml()).Event.EventData.Data
[pscustomobject]@{
Time = $_.TimeCreated
User = ($d | Where-Object Name -eq 'TargetUserName').'#text'
Service = ($d | Where-Object Name -eq 'ServiceName').'#text'
Enc = ($d | Where-Object Name -eq 'TicketEncryptionType').'#text'
}
} | Where-Object { $_.Enc -eq '0x17' -and $_.Service -ne 'krbtgt' }
SecurityEvent
| where EventID == 4769
| where TicketEncryptionType == "0x17"
| where ServiceName != "krbtgt"
| project TimeGenerated, Computer, TargetUserName, ServiceName, TicketEncryptionType, IpAddress
sourcetype="WinEventLog:Security" EventCode=4769 Ticket_Encryption_Type="0x17" Service_Name!="krbtgt"
| table _time, host, user, Service_Name, Ticket_Encryption_Type, src_ip
What stays constant
Look at what does not change. Every surface keys on the same three facts, and it has to, because the detection is a claim about the world, not about a tool.
The event identifier is 4769 in all of them. The encryption type is the value 0x17, the RC4 tell. And each one excludes krbtgt, because a ticket for the ticket-granting service itself is normal and would flood the result.
What differs is only the spelling. Each platform names the same underlying Windows field its own way, and learning those small naming differences is most of what makes a detection feel hard to port.
Once you see that Ticket_Encryption_Type in Splunk and TicketEncryptionType in KQL are the same field off the same 4769, the translation stops being mysterious. That recognition is the skill this sub builds, and it is why the course shows you all four every time rather than picking one.
There is a fourth constant the queries handle quietly: success. A 4769 is logged whether the request succeeded or failed, and a Kerberoast is a successful request, so a tighter version of each query also filters on a success status. The point holds either way. The facts that define the attack are the same facts in every surface, and the query is just the local way of asserting them.
What each surface costs you
The four surfaces are equivalent in logic but not in what they demand, and choosing among them is a question of trade-offs worth naming now.
The PowerShell floor runs anywhere with nothing installed, which is its whole value, but it has no alerting and no retention of its own. You query the live log on one controller, so you see only what that controller still holds, and only when you run the command. It is perfect for hunting and for a small shop that schedules it, and poor as a standing alert across fifty controllers.
The two SIEM surfaces invert that. KQL and SPL both give you centralized collection, long retention, scheduled alerting, and correlation across sources, which is what you want for a real program. The cost is the ingest: events must be forwarded and stored, which is licensing and engineering you may or may not have.
Sigma sits above all of them as the portable record, but it is not itself runnable. It needs a converter or a human to render it into one of the others, so it is the thing you store and share, not the thing that fires.
The practical reading is that a mature program uses several at once. Sigma is the library you keep and version. The SIEM surfaces are where detections run day to day. PowerShell is the hunt tool and the fallback when the SIEM is behind or absent. None is the right answer in isolation, which is the deeper reason the course refuses to pick one for you.
In a real week that looks like this. You keep your detections as Sigma in a repository. Your SIEM runs the rendered KQL or SPL on a schedule and alerts you. When something odd surfaces, you drop to PowerShell on the controller to confirm it against the live log before you act. Three surfaces, one detection, each doing the job it is best at.
Anti-pattern
Maintaining four separate detections that drift. If you hand-write the Kerberoast rule independently in PowerShell, KQL, and SPL, they slowly diverge: someone tightens the KQL, nobody updates the SPL, and a year later the same attack is caught in one console and missed in another. Keep the Sigma as the single source of truth, render the others from it, and when the logic changes, change the canonical rule and re-render. One claim about the world, kept in one place.
Why canonical-first changes how you think
It would be possible to teach this course in KQL alone and mention the others in passing. The cost of that is that students learn a query language rather than a detection, and when they change jobs or tools, the knowledge does not travel.
Writing the Sigma first forces the opposite habit. You state what is true about the attack, the event and the fields and the values, and only then express it in a syntax. The syntax becomes interchangeable. The detection is the durable thing.
This is why the Sigma tab leads every detection block in the course and the runnable tabs follow. The order is a teaching choice: state the claim, then show how to run it. By the time you have done this a dozen times you will read any new detection by its Sigma first and treat the query forms as the easy part, which is exactly the instinct a portable detection engineer has.
That habit also makes you a better reviewer of your own rules. When the logic lives in the Sigma, a false positive is a question about the detection, did you scope it right, is there a legitimate source of RC4 you forgot, rather than about whether you typed the KQL correctly. You debug the claim about the world, not the punctuation.
Take the false positive the Sigma rule names, legacy applications negotiating RC4. When that fires, the fix is not in the query, it is in the detection. You confirm which service accounts legitimately still use RC4, decide whether to exception them or fix the account so it negotiates AES, and record that decision. Then you re-render the rule. Because the reasoning lived in the canonical rule, the decision flows to all four surfaces at once instead of being patched into one console and forgotten in the others.
Reading the result, not just the query
A detection is only half the skill. The other half is reading what it returns. When you run the KQL or SPL above against the lab corpus, you will not get a screen full of hits. You will get a small handful, because the corpus holds one intrusion and the detection is keyed on the field that isolates it.
That smallness is the signal. A handful of RC4 service-ticket requests for svc-sql, from a workstation that has no business requesting them, is the Kerberoast. If your version of the query returned hundreds of rows, you would know at once that you had keyed on the wrong thing, probably the event alone without the cipher.
So as you work through the course, read every result against a prediction. How many rows should this return, and for which accounts? When the answer matches, you understand the detection. When it does not, the gap is the lesson, and it is usually more instructive than the cases that go as expected.
How detection tabs and reveal mode work
Two pieces of mechanics, since you will use them constantly. The detection tabs you just used appear on most content subs from here on. The Sigma tab is always the canonical statement, the PowerShell tab is what you run with nothing but a controller, and the KQL and SPL tabs are runnable against the lab corpus.
You will also meet reveal mode on output blocks. When a sub shows a query and then its result, the result is often hidden behind a control until you click to reveal it.
That is deliberate. Predicting what a detection returns before you see the answer is how you learn to read telemetry, rather than nodding along to a result that looks reasonable in hindsight. Use it honestly: form the prediction, then reveal, and notice where you were wrong, because the gaps are where the learning is.
One habit to carry from here: never let a revealed result wash over you. Ask why each row is present, whether a row that should be there is missing, and what one benign change in the environment would do to the count. A detection you can interrogate that way is one you can trust in production. A detection you ran once and eyeballed is one that will surprise you later.
You now have the method: source-first evidence, a canonical rule, four renderings, run it against real data. What you do not yet have is the data. The next sub introduces the Northgate Engineering domain, the on-premises AD estate you defend for the rest of the course, including the deliberately weak accounts that make the intrusion possible.