TTPs & the Pyramid of Pain
Detect behavior, not disposable indicators.
A burglar can swap gloves in a second. Making them leave no fingerprints costs them nothing, so they do it without thinking twice. Now make them give up the one trick they know for popping a window latch. That is expensive. They have to relearn the job. Detection engineering has exactly this shape. An indicator of compromise (IOC), meaning one specific artifact tied to one attack such as a file hash, an IP address or a domain name, is the glove. A tactic, technique or procedure (TTP), meaning the way an attacker actually gets the job done, is the craft. Detect the glove and they change gloves. Detect the craft and they have to change how they work. This lesson is about moving your detections up from the gloves to the craft, and then proving they fire.
The pyramid, one tier at a time
David Bianco published the Pyramid of Pain in 2013. It ranks the *types* of indicator you can build a detection on by how much pain, meaning cost and effort and lost time, you inflict on the attacker when you take that indicator away from them. Start at the bottom. Hash values are *trivial*: flip one byte, recompile, and the hash is brand new. IP addresses are *easy*: rotate through a cloud VPS (virtual private server, a rented machine you can throw away) or through Tor. Domain names are *simple*: register another one, or have the malware generate them algorithmically. Then you cross a line. Host and network artifacts are *annoying*, because they are the user-agent strings, named pipes, service names and registry keys the tooling leaves behind whether the operator wants it to or not. Tools are *challenging*, because now the attacker has to find or build a replacement for Mimikatz. At the top sit TTPs, rated *tough*, because that tier is the behavior itself. The three tiers above the line are where durable detections live. An artifact, a tool or a technique costs real time and real skill to change.
None of that makes hashes and IP addresses worthless. The claim is narrower. A detection keyed to a hash expires the moment the attacker changes anything at all, while a detection keyed to a technique survives them re-tooling completely. So put the bulk of your engineering hours near the top, where every rule you ship forces the adversary into an expensive rethink instead of a five-second swap.
The same threat, written two ways
The difference stops being abstract the moment you write both queries side by side. Below, one threat appears twice: an attacker dumping credentials out of LSASS (Local Security Authority Subsystem Service, the Windows process that holds logon secrets in memory). Both versions are KQL (Kusto Query Language), the language behind Microsoft Defender and Sentinel advanced hunting. The brittle version pins itself to a hash and an IP address. The durable version pins itself to the behavior described by MITRE ATT&CK (Adversarial Tactics, Techniques and Common Knowledge, the public catalog of attacker behavior) technique T1003.001: a non-system process opening a handle to lsass.exe. Read the result rows under the durable query. One attacker used procdump. The other used a comsvcs.dll living-off-the-land trick, meaning they abused a component Windows already ships instead of bringing their own tool. One technique-level rule caught both. That is the pyramid paying off.
// BRITTLE — bottom of the pyramid (Hash / IP). Returns 0 rows the instant// the attacker recompiles or moves to a new server.DeviceFileEvents| where SHA256 == "a3f0c7e1b28d...9f" // one recompile -> new hash -> no matchDeviceNetworkEvents| where RemoteIP == "203.0.113.5" // one new VPS -> no match// DURABLE — top of the pyramid (TTP: T1003.001 OS Credential Dumping: LSASS Memory).// Detect the behavior: a non-system process opening a handle to lsass.exe.DeviceEvents| where ActionType == "OpenProcessApiCall"| where FileName =~ "lsass.exe"| where InitiatingProcessFileName !in~ ("MsMpEng.exe","wininit.exe","csrss.exe")| project Timestamp, DeviceName, InitiatingProcessFileName, InitiatingProcessCommandLine// Timestamp DeviceName InitiatingProcessFileName InitiatingProcessCommandLine// 2026-07-13T09:14:22Z FIN-WKS-07 procdump64.exe procdump64.exe -ma lsass.exe out.dmp// 2026-07-13T11:02:51Z DC-01 rundll32.exe rundll32 comsvcs.dll, MiniDump 640 c:\t.dmp full// -> two different TOOLS, one TECHNIQUE, one rule catches both.
The bill for that resilience is visible in the same query. The durable version needs rich endpoint telemetry, specifically process API call events (the operating system's record of one program asking for access to another), which not every agent collects and not every agent forwards. It also needs an allow-list of the software that legitimately reads LSASS, or your own antivirus will bury you in matches. IOC queries are cheap and need almost no context around them. TTP queries buy durability with data volume and tuning time.
Fire the technique at yourself before you trust the rule
A smoke alarm nobody has ever tested is decoration. A detection you have never watched fire is a hypothesis, not a control. Atomic Red Team is an open-source library from Red Canary of small, self-contained tests, each one mapped to an ATT&CK technique, and it exists so you can reproduce a behavior safely on a lab host and check whether your rule wakes up. The runner is a PowerShell module called invoke-atomicredteam. Run the atomic for T1003.001, watch your KQL rule light up, and you have closed the purple-team loop (red-team behavior and blue-team detection checked against each other): emulate, detect, verify.
# Install once (Red Canary's runner + YAML parser)Install-Module -Name invoke-atomicredteam, powershell-yaml -Scope CurrentUser -ForceImport-Module invoke-atomicredteam# What does technique T1003.001 actually test?Invoke-AtomicTest T1003.001 -ShowDetailsBrief# PathToAtomicsFolder = C:\AtomicRedTeam\atomics# T1003.001-1 Dump LSASS.exe Memory using ProcDump# T1003.001-2 Dump LSASS.exe Memory using comsvcs.dll# T1003.001-3 Dump LSASS.exe Memory using direct system calls and API unhooking# Confirm the test can run here, then fire test #1 in your LAB onlyInvoke-AtomicTest T1003.001 -TestNumbers 1 -CheckPrereqs# Prerequisites met: T1003.001-1 Dump LSASS.exe Memory using ProcDumpInvoke-AtomicTest T1003.001 -TestNumbers 1# Executing test: T1003.001-1 Dump LSASS.exe Memory using ProcDump# Done executing test: T1003.001-1 Dump LSASS.exe Memory using ProcDump# Always remove the artifacts the test dropped (the .dmp file, etc.)Invoke-AtomicTest T1003.001 -TestNumbers 1 -Cleanup
Within seconds, your OpenProcessApiCall query should return the emulation host. Be precise about what that proves. A detection firing is a claim that something matched your logic; an incident is a human confirming the match was real and mattered. Here you already know the answer, because you caused it. If nothing comes back at all, you have found a gap, and that gap is the most useful thing you will produce all week. Maybe the telemetry from that host was never onboarded. Maybe your allow-list is so broad it swallowed the test. Either answer beats a rule that reads convincingly in review and has never once fired.
Tag every rule, then count what you actually cover
MITRE ATT&CK files adversary behavior the way a library files a book by subject, then title, then edition. Tactics are the goal (Credential Access, TA0006). Techniques are how the goal gets reached (OS Credential Dumping, T1003). Sub-techniques are a specific variant (T1003.001, LSASS Memory). Procedures are one real crew's real implementation. Tag every detection you write with its technique ID and the fuzzy question "are we covered?" becomes arithmetic: for each technique that matters in your environment, is there a rule, and has it ever fired? Here is a five-second coverage tally across a Sigma rule repository (Sigma being the vendor-neutral rule format you convert into whatever your SIEM, or security information and event management platform, actually speaks), followed by an ID-to-name lookup with the current mitreattack-python library so you can put a name on the gap you found.
# How many unique ATT&CK techniques do our Sigma rules cover today?grep -rhoE 'attack\.t[0-9]{4}(\.[0-9]{3})?' rules/ | sort -u | wc -l# 147# Which Credential Access sub-techniques under T1003 do we actually detect?grep -rhoE 'attack\.t1003(\.[0-9]{3})?' rules/ | sort | uniq -c# 9 attack.t1003.001 <- LSASS Memory (well covered)# 2 attack.t1003.002 <- Security Account Manager (SAM)# (nothing for t1003.003 NTDS.dit -> that is your coverage gap)# Resolve the gap's ID to a human name so you can prioritise itpip install mitreattack-pythonpython - <<'PY'from mitreattack.stix20 import MitreAttackDatamad = MitreAttackData("enterprise-attack.json") # download once from MITRE CTIprint(mad.get_object_by_attack_id("T1003.003", "attack-pattern").name)# NTDSPY
Feed those technique IDs into ATT&CK Navigator and you get a heat-map layer leadership can read at a glance. Then overlay DeTT&CT, which scores how much visibility your data sources give you, because an uncovered technique often has nothing to do with a missing rule. Sometimes the log you would need never reaches you in the first place. Telling those two failures apart is what separates a real coverage program from a rule count.
What climbing the pyramid costs you
Climbing is not free. TTP detections want richer and pricier telemetry (full process command lines, API calls, authentication events) and far more tuning, because an administrator doing their job and an attacker doing theirs often look identical at the event level. Top-tier rules trend noisy and need behavioral context around them before they earn the right to page anyone. The pyramid ranks durability, not detectability: some techniques are effectively invisible unless you collect one specific data source, which is why a coverage gap so often turns out to be a telemetry gap. The tiers are not a strict ordering either. A rare host artifact used by exactly one crew can hurt more than a generic technique thousands of people use. The grown-up posture is layered. Keep cheap, high-confidence IOC blocking at the perimeter, because a known-bad hash should still be denied instantly, and spend your detection-engineering hours further up, where each rule you ship forces the adversary to change how they operate rather than what they carry. For cert prep, memorise Bianco's six tiers and their pain labels (trivial, easy, simple, annoying, challenging, tough) and be ready to place any indicator you are handed on the right one.
Signatures have a ceiling. Even a flawless T1003.001 rule matches one known shape of the technique. An attacker who dumps LSASS with a custom driver instead of ProcDump, or who spreads malicious logons across a fortnight so no single day crosses any threshold, leaves no signature to match. What they leave is a statistical residue, like an account suddenly touching a server it has never touched in two years of history. Catching residue means learning what normal looks like first, then flagging the deviation. The next lesson, Behavioral analytics (UEBA), short for user and entity behavior analytics, builds those baselines. That is the layer that catches the technique variants nobody ever wrote a rule for.
Treat the whole thing as a portfolio decision, the way you would weight a set of investments. Hashes and IP addresses earn their keep in blocking and in fast response, and they should still not dominate your detection backlog. Score every candidate rule by what it would cost the adversary to evade it, because tool-marking and TTPs beat domain lists every time. When a vendor offers you "ten thousand IOC feed integrations", ask which of those map to a behavior you can still catch after the feed goes stale. Plenty of IOC pipelines produce impressive alert volume and never cost the attacker an hour. Alert volume was never a success metric.
Try this
Take three rules that page a human today and put each one on a tier: hash, IP or domain at the bottom; tool in the middle; TTP at the top. Be honest about where they land. Then pick the most IOC-heavy of the three and rewrite its idea as a behavior-focused Sigma condition, and write the tier and the eviction cost into the pull request so a reviewer can argue with your reasoning instead of guessing at it.
# Before (IOC-ish): alert on a specific payload hash or C2 IP# After (TTP-ish): alert on certutil download behavior$ sigma convert -t splunk -p sysmon rules/win_certutil_downloader.ymlsource="WinEventLog:Microsoft-Windows-Sysmon/Operational" EventCode=1Image="*\\certutil.exe" CommandLine="*urlcache*" CommandLine="*split*"NOT ParentImage="*\\CcmExec.exe"# Checklist output you should write in the PR:# Pyramid tier: TTP/tool | ATT&CK: T1105 | Eviction cost: high (must change tradecraft)
Takeaway
Gloves come off in a second. Craft takes years to relearn. Push your detections up the Pyramid of Pain so an attacker has to change how they operate, not the file they happen to be carrying.
Next step: find one alert that pages on a hash or an IP address, demote it to intel context so it still enriches an investigation without waking anyone at 3 a.m., and hand its paging path to a behavior rule you can prove with an Atomic Red Team test.