Designing a detection from the primitive up, not the tool down
A working method for turning an attack technique into a rule that survives contact with a real attacker: find the primitive the technique cannot avoid, test whether the change is rare, weigh how cheaply it can be bypassed, and check it carries enough context to page someone over.
Every brittle rule I have inherited had the same flaw. It was written against a tool, not against the thing the tool does. Somebody saw mimikatz.exe in an incident, wrote a detection for the image name, and closed the ticket. That rule caught exactly one attacker: the one who did not rename the binary. Tie a detection to a string the attacker controls for free and you have shipped something with a half-life measured in the seconds it takes to type copy.
So when I build a detection now, I start somewhere other than the tool. This is how I get from an attack technique to a rule I am willing to wake an analyst over, and it is a method rather than a rule you can paste. I am writing it in first person because these are the questions I actually ask, in this order, at my desk on MDE with Sysmon 15 feeding a Splunk index.
Break the technique into its primitives
Pick a technique and ask what it physically has to do to the machine. Credential dumping from LSASS, T1003.001, is the example I keep returning to because it is honest about the split between a tool and a primitive. The tool might be ProcDump, Task Manager, comsvcs.dll, a signed driver, or a loader someone wrote last week. The primitive is narrower and far more stubborn: something has to open a handle to lsass.exe with rights to read its memory, and something has to carry that memory off the box or parse it in place. Rename every tool you like. That handle still gets requested.
A primitive is the change the technique cannot skip. Find it and you have the spine of a resilient rule. Miss it and you are playing whack-a-mole with filenames. Most techniques decompose into two or three primitives chained together, and usually one of them is much harder for an attacker to vary than the others. That is the one you build on.
Ask whether the change is actually rare
Finding the primitive is not enough, because plenty of primitives are also things Windows does ten thousand times an hour. A file landing in %TEMP% with a .tmp extension is a real thing malware does and a real thing every legitimate installer on earth does. If the change is common under normal conditions, it cannot carry an alert on its own no matter how central it is to the attack.
So the second question is about frequency, and the honest way to answer it is to go count. I pull a week of the candidate telemetry from a representative slice of the fleet and see how often the primitive fires with nothing bad attached. If it fires thousands of times a day across finance laptops and build servers, it is a hunt input, not an alert. If it fires three times a week and every instance is explainable, now we are talking. This is the step people skip, and skipping it is why a SOC drowns.
Weigh how cheaply they can route around it
Assume the attacker reads your rule. It costs nothing to assume it and it changes how you build. For any detection I sketch, I ask what the cheapest bypass is and how much it costs them in capability or noise. Detecting an LSASS dump by watching for a file literally named lsass.dmp is the low end: the bypass is renaming the output, which costs them nothing and buys them everything. Watching the handle request into lsass.exe with a suspicious access mask, the approach behind catching ProcDump or Task Manager reaching into a protected process, is the high end: routing around that means not touching LSASS memory at all, which pushes them toward a genuinely different and usually noisier technique.
I call this resilience, and I grade it roughly, not with a spreadsheet. High resilience means the bypass forces a real change in behavior. Low resilience means the bypass is a rename or a flag. A low-resilience rule is not worthless, it just needs to be understood as a tripwire for the lazy, and paired with something sturdier underneath. Know which one you are shipping.
Context: one technique, or a hundred?
The last question is whether the signal, even when rare and resilient, actually tells the analyst anything. rundll32.exe launching with no command-line arguments is unusual. It is also consistent with a dozen unrelated techniques and a handful of odd but benign vendor behaviors. On its own it says “something weird happened” and nothing more, and “something weird” at 3am with no direction is how alert fatigue is manufactured.
Context is what turns a weird-thing signal into an actionable one. Sometimes the primitive carries its own context, like an access mask that only makes sense for reading memory. More often you get context by joining: the rare parent, the user who should never do this, the host that has no business running developer tooling. A signal that could belong to a hundred techniques needs a second field to narrow it before it earns a page. A signal that already points at one specific bad thing can stand alone. This is the same discipline behind designing abnormal child-process rules without production telemetry, where the whole game is proving a parent-child pair is rare enough and specific enough to alert on.
Write it down so the next person can argue with it
Here is the part that keeps a detection alive past the day I wrote it. I write down, next to the rule, the technique it targets, the primitive it keys on, its resilience grade, the known false positives, and the frequency I measured. Not for tidiness. For the next engineer, who will inherit this rule the way I inherit everyone else’s, and who deserves to know what I was thinking so they can tell me I was wrong.
A rule with that context attached can be tuned. A rule that is just a Sigma condition with no reasoning behind it gets muted the first time it is inconvenient, because nobody remembers why it exists. If you want a shared vocabulary for capturing this, the Palantir Alerting and Detection Strategy framework is the cleanest public template I have used, and mapping each rule back to a MITRE ATT&CK data source forces you to admit what telemetry you are actually relying on.
None of this is fast, and that is the point. A detection built primitive-first, frequency-tested, resilience-graded, and context-checked takes an afternoon instead of ten minutes. It also survives the attacker renaming their binary, which the ten-minute version never does. I would rather ship three of these a month than thirty tripwires that catch nobody. This is part one of how I think about it, and I will come back to the harder cases, the ones where the primitive itself is common and you have to earn the detection entirely through context, in a follow-up.
detection-engineeringthreat-huntingmethodologysysmon