Detection engineering: write the rule that catches the attacker
Lesson 1 of 3
1Detection engineering: write the rule that catches the attacker
The big pictureTools ship with ready-made rules, but attackers know them too. A mid-level SOC analyst does not wait for the product to catch everything; they ask "what does this attack look like in our logs?" and write the rule themselves. And every rule has a price: too many false alerts wear the team down, and a rule too narrow catches nobody. Detection engineering is the art of balancing the two.
What the picture shows: You start from an ATT&CK technique, ask which log sees it, write the rule, run a simulated attack to see whether it fires, then tune it on real data before shipping it.
Map of this part
The concepts in order, click any one to jump to it:
Two ways into the same idea
Picture a building guard. A weak rule: "stop the man in the red shirt" (an indicator that changes easily). A strong rule: "stop anyone trying doors one after another at 3 am" (behaviour). Detection engineering is writing rules of the second kind, testing them with an actor playing the thief, and making sure they do not stop the cleaner every night.
Key Windows sources: 4624 successful logon and 4625 failed, 4688 process creation (turn on command-line logging), 4720 user created, 4732 added to a local group, 4769 Kerberos service ticket, and 1102 security log cleared. Sysmon adds: 1 process creation with hash and parent, 3 network connection, 10 process access (such as LSASS), 11 file creation. On Linux: auth.log and auditd. Sigma: a generic YAML format for detection rules (title, logsource, detection, condition, level, and tags such as attack.t1059.001) converted by sigma-cli/pySigma into a Splunk, Elastic or Sentinel query. Testing with Atomic Red Team (a small test per technique). Measuring: precision (how many alerts are real out of all) and coverage on the ATT&CK matrix. Detection as code: every rule in Git with review and an automatic test.
Before You Start
🚨Detection and response
You know a SIEM, alerts and the response cycle.
🧠How attackers think
You know the ATT&CK tactics.
The Core Idea
1The logs that matter
No detection without a log. Before writing any rule, make sure the event is logged at all and reaches the SIEM. Most rules that fail in real life fail because command-line logging was never turned on, Sysmon is missing from the servers, or logs are kept for only seven days.
| Event | Source | What it reveals | ATT&CK technique |
|---|---|---|---|
| 4625 ×20 | Windows Security | Password guessing or spraying | T1110 |
| 4688 / Sysmon 1 | Windows Security and Sysmon | PowerShell with an encoded command | T1059.001 |
| 4720 + 4732 | Windows Security | A new account added to admins | T1136 · T1098 |
| Sysmon 10 | Sysmon | A process reading LSASS memory | T1003.001 |
| 1102 | Windows Security | The security log cleared | T1070.001 |
2A Sigma rule: one language for every SIEM
Instead of writing a rule in Splunk's language and rewriting it for Elastic, you write it once in Sigma and convert it automatically. A rule has three parts: logsource (which log), detection (what to look for) and condition (how the conditions combine), plus a severity level, the ATT&CK technique and the known false positives.
title: PowerShell started with an encoded command
id: 7b0c4f2a-0d1e-4b55-9b3a-2f6e1c9a0d11
status: experimental
description: Encoded commands hide what PowerShell runs; attackers use them to slip past simple filters.
logsource:
product: windows
category: process_creation
detection:
selection_img:
Image|endswith: ['\powershell.exe', '\pwsh.exe']
selection_flag:
CommandLine|contains: [' -enc ', ' -EncodedCommand ', ' -e ']
filter_known:
ParentImage|endswith: '\ccmexec.exe' # the software-deployment agent does this legitimately
condition: selection_img and selection_flag and not filter_known
falsepositives:
- Admin scripts that pass encoded commands
level: high
tags:
- attack.execution
- attack.t1059.0013The rule at work: a tiny detection engine
To see what a SIEM does, run a miniature engine: events as JSON, rules that match them, and alerts. Notice the threshold rule: one failed logon means nothing, but twenty from one address within minutes means guessing. And the sequence rule: a user created then added to admins within minutes.
The filter dropped the PowerShell started by the deployment agent. Notice the one from Word is the suspicious one: a document running commands.
from collections import Counter
events = [{"id": 4625, "ip": "10.8.1.50", "user": f"user{i}", "t": i} for i in range(22)]
events += [{"id": 4688, "image": "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe",
"cmd": "powershell -enc SQBFAFgA", "parent": "winword.exe", "t": 40},
{"id": 4720, "user": "svc_backup2", "t": 50},
{"id": 4732, "user": "svc_backup2", "group": "Administrators", "t": 53},
{"id": 4688, "image": "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe",
"cmd": "powershell -enc AAAA", "parent": "ccmexec.exe", "t": 60}]
alerts = []
fails = Counter(e["ip"] for e in events if e["id"] == 4625)
users = {ip: len({e["user"] for e in events if e["id"] == 4625 and e["ip"] == ip}) for ip in fails}
for ip, n in fails.items():
if n >= 20:
alerts.append(f"HIGH T1110.003 password spraying from {ip}: {n} failures over {users[ip]} accounts")
for e in events:
if e["id"] == 4688 and e["image"].lower().endswith("powershell.exe") and " -enc " in f" {e['cmd']} ":
if not e["parent"].endswith("ccmexec.exe"):
alerts.append(f"HIGH T1059.001 encoded PowerShell, parent {e['parent']}")
created = {e["user"]: e["t"] for e in events if e["id"] == 4720}
for e in events:
if e["id"] == 4732 and e["user"] in created and e["t"] - created[e["user"]] <= 10:
alerts.append(f"CRIT T1136+T1098 {e['user']} created and added to {e['group']} within {e['t'] - created[e['user']]} min")
print("\n".join(alerts))4Testing, tuning and coverage
An untested rule is not a rule. Run the Atomic Red Team test for that technique in your lab and confirm the alert appears. Then run the rule over two weeks of real logs, count the false alerts and tune the filters. And draw your coverage: which ATT&CK techniques have a tested rule and which do not. The gaps tell you what to write next.
Before the filter: 143 alerts with 3 real, so analysts will ignore it. After: 9 alerts and a third are real.
def precision(true_alerts, false_alerts):
total = true_alerts + false_alerts
return true_alerts / total if total else 0
week = {"encoded PowerShell": (3, 140), "after filter": (3, 6), "spraying >= 20": (1, 0)}
for rule, (tp, fp) in week.items():
print(f"{rule:<20} {tp + fp:>4} alerts, precision {precision(tp, fp):6.1%}")Worked example
The task: an intelligence report says a ransomware gang starts by disabling Windows Defender with a PowerShell command, then deletes shadow copies with vssadmin delete shadows. Write a detection plan.
The answer: (1) The techniques: T1562.001 (impair defences) and T1490 (inhibit recovery). (2) The source: 4688 and Sysmon 1 with the command line. (3) Two Sigma rules: Set-MpPreference with -DisableRealtimeMonitoring, and vssadmin or wmic shadowcopy with delete. The second is critical because legitimate use is very rare. (4) A sequence rule: both on one host within an hour = isolate the host automatically. (5) Test with the Atomic Red Team test for T1490 in the lab. (6) Run it for a week and review false positives (backup software). (7) Add them to Git and update the coverage map.
Myth vs Reality
| Myth | Reality |
|---|---|
| The security product catches everything by itself. | Ready-made rules are generic, and attackers test against them. Your environment needs rules that know your systems and habits. |
| More alerts mean more security. | Floods of false alerts teach analysts to ignore the real one. Precision beats volume. |
| A rule is written once and lasts. | Systems and software change, so a rule turns noisy or silent. Review and retest it regularly. |
Where you meet it at work
🛡️The SOC
The detection engineer writes the rules analysts work from.
📰A new intelligence report
Turns within a day into tested rules for the gang's techniques.
📊A report to management
An ATT&CK coverage map shows where we are strong and where the gaps are.
Test your understanding
Which Windows event logs a new process?
4688 is process creation, with the command line if enabled.
What is the advantage of writing a rule in Sigma?
A generic format sigma-cli converts to Splunk, Elastic or Sentinel.
Why is behaviour-based detection stronger than hash-based?
A hash changes with any edit; behaviour is tied to the attacker's goal.
A rule fired 200 alerts, 2 of them real. What is its precision?
2 ÷ 200 = 1%. It needs tuning before it ships.
How do you confirm a rule works before shipping it?
Atomic Red Team gives you a small test per technique.
Quick review cards
Check Your Understanding
What do you check first before writing a rule?
That the event is actually logged, reaches the SIEM and is kept long enough.
Why write known false positives inside the rule?
So the analyst quickly knows whether an alert comes from a legitimate source, and the knowledge stays with the rule.
What does the coverage map tell you?
Which techniques have tested rules and which are gaps, so you know what to write next.
Resources for this lesson
Grouped by type. Start with the official docs for precision, or an article or video for the explanation.
Tools2
Done with this lesson?
Sign in to save your progress.