Chapter 226

Security Operations Center Architecture

A mature SOC is not just an alert queue and a SIEM — it is a data engineering platform, a detection-as-code CI/CD pipeline, a response orchestration layer, and a threat intelligence fusion cell. Detection engineers sit at the intersection of all of these, responsible for translating adversary tradecraft into rules, validating coverage, and reducing analyst toil through automation.

Scenario

Your SOC is generating 50,000 alerts per day; analysts are triaging 2% of them and marking 95% of those as false positives. Mean time to detect (MTTD) is 14 days. Leadership wants MTTD under 48 hours. Your task: redesign the detection pipeline, implement tiered alerting, build SOAR playbooks for the top 5 alert types, and establish a coverage measurement framework.

SOC Tiers and Detection Engineering Role

SOC CAPABILITY LEVELS ════════════════════════════════════════════════════════════════════════ Tier 1 — Alert Triage Role: Analysts monitor alert queue, perform initial enrichment, escalate Tooling: SIEM dashboard, ticketing (ServiceNow/JIRA), threat intel lookup Bottleneck: alert volume > analyst capacity → alert fatigue → missed detections Tier 2 — Incident Response Role: Investigate escalated alerts, determine scope, contain incidents Tooling: EDR console, PCAP analysis, memory forensics, IR platform Bottleneck: unstructured investigation; inconsistent runbooks Tier 3 — Threat Hunting / Detection Engineering Role: Proactive hunting, rule development, ATT&CK coverage mapping Tooling: SIEM/Datalake KQL/SPL, YARA, Sigma, DeTT&CT, ATT&CK Navigator Bottleneck: detection engineering is underinvested; most SOCs treat it as T2 overflow Detection Engineering function (often Tier 3 or separate team): ┌─────────────────────────────────────────────────────────────┐ │ Threat research → rule development → test → CI/CD deploy │ │ Coverage mapping → gap analysis → hunt hypothesis backlog │ │ Alert quality metrics → FP reduction → rule retirement │ └─────────────────────────────────────────────────────────────┘ ════════════════════════════════════════════════════════════════════════

Data Pipeline — What Gets Logged and Why

Log sourceKey eventsATT&CK coverageRetention priority
Windows Security (4xxx)4624/4625 logon, 4688 process, 4698/4702 task, 4720 user createTA0001, TA0003, TA0008Critical — 1 year minimum
Sysmon (1/3/7/8/10/12/17)Process create, network, image load, remote thread, reg, pipeBroadest coverage across all tacticsCritical — enables behavioral rules
EDR telemetry (MDE/CrowdStrike)Process tree, network, file, registry — raw and enrichedNear-complete coverage with behavioral AICritical — usually 30d hot, 1y cold
DNS query logsQuery, response, NXDOMAIN, rare TLDsTA0011 (C2), TA0010 (exfil via DNS)High — enable DGA/tunnel detection
Proxy/web gatewayURL, user-agent, response code, bytesTA0011 (HTTP C2), TA0010High
NetFlow/IPFIXSrc/dst IP, port, bytes, durationTA0008 (lateral), TA0010 (exfil)Medium — good for beaconing; lossy
AD/LDAP auditUser/group changes, GPO mods, trust changesTA0003 (persistence), TA0004 (privesc)High — tracks AD attack chain

SIEM Tuning — Alert Quality Over Volume

-- KQL example: tuning a noisy rule by scoping with context and baselined exceptions
-- BAD (generates 4000 alerts/day): "any PowerShell with -enc"
DeviceProcessEvents
| where ProcessCommandLine has "-enc"

-- BETTER: encoded command from non-whitelisted parent, pointing to rare hosts
let management_hosts = dynamic(["SCCM-SRV01","PATCHING-SRV02"]);
DeviceProcessEvents
| where ProcessCommandLine has "-enc"
| where InitiatingProcessFileName !in~ (
    "svchost.exe", "services.exe", "WmiPrvSE.exe"
  )
| where not (DeviceName has_any (management_hosts))
| extend b64 = extract(@"-[eE][nN][cC][oO]?\s+([A-Za-z0-9+/=]+)", 1, ProcessCommandLine)
| extend decoded = base64_decode_tostring(b64)
| where decoded has_any ("IEX","Invoke-Expression","DownloadString","WebClient","bypass")
| project Timestamp, DeviceName, AccountName, InitiatingProcessFileName,
          ProcessCommandLine, decoded

-- Alert deduplication: suppress repeated identical alert on same host within 1 hour
-- (implement via SOAR dedup logic or SIEM lookup table keyed on host+rule_id+hour bucket)

SOAR Playbook — Automated Alert Enrichment

# SOAR pseudo-playbook: IP IOC triage (runs on every network-based alert)

def ip_triage_playbook(alert):
    ip = alert['remote_ip']

    # Step 1: Threat intel lookup (VirusTotal, Shodan, AbuseIPDB)
    vt = vt_lookup(ip)
    abuse = abuseipdb_lookup(ip)
    shodan = shodan_lookup(ip)

    # Step 2: Internal context
    asset_info   = cmdb_lookup(alert['hostname'])
    user_history = get_user_login_history(alert['user'], days=30)
    similar_alerts = siem_count_similar(ip=ip, hours=24)

    # Step 3: Scoring
    score = 0
    if vt['malicious'] > 3:   score += 40
    if abuse['confidence'] > 80: score += 30
    if shodan['org'] in BULLETPROOF_HOSTERS: score += 20
    if asset_info['is_privileged']: score += 10

    # Step 4: Auto-triage decision
    if score >= 70:
        create_p1_incident(alert, enrichment={'vt': vt, 'abuse': abuse})
        block_ip_on_firewall(ip)  # automated containment
        notify_oncall()
    elif score >= 40:
        create_p2_ticket(alert, enrichment={...})
    else:
        auto_close(alert, reason="low-score after enrichment")

SOC Metrics — What to Measure

MetricTargetWhat it measures
Mean Time to Detect (MTTD)< 48 hours (mature: < 1 hour)Detection pipeline latency
Mean Time to Respond (MTTR)< 4 hours critical, < 24h P2Response process efficiency
Alert-to-incident ratio< 10:1 (alert fatigue indicator)Detection precision (high ratio = FP problem)
ATT&CK technique coverage %> 60% (Tier 3 target: 80%+)Detection breadth across kill chain
Rule FP rate per rule< 5% per rulePer-rule quality; drives tuning priority
Detection Engineer rule rate2-4 rules/week/DEDetection program velocity

Detection Engineering

title: SOAR Enrichment Bypass — Direct Alert Close Without Investigation
description: >
  Detects when a SOAR playbook closes a high-severity alert without creating
  a ticket — may indicate playbook logic error or manipulation.
logsource:
  product: soar
  service: audit
detection:
  selection:
    action: 'close_alert'
    original_severity: 'high'
    ticket_created: false
  condition: selection
level: high

-- MDE KQL: ATT&CK coverage gap identification — technique with no recent alerts
-- (conceptual: join your rule catalog against alert fire history to find dark areas)
let rule_catalog = datatable(technique_id:string, rule_name:string)[
    "T1003.001", "LSASS Memory Access",
    "T1055.001",  "DLL Injection",
    "T1071.001",  "HTTP C2 Beaconing",
    "T1021.002",  "SMB Lateral Movement"
];
let fired_last_30d = AlertInfo
| where Timestamp > ago(30d)
| summarize last_fired=max(Timestamp) by AttackTechniques
| mv-expand AttackTechniques to typeof(string);
rule_catalog
| join kind=leftouter fired_last_30d on $left.technique_id == $right.AttackTechniques
| where isnull(last_fired) or last_fired < ago(14d)
| project technique_id, rule_name, last_fired
| order by last_fired asc

Q&A

A SOC has a high alert volume problem — 50,000 alerts per day with analysts manually triaging all of them. What is the detection engineering approach to sustainably reducing alert volume without increasing missed detections, and how do you prevent the "whack-a-mole" pattern where tuning one rule creates new FPs in adjacent rules?

The root cause of high-volume, low-fidelity alerts is almost always rules written at the wrong level of specificity: broad signatures that match behavior patterns shared between legitimate and malicious activity. The detection engineering approach starts with per-rule false-positive measurement — classify each alert (true positive, false positive, benign true positive) and compute an FP rate per rule over 30 days. Rules with FP rates above 20% are candidates for immediate tuning or retirement. The tuning priority list typically reveals a small number of "noisy rules" (top 10 rules often generate 80%+ of volume) that can be narrowed with additional behavioral context — parent process, command-line pattern, asset class, time window — without losing true-positive coverage. This is the safe path: surgical per-rule tuning with documented rationale.

The whack-a-mole pattern emerges when tuning is done by adding exceptions to existing rules rather than rewriting the detection logic. Suppressing "any PowerShell with -enc except SCCM" works until attackers start using SCCM-looking process names (parent PID spoofing), at which point the exception re-enables the attack. The fix is to invest in detection content versioning with test coverage: treat detection rules like software, with unit tests (Atomic Red Team executions that must fire the rule) and negative tests (legitimate activity samples that must NOT fire). A CI/CD pipeline for detection content — Sigma files in git, automated validation on PR, rollback capability — prevents tuning one rule from silently breaking another. When rules are version-controlled and tested against both attack simulation and production baseline samples before deployment, the whack-a-mole pattern becomes visible as a test failure rather than an operational surprise. SOAR alert clustering (grouping semantically similar alerts from multiple rules into a single investigation case) is a complementary tactical improvement: even if multiple rules fire, the analyst sees one case rather than N alert tickets.