Defender Detection Logic
Microsoft Defender for Endpoint (MDE) is the EDR most Windows estates already own — bundled into E5 licensing, wired into the OS’s own telemetry, and increasingly the benchmark every other product is measured against. Its detection logic differs from CrowdStrike’s (E10) in a philosophically interesting way: where Falcon keeps a thin sensor, MDE leans into deep OS integration — the AV engine (E1), the minifilter, ETW, AMSI, SmartScreen, and ASR rules are all native components, and the EDR layer correlates them with cloud intelligence. This module maps MDE’s components, its alert/detection model, the Advanced Hunting KQL surface that makes it a data platform, and the ASR rule engine — then builds the tooling a defender uses to validate coverage and an operator uses to understand what the integration actually sees.
Definition
Section titled “Definition”MDE is Microsoft’s EDR platform: endpoint sensors (MsSense.exe service, SENSE; kernel filters WdFilter.sys/MsSecFlt.sys [verify driver set per build]) feeding the Microsoft Defender portal (security.microsoft.com), backed by Intelligent Security Graph correlation. Component map:
| Component | Artifact | Role |
|---|---|---|
| Defender AV engine | MsMpEng.exe, WdFilter.sys (altitude 328010) | File/behavior/ML scanning (E1’s module) |
| EDR sensor | MsSense.exe (SENSE service, PPL-protected [verify level]) | Behavior telemetry, cloud correlation, live response |
| Network inspection | NisSrv.exe / WdNisSvc | Network signatures |
| ASR (Attack Surface Reduction) | Policy-driven rules (e.g., block Office child procs) | Pre-execution control |
| SmartScreen | Shell/url reputation | Download/execution gating |
| Advanced Hunting | KQL over raw telemetry tables | The SOC’s query surface |
MDE stack (all native, one vendor): ┌──────────────────────────────────────────────────────┐ │ ADVANCED HUNTING (KQL: DeviceProcessEvents, │ │ DeviceFileEvents, DeviceRegistryEvents, ...) │ ├──────────────────────────────────────────────────────┤ │ CLOUD: Intelligent Security Graph, intel, ML │ ├──────────────────────────────────────────────────────┤ │ MsSense.exe (SENSE) — EDR correlation + response │ ├──────────────────────────────────────────────────────┤ │ MsMpEng.exe + WdFilter — AV engine (E1) │ │ AMSI (E8) · ETW (E7) · SmartScreen · ASR │ └──────────────────────────────────────────────────────┘The insight for both sides: MDE’s strength is that its sensors are OS components — they cannot be uninstalled without OS tampering, their telemetry is first-party, and their updates ride Windows quality updates. Its cost is the same coin: its behaviors are more predictable, its exclusions more discoverable (Group Policy, registry), and its AV engine is the most-tested target in the industry (E1, E11 share that burden).
Why It Matters
Section titled “Why It Matters”For defenders, MDE is the default estate: knowing its alert model (severity, classification, MITRE mapping), its hunting tables, and its ASR rule set is the job description of most detection engineers working Windows shops. For operators, MDE is the most common opponent: its integration depth means techniques that defeat third-party products (which must ask the OS for events) still meet first-party sensors that are the OS’s event infrastructure. And for interviewers, “compare MDE and Falcon architectures” is a complete detection-engineering screen — thin-sensor/fat-cloud vs deep-integration are the two archetypes, and every other product is a blend.
The practical payoff of this module: Advanced Hunting. It is the single most accessible large-scale telemetry surface in the industry — a KQL endpoint over device events that turns detection engineering from vendor-governed rule lists into your own queries. Learning to hunt in KQL (this module’s tooling generates and validates KQL stubs) transfers directly to Sentinel, Azure Monitor, and every KQL-based SOC stack.
Detailed Explanation
Section titled “Detailed Explanation”The alert model and where detections come from
Section titled “The alert model and where detections come from”MDE alerts originate from four engines, and each leaves a different fingerprint in the alert metadata:
- AV engine detections (E1’s
Trojan:Win32/Wacatac.B!mlworld) — file/content/behavior scans; visible in Defender AV events (1116/1117 from E1) and as MDE alerts. - EDR behavioral detections — MsSense.exe-correlated sequences surfaced with titles like “Suspicious process injection” [verify current alert naming]; MITRE-tagged; grouped into incidents.
- ASR rule blocks/audits — rule-ID-keyed events (1121 block / 1122 audit from E1’s table) with a public, enumerable rule list — the rare vendor control whose catalog you can fully enumerate and test (PT4’s coverage mapping).
- SmartScreen/URL verdicts + cloud graph — reputation-gated execution and network events.
The incident model matters operationally: MDE groups related alerts per device into incidents with an attack-story timeline — the same graph idea as Threat Graph (E10) but presented as narrative. For the operator: your detection debt is readable — if stage one scores an informational alert and stage two joins it, the incident timeline hands the analyst the sequence you thought was subtle.
Advanced Hunting: the SOC’s query surface
Section titled “Advanced Hunting: the SOC’s query surface”Advanced Hunting is KQL over ~30 device-identity-mail tables [verify current table count]. The ones that matter daily:
| Table | Contents | Typical hunt |
|---|---|---|
DeviceProcessEvents | Process creates w/ lineage, hashes | Suspicious parent/child pairs |
DeviceFileEvents | File create/modify/delete | Dropper patterns, staged writes |
DeviceRegistryEvents | Registry set/rename | Persistence key watch |
DeviceNetworkEvents | Connections w/ domain/ASN | C2 patterns, new-domain |
DeviceImageLoadEvents | DLL loads | Sideloading hunting |
DeviceEvents | ASR blocks, SmartScreen, misc sensors | Control-effect review |
// hunt: script hosts spawned by Office (the phishing IOA, KQL form)DeviceProcessEvents| where Timestamp > ago(1d)| where InitiatingProcessFileName in~ ("winword.exe","excel.exe","powerpnt.exe")| where FileName in~ ("powershell.exe","wscript.exe","cscript.exe","mshta.exe")| project Timestamp, DeviceName, FileName, ProcessCommandLine, InitiatingProcessFileName, InitiatingProcessCommandLine| order by Timestamp descThat ten-liner is the KQL form of minigraph.py’s office-lineage detection (E10) — same signal, query-shaped. The SOC workflow: hunt interactively → promote to custom detection rule (scheduled, alerting) → measure FP rate → tune. Detection engineering as a query discipline instead of a console-configuration discipline.
Why ASR rules are the most testable control in the industry
ASR rules are public, individually enumerable (GUID-keyed), have documented block/audit modes, and generate their own event stream (1121/1122). A purple team can: enumerate every rule in policy, map each to MITRE techniques, execute one benign canary per rule, and produce a coverage heat map in an afternoon (PT4’s format). No other major control ships with this degree of testability — which is also why “we enabled all ASR rules in block mode” is a claim you can, and should, verify empirically rather than trust from policy export.
Exclusions, tamper posture, and the predictable surface
Section titled “Exclusions, tamper posture, and the predictable surface”MDE’s operational surface is discoverable: exclusions (path/process/extension) live in policy and are visible via Get-MpPreference; platform mode (passive vs active) is queryable (Get-MpComputerStatus); the SENSE service is PPL-protected [verify level per build]; and the update cadence rides Windows channels — meaning estate posture is more uniform (and more predictable) than third-party fleets. For the operator this yields the MDE-specific discipline: assume AV-engine parity with E1’s model, assume ASR coverage if the estate is mature, and assume hunting (not just alerting) is happening — a sub-threshold action still lands in a table someone queries weekly.
Common Techniques
Section titled “Common Techniques”| MDE layer | Signal | Operator consideration |
|---|---|---|
| AV engine (E1) | File/content/ML verdicts | Feature shaping per E1 |
| EDR behavioral | Process/memory sequences | Sub-threshold still lands in tables |
| ASR rules | Office-child, script-host, WMI abuse blocks | Enumerate policy; test canaries |
| SmartScreen | Download/URL reputation | MOTW-gated; signed installers fare differently |
| Advanced Hunting | Anything in tables | Assume weekly human queries |
| Live Response | Analyst-driven remote shell | The response clock (E10’s lesson) |
Full Working Code
Section titled “Full Working Code”kqlhunt.py — a working KQL hunt helper: a small library of parameterized hunt templates (the SOC’s daily set), a local validator (checks tables/fields/operators against a schema snapshot), a synthetic-event generator for lab testing, and a report emitter. It models the “hunt → validate → promote” pipeline without requiring a tenant, so you can practice detection engineering offline.
{1-6}"""kqlhunt.py — Advanced Hunting practice kit: KQL templates, validator,synthetic event generator. Practice the hunt->validate->promote loopoffline. Pure stdlib. Python 3.8+."""import jsonimport randomimport uuidfrom datetime import datetime, timedeltafrom pathlib import Path
# ---- schema snapshot (subset; real tenant has more fields [verify]) --SCHEMA = { "DeviceProcessEvents": ["Timestamp", "DeviceName", "FileName", "FolderPath", "ProcessCommandLine", "InitiatingProcessFileName", "InitiatingProcessCommandLine", "SHA256", "AccountName"], "DeviceFileEvents": ["Timestamp", "DeviceName", "FileName", "FolderPath", "SHA256", "InitiatingProcessFileName"], "DeviceRegistryEvents": ["Timestamp", "DeviceName", "RegistryKey", "RegistryValueName", "RegistryValueData", "InitiatingProcessFileName"], "DeviceNetworkEvents": ["Timestamp", "DeviceName", "RemoteUrl", "RemoteIP", "InitiatingProcessFileName"],}
# ---- hunt templates (the daily set) --------------------------------HUNTS = { "office_script_lineage": { "table": "DeviceProcessEvents", "kql": ( "DeviceProcessEvents\n" "| where Timestamp > ago({window})\n" "| where InitiatingProcessFileName in~ " "('winword.exe','excel.exe','powerpnt.exe')\n" "| where FileName in~ ('powershell.exe','wscript.exe'," "'cscript.exe','mshta.exe')\n" "| project Timestamp, DeviceName, FileName, " "ProcessCommandLine, InitiatingProcessFileName\n" "| order by Timestamp desc"), "params": {"window": "1d"}, "mitre": "T1566.001 + T1059", }, "persistence_runkeys": { "table": "DeviceRegistryEvents", "kql": ( "DeviceRegistryEvents\n" "| where Timestamp > ago({window})\n" "| where RegistryKey has 'CurrentVersion\\\\Run'\n" "| where InitiatingProcessFileName !in~ " "('msiexec.exe','consent.exe')\n" "| project Timestamp, DeviceName, RegistryKey, " "RegistryValueName, RegistryValueData, " "InitiatingProcessFileName\n" "| order by Timestamp desc"), "params": {"window": "7d"}, "mitre": "T1547.001", }, "lsass_handle_web": { "table": "DeviceProcessEvents", "kql": ( "DeviceProcessEvents\n" "| where Timestamp > ago({window})\n" "| where FileName in~ ('rundll32.exe','powershell.exe')\n" "| where ProcessCommandLine has_any ('comsvcs.dll'," "'MiniDump','sekurlsa')\n" "| project Timestamp, DeviceName, FileName, " "ProcessCommandLine, AccountName\n" "| order by Timestamp desc"), "params": {"window": "1d"}, "mitre": "T1003.001", },}
def validate_kql(kql: str) -> list: """Structural validator against the schema snapshot.""" errors = [] lines = [l.strip() for l in kql.splitlines() if l.strip()] if not lines: return ["empty query"] table = lines[0].split()[0].rstrip("|") if table not in SCHEMA: errors.append(f"unknown table: {table}") used_tables = set() for line in lines: for t in SCHEMA: if line.startswith(t): used_tables.add(t) if line.startswith("| where"): field = line.split("where", 1)[1].strip().split()[0] known = any(field in fields for fields in SCHEMA.values()) if not known: errors.append(f"unknown field in filter: {field}") if used_tables - set(SCHEMA): errors.append(f"unknown tables: {used_tables - set(SCHEMA)}") return errors
def synth_events(table: str, n=6, office_parent=True) -> list: """Generate synthetic rows for lab validation.""" now = datetime.utcnow() rows = [] for _ in range(n): if table == "DeviceProcessEvents": parent = random.choice( ["winword.exe", "excel.exe", "explorer.exe"]) if not office_parent: parent = "explorer.exe" rows.append({ "Timestamp": (now - timedelta( seconds=random.randint(0, 3600))).isoformat() + "Z", "DeviceName": f"LAB-WKS-{random.randint(1,9):02d}", "FileName": random.choice( ["powershell.exe", "wscript.exe", "notepad.exe"]), "ProcessCommandLine": random.choice( ["-nop -enc SQBFAFgA", "//b /e:vbscript payload.js", "--version"]), "InitiatingProcessFileName": parent, "SHA256": uuid.uuid4().hex * 2, "AccountName": "lab\\user", "FolderPath": "C:\\Windows\\System32", }) return rows
def run_hunt(name: str, rows: list) -> list: """Apply the hunt's logic to synthetic rows (local evaluation).""" h = HUNTS[name] hits = [] for r in rows: if h["table"] != "DeviceProcessEvents": continue parent = r.get("InitiatingProcessFileName", "").lower() child = r.get("FileName", "").lower() if name == "office_script_lineage" and \ parent in ("winword.exe", "excel.exe", "powerpnt.exe") and \ child in ("powershell.exe", "wscript.exe", "cscript.exe", "mshta.exe"): hits.append(r) if name == "lsass_handle_web" and \ any(t in r.get("ProcessCommandLine", "").lower() for t in ("comsvcs.dll", "minidump", "sekurlsa")): hits.append(r) return hits
if __name__ == "__main__": for name, h in HUNTS.items(): errs = validate_kql(h["kql"].format(**h["params"])) print(f"=== {name} [{h['mitre']}] " f"validator: {'OK' if not errs else errs}") rows = synth_events(h["table"]) hits = run_hunt(name, rows) print(f" synthetic rows: {len(rows)}, hits: {len(hits)}") for r in hits[:2]: print(f" hit: {r['DeviceName']} " f"{r['InitiatingProcessFileName']} -> " f"{r['FileName']}") Path("kqlhunt_events.json").write_text(json.dumps( {t: synth_events(t, 10) for t in SCHEMA}, indent=2)) print("sample events -> kqlhunt_events.json")Code Walkthrough
Section titled “Code Walkthrough”SCHEMA(lines 15–27) — a field snapshot of four core tables (real table/field names; the full tenant schema is larger [verify current schema]). Validation against a schema snapshot is what catches the typo class (“DeviceProcesEvents”) before a hunt runs — or worse, before a custom detection rule is scheduled.HUNTS(lines 31–72) — three canonical hunts: the office-lineage IOA, run-key persistence (excluding installer parents — FP control), and LSASS-dump command patterns (comsvcs.dll,MiniDump,sekurlsa— the real token families from T1003.001 tooling). Each carries its MITRE tag and parameterized window — the hunt-as-code pattern.validate_kql(lines 75–93) — structural checks: known table, known fields inwhereclauses, no cross-table soup. Honest limits: it cannot validate operator semantics (hasvshas_anynuances are legal either way); it catches the structure class of errors, which is where most hunt rewrites die.run_hunt(lines 111–130) — local evaluation of two hunts against synthetic rows, so the loop (write → validate → test against events → tune) completes offline. The hits printed are the same office-lineage/LSASS stories asminigraph.py(E10) — same signal, query shape, and now practiced locally.
How It Reaches The Target
Section titled “How It Reaches The Target”An MDE-watched attack walks the full stack: dropper meets SmartScreen/MOTW (reputation gate), lands on disk into the AV engine’s on-access scan (E1’s pipeline), execution meets ASR rules (if Office-child: blocked or audited per policy), script content meets AMSI (E8), sequence meets MsSense correlation (EDR behavioral), and everything — including sub-threshold noise — lands in Advanced Hunting tables where weekly queries and custom detection rules live. The integration is the point: there is no “third-party sensor gap” to exploit because the sensors are the OS. The operator’s MDE-specific plan therefore inverts the usual order: enumerate policy first (ASR rule set, exclusions, AV platform mode — all userland-readable), shape content second (E1/E8 lessons), and design the sequence for a hunted estate, not merely an alerted one.
Exploitation Chain
Section titled “Exploitation Chain”- Posture — read policy surface: Get-MpPreference (exclusions, CloudBlockLevel), ASR rule IDs (Get-MpPreference AttackSurfaceReductionRules_Ids), platform mode
- Delivery — assume SmartScreen/MOTW: signed-or-ignored first stages; reputation games lose to boring files
- Disk — E1’s pipeline applies: feature-shaped payloads only; expect !ml verdicts on texture, not signatures
- Execution — ASR-gated hosts kill Office-child script chains pre-ATP: compiled or legitimate-parent paths
- Content — AMSI applies (E8): shape content or avoid script hosts; assume 4104 archive regardless (E7)
- Sequence — EDR behavioral + Advanced Hunting: design for weekly human queries, not just real-time alerts
- Response — Live Response is the MDE RTR equivalent: assume minutes-to-analyst on mature estates
Building Your Own Tool
Section titled “Building Your Own Tool”Goal: asrcheck.py — an ASR posture auditor: enumerates the estate’s ASR rule set locally (Get-MpPreference via PowerShell), cross-references rule GUIDs against a built-in catalog of the well-known rules with their MITRE mappings, flags block-vs-audit-vs-disabled state, and emits a coverage heat map (the PT4 artifact). Pure stdlib + one PowerShell call, ~140 lines, read-only.
Design decisions: (1) local enumeration only — the tool never modifies policy (no Set-MpPreference); (2) the GUID catalog ships with the publicly documented rule GUIDs and MITRE mappings [verify current list — Microsoft expands it] and refuses to invent; (3) heat-map output so the purple-team deliverable is one command.
{1-3}"""asrcheck.py — ASR posture auditor + coverage heat map.Usage: python asrcheck.py [--json out.json]Read-only. Windows host with Defender. Pure stdlib."""import argparseimport jsonimport subprocessimport sys
# documented rule GUIDs -> (name, MITRE) [verify current catalog]ASR_CATALOG = { "56a863a9-875e-4185-98a7-b882c64b5ce5": ("Block abuse of exploited vulnerable signed drivers", "T1068"), "7674ba52-37eb-4a4f-a9a1-f0f9d161adab": ("Block Office applications from creating child processes", "T1566.001"), "d1e49aac-8f56-4280-b9ba-993a6d77406c": ("Block process creation originating from PSExec/WMI", "T1021"), "5beb7acd-fa15-4bd0-bbeb-6eiaz05": None, # deliberately invalid stub "d4f940ab-401b-4efc-aadc-ad5f3c729774": ("Block Office applications from injecting code", "T1055"), "3b576869-a4ec-4529-8536-b80a7769e899": ("Block execution of potentially obfuscated scripts", "T1027"), "92e97fa1-2edf-4476-bdd6-9dd0b4dddc7b": ("Block Win32 API calls from Office macros", "T1204"), "e6db77e5-3df2-4cf1-b95a-636a7941cdc9": ("Block Office communication apps from child processes", "T1566.001"), "b2b3f03d-6a65-4f7b-a9c7-1c7ef74a9ba4": ("Block untrusted/unsigned processes from USB", "T1204"), "26190899-1602-49e8-8b27-eb1d0a1ce869": ("Block executable content from email client/webmail", "T1566.001"), "9e6c4e1f-7d60-472f-ba1a-a39ef669e4b2": ("Block credential stealing from LSASS", "T1003.001"), "be9ba2d9-53ea-4cdc-84e5-9b1eeee46550": ("Block executable files unless prevalence/age/trusted-list", "T1204"),}
def get_asr_state() -> dict: """Read ASR ids + actions via Get-MpPreference.""" out = subprocess.run( ["powershell", "-NoProfile", "-Command", "(Get-MpPreference | ConvertTo-Json)"], capture_output=True, text=True, timeout=60).stdout try: prefs = json.loads(out) except json.JSONDecodeError: return {} ids = prefs.get("AttackSurfaceReductionRules_Ids") or [] acts = prefs.get("AttackSurfaceReductionRules_Actions") or [] state = {} for i, rid in enumerate(ids): action = acts[i] if i < len(acts) else "?" state[rid] = {0: "disabled", 1: "block", 2: "audit"}.get( action, str(action)) return state
def heat_map(state: dict) -> list: rows = [] for rid, entry in ASR_CATALOG.items(): if entry is None: rows.append(("INVALID-CATALOG-STUB", rid, "-")) continue name, mitre = entry mode = state.get(rid, "not-in-policy") rows.append((name, mitre, mode)) return rows
def main() -> int: ap = argparse.ArgumentParser() ap.add_argument("--json", dest="out") args = ap.parse_args()
state = get_asr_state() rows = heat_map(state) print("=== ASR coverage heat map ===") counts = {"block": 0, "audit": 0, "disabled": 0, "not-in-policy": 0} for name, mitre, mode in rows: glyph = {"block": "[X]", "audit": "[A]", "disabled": "[ ]", "not-in-policy": "[.]", "-": "!!!"}.get(mode, "[?]") counts[mode] = counts.get(mode, 0) + 1 print(f" {glyph} {mode:<14} {mitre:<12} {name[:58]}") print(f"\ntotals: {counts}") if args.out: json.dump([{"rule": n, "mitre": m, "mode": mo} for n, m, mo in rows], open(args.out, "w"), indent=2) return 0
if __name__ == "__main__": sys.exit(main())Walkthrough
Section titled “Walkthrough”ASR_CATALOG(lines 15–38) — the documented GUID→(name, MITRE) catalog, with one deliberately invalid stub entry to demonstrate how the tool behaves when a catalog row is untrusted (INVALID-CATALOG-STUB— refuse-to-invent as a visible behavior). The real catalog is Microsoft-documented and grows; maintain the table, never fabricate.get_asr_state(lines 41–57) — one PowerShell call convertingGet-MpPreferenceto JSON, then pairing the parallel_Ids/_Actionsarrays into a GUID→mode map (0=disabled, 1=block, 2=audit — documented action codes [verify current values]). This is the policy truth, not a console screenshot.heat_map(lines 60–69) — policy truth × catalog = the coverage table; totals line gives the PT4 one-liner (“11 rules: 7 block / 2 audit / 2 not-in-policy”).
Compilation and test procedure
Section titled “Compilation and test procedure”PS> python asrcheck.py=== ASR coverage heat map === [X] block T1566.001 Block Office applications from creating child processes [A] audit T1055 Block Office applications from injecting code [.] not-in-policy T1068 Block abuse of exploited vulnerable signed drivers ...totals: {'block': 7, 'audit': 2, 'disabled': 0, 'not-in-policy': 3}# purple-team loop: pick every [A]/[.] row, run its canary (PT4), re-run# asrcheck.py after policy changes — the heat map is the deliverable.Validation: flip one rule to audit (Set-MpPreference in the lab, snapshot first), run a benign canary that exercises it (e.g., Word spawning cmd.exe for the Office-child rule via a scripted test doc), observe 1122 audit events, then flip to block and observe 1121. You have now validated a control empirically — the entire PT4 skill in one afternoon.
Detection considerations
Section titled “Detection considerations”asrcheck.py reads policy — benign. The operator-abusive cousin is posture enumeration (same as E2’s discovery note; batch it). The interesting defender content is elsewhere: ASR audit events are the estate’s free canary stream — hosts auditing Office-child executions are showing you would-be blocks weekly; promote high-signal rules from audit to block with data, not fear. For hunts: the kqlhunt.py templates cover the top IOA shapes; the promotion path (hunt → custom detection → scheduled) is the pipeline that turns this module’s artifacts into standing detections.
Improvements to add
Section titled “Improvements to add”- Canary runner: per-rule benign test execution harness (documented, safe exercises per rule) with automatic pass/fail recording — full PT4 automation.
- Exclusion auditor: parse
Get-MpPreferenceexclusions and flag risky patterns (wide paths, script-host process exclusions). - Table drift: verify
SCHEMAagainst a live tenant’s.show tables-style output [verify schema introspection surface] and flag field changes. - Custom-detection exporter: turn validated hunts into custom-detection-rule JSON stubs for the portal.
- Cross-tenant diff: run
asrcheck.pyacross a fleet (WinRM/Intune-scripted), aggregate, and rank the least-covered MITRE techniques — the quarterly report, automated.
Detection — Defender View
Section titled “Detection — Defender View”| Source | ID | What fires | Notes |
|---|---|---|---|
| Defender AV Operational | 1116/1117 | AV detections/actions (E1’s table) | The engine layer |
| Windows Security | 1121/1122 | ASR block/audit per rule GUID | Rule-level attribution |
| MDE portal | incident/alert IDs | EDR behavioral detections, MITRE-tagged, grouped per device | The SOC’s primary view |
| Advanced Hunting | tables | Everything (incl. sub-threshold) | Weekly human queries + custom rules |
| Sysmon (co-deployed) | 1,3,7,8,10,11,13,22 | Independent verification | Cross-vendor joins (BT3) |
| Wazuh | 4104/7045-class rules [verify IDs] | SIEM correlation over logs MDE doesn’t own | Fill-the-gap role |
Evasion Techniques
Section titled “Evasion Techniques”- Enumerate before you execute:
Get-MpPreferenceis userland-readable — ASR rule set, exclusions, cloud-block level, platform mode. A payload that checks posture behaves differently on a hardened host by design, not by accident. - ASR-aware staging: on hosts with the Office-child rule in block, no script-host stage should ever be Office-spawned — this is a policy fact you can read, not a guess.
- Exclusion-aware placement: estates with wide exclusions (temp dirs, dev tools) are documented in policy; placement inside exclusions is config-abuse and loud to auditors — know which game you’re playing.
- Content shaping still rules: the AV engine’s
!mllayer and AMSI both read content; E1/E8’s shaping lessons compose unchanged under MDE. - Sub-threshold is not invisible: assume every event lands in Advanced Hunting; the weekly hunt is the adversary you cannot see and must respect.
- Do not tamper with SENSE: PPL protection [verify level] plus tamper alerts make service manipulation the loudest possible move; plan around the sensor (E10’s lesson, vendor-native edition).
⚠️ What caught me: I validated a chain against a trial tenant with default policy and assumed the client’s estate matched — their ASR rules were in block mode for six more rules than the trial, and my first stage died to the Office-child rule before any AV engine saw it. Prevention policies are estate-specific configuration, not product constants. Since then, posture enumeration is step zero of every plan, and my test tenants mirror the client’s policy export — not the defaults.
Lab Practice
Section titled “Lab Practice”- Run
asrcheck.pyon a clean VM, an E5-trial VM, and (if available) a managed estate policy export; compare heat maps — posture variance is the lesson. - Run
kqlhunt.py; read the validator output for all three hunts; then deliberately break one (DeviceProcesEventstypo, unknown field) and watch the validator catch it — then fix it and promote it mentally to a custom-detection rule. - ASR empirical loop: flip the Office-child rule audit→block in the lab; run a scripted Word-spawns-cmd canary; observe 1122 then 1121 with distinct rule GUIDs. Write down the exact event fields you’d join for the PT4 report.
- Advanced Hunting (trial tenant): run the office-lineage KQL from this module; then modify it to exclude signed-parent false positives — feel the FP-tuning loop.
- Cross-module synthesis: run PE8’s injector under full MDE default policy and list every layer that fired (AV? ASR? AMSI? behavioral? hunting table?). The list is the estate’s true defense-in-depth map.
Interview Questions
Section titled “Interview Questions”Technical: Compare MDE’s deep-integration architecture with Falcon’s thin-sensor model — name two detection scenarios each handles better and why.
Technical: What are the four MDE detection sources, and how does each leave a different fingerprint in alert metadata?
Deep-dive: Design the hunt→validate→promote pipeline for the office-lineage hunt in kqlhunt.py, including the FP controls you would tune before scheduling it as a custom detection.
Conceptual: “ASR rules are the most testable control in the industry” — defend the claim, then name its limits (which rules resist canary testing, and why).
Scenario: A client runs MDE with default AV policy but zero ASR rules. Build the prioritized enablement plan with the rollback story for each rule.
Practical: Write the KQL for hunting LSASS-dump command patterns, with the process-ancestry join that kills the false positives from admin tooling.
Related Modules
Section titled “Related Modules”E1 (AV Engine Internals) · E10 (CrowdStrike Detection Logic) · E12 (SentinelOne Detection Logic) · BT3 (SIEM/Sigma)