Skip to main content

From Threat Intelligence to Detection: A Practitioner’s Guide

Cover image
Article Metadata

Ecosystem Fit​

This page mirrors the original Medium article into the 1200km.com Docusaurus ecosystem. The original article flow, images, screenshots, infographics, and technical blocks are preserved from the export.

For source-to-detection examples, use the anomaly incident register with telemetry and ATT&CK mappings. It separates investigator-reported behavior from inferred detection opportunities and preserves attribution boundaries.

Building atomic, collection, correlational, TTP-based, and anomaly detection rules from real adversary behavior.​

ByAndrey Pautov— April 2026

Table of Contents​

  • Why IOC-Only Detection Fails

  • The Three APTs: Profiles and Why They Were Chosen

  • Detection Taxonomy

  • Atomic Event Rules

  • Collection-Based Rules

  • Correlational Rules

  • TTP-Based Rules

  • Anomaly Detection Rules

  • The Detection Chain: Layering All Five Tiers

  • Tuning, Validation, and Measurement

  • Rule Lifecycle and Versioning

  • Evasion Considerations

  • Key Sources

Why IOC-Only Detection Fails​

The most common detection workflow in threat intelligence consumption looks like this: receive a report, extract IPs, domains, and file hashes, push them into your firewall and EDR blocklist, mark the ticket closed. This is useful as far as it goes — blocked infrastructure is blocked infrastructure — but it answers a question no sophisticated adversary actually leaves unanswered.

IP addresses rotate. Domains age out. Hashes are trivially changed with a recompile or packer swap. A threat actor who has been operating for more than a week has almost certainly burned the IOCs that appear in public reports, because those reports describe what was foundafterthe fact. By the time an IOC reaches your blocklist, the adversary has likely already moved.

The problem is structural. IOC-based detection operates at the very bottom of thePyramid of Pain— the layer where changing indicators costs the attacker almost nothing. Effective detection operates higher up the pyramid: at the level of tools, techniques, and ultimately behavioral patterns that are expensive for an adversary to modify because they are derived from operational necessity, not configuration choices.

This guide builds all five layers of detection from the behavior of three well-documented, sophisticated adversary groups. Each layer answers a different question:

Article image

A detection program that only runs at the top row is noisy and incomplete. One that only runs at the bottom row misses everything that has rotated its indicators. The goal is to run all five layers simultaneously, with increasing alert confidence as you move up.

The Three APTs: Profiles and Why They Were Chosen​

Three adversary groups were selected on four criteria: technical sophistication, public reporting depth, operational diversity, and breadth of TTPs that generate useful detection examples across all five layers.

1. APT29 — Midnight Blizzard / Cozy Bear (Russia, SVR)​

Article image

**Classification:**Russian Foreign Intelligence Service (SVR), active since at least 2008 MITRE ATT&CK:G0016 **Primary mission:**Long-duration strategic espionage — government, diplomatic, think tank, and technology targets

**Why chosen:**APT29 is the canonical example of a patient, low-and-slow actor that lives almost entirely off legitimate infrastructure and signed tooling. Their 2019–2020 SolarWinds supply-chain operation (SUNBURST/TEARDROP) remains one of the most technically documented intrusions in open reporting. Their 2023–2024 Microsoft corporate network compromise via OAuth device-code phishing and application impersonation is thoroughly reported by Microsoft MSTIC. They generate rich examples for: supply chain detection, OAuth and SAML abuse, living-off-the-land detection, and long-dwell behavioral anomalies.

Key campaigns and public reporting:

  • **SUNBURST (SolarWinds):**FireEye/Mandiant Dec 2020, CISA AA20–352A, Microsoft MSTIC Dec 2020

  • **NOBELIUM / OAuth abuse:**Microsoft MSTIC Oct 2021, May 2023, Jan 2024

  • **Golden SAML:**CyberArk research, Mandiant 2021 follow-up

  • **WellMess / WellMail:**UK NCSC Jul 2020 advisory

Core TTP profile:

  • T1195.002 — Supply chain compromise via software build system

  • T1078.004 — Valid cloud accounts (Azure AD, M365)

  • T1550.001 — Application access token abuse

  • T1556.006 — Modify authentication process (Golden SAML)

  • T1059.001 — PowerShell

  • T1021.002 — SMB/WMI lateral movement

  • T1560.001 — Archive collected data

  • T1071.001 — Web protocols for C2 (HTTP/S to legitimate cloud services)

2. APT41 — Double Dragon / Winnti (China, MSS-linked)​

Article image

**Classification:**China Ministry of State Security contractor/affiliated group, active since at least 2012 MITRE ATT&CK:G0096 **Primary mission:**Dual — state-directed espionage AND financially motivated cybercrime (ransomware, cryptocurrency theft, virtual goods)

**Why chosen:**APT41 is the clearest documented case of a single group conducting both state espionage and opportunistic cybercrime. Their toolset is wide, their targeting is broad, and their TTPs are well-documented across multiple vendor reports and U.S. DOJ indictments (2019, 2020). They generate excellent examples of: exploitation chain detection, supply chain DLL hijacking, custom malware staging, living-off-the-land with LOLBins, and multi-phase intrusion correlation.

Key campaigns and public reporting:

  • **Operation ShadowHammer (ASUS Live Update):**Kaspersky Apr 2019

  • **Healthcare/COVID research targeting:**FBI-CISA May 2020

  • **Citrix/ManageEngine exploitation wave:**Mandiant 2022–2023

  • **DOJ indictments:**Sep 2019 (two defendants), Sep 2020 (five defendants)

  • **KEYPLUG / DEADEYE / DUSTPAN malware family:**Mandiant Apr 2022

Core TTP profile:

  • T1190 — Exploit public-facing application (Citrix, ManageEngine, Log4Shell)

  • T1505.003 — Web shell deployment

  • T1574.002 — DLL side-loading (very characteristic of this group)

  • T1036.005 — Match legitimate name or location (masquerading)

  • T1055 — Process injection

  • T1003.001 — LSASS memory dump

  • T1021.006 — WinRM lateral movement

  • T1567.002 — Exfiltration to cloud storage

3. Lazarus Group — HIDDEN COBRA / Diamond Sleet / TraderTraitor (DPRK, RGB)​

Article image

**Classification:**North Korean Reconnaissance General Bureau (RGB), active since at least 2009 MITRE ATT&CK:G0032 **Primary mission:**Revenue generation for the DPRK regime (cryptocurrency theft, financial fraud, sanctions evasion) AND targeted espionage (defense, nuclear, aerospace)

**Why chosen:**Lazarus provides the richest set of social-engineering-to-intrusion chain examples and is uniquely documented for financial system targeting. Operation Dream Job (fake LinkedIn recruitment), AppleJeus (trojanized crypto software), and the 3CX supply chain compromise give concrete cases for initial access detection. TraderTraitor is documented extensively by CISA, FBI, and the UN Panel of Experts. They generate excellent examples of: initial access via social engineering, cross-platform malware, BYOVD (bring-your-own-vulnerable-driver), and financial API abuse.

Key campaigns and public reporting:

  • **Operation AppleJeus:**Kaspersky Aug 2018, CISA Apr 2021 advisory (AA21–048A)

  • **Operation Dream Job:**ClearSky Jan 2020, Mandiant 2022 follow-up

  • **TraderTraitor (crypto targeting):**CISA/FBI/Treasury Apr 2022, FBI Mar 2023

  • **3CX Supply Chain:**Mandiant/CrowdStrike Apr 2023

  • **BYOVD (Dell DBUtil / POORTRY):**Mandiant Aug 2022, Microsoft Oct 2022

  • **UN Panel of Experts reports:**2021, 2022, 2023

Core TTP profile:

  • T1566.002 — Spear-phishing link (LinkedIn, email with weaponized PDF/ZIP)

  • T1204.002 — User execution of malicious file

  • T1195.002 — Supply chain compromise (3CX, trading software)

  • T1014 — Rootkit (BYOVD with POORTRY/WHIPEDOUT)

  • T1059.001 / T1059.003 — PowerShell and cmd scripting

  • T1041 / T1071.001 — Exfiltration and C2 over HTTPS

  • T1657 — Financial theft (cryptocurrency exchange API abuse)

  • T1070.004 — File deletion / indicator removal

Detection Taxonomy​

Before building rules, it helps to be precise about what each tier detects and what data sources it requires.

Detection Layer Definitions​

Atomic Event Rulesmatch a single telemetry event against a known-bad signature. The logic is essentially:IF event.field == bad_value THEN alert. No context required, no lookback, no correlation. Fastest to write, fastest to evade.

Collection-Based Rulesaggregate multiple events of thesame typeover a time window and alert when a threshold is crossed:IF count(event_type, 10 minutes) > threshold THEN alert. These detect volume-based techniques like brute force, port scanning, or bulk data staging.

Correlational Rulesjoindifferentevent types — process creation, network connection, file write, authentication — in a temporal sequence tied to a common entity (host, user, process). They model cause-and-effect chains: the attacker did A, then B, then C. Changing any one link breaks the rule; changing all three breaks the campaign.

TTP-Based Rulesdetect atechnique, not a specific tool implementing that technique. A TTP-based rule for credential dumping fires whether the actor uses Mimikatz, ProcDump, comsvcs.dll, or a custom tool — because all of them must access LSASS memory in a way that leaves a detectable behavioral footprint, regardless of file hash.

Anomaly Detection Rulesestablish a behavioral baseline per entity (user, host, service account, application) and alert on statistically significant deviations. They require historical data, a meaningful baseline period, and tolerance tuning. They are the hardest to build, the noisiest when poorly tuned, and the hardest for an adversary to evade in a well-baselined environment.

Required Log Sources by Layer​

Article image

**Rule format guide:**This article uses four distinct formats, indicated in each section header or code block:

Article image

Atomic Event Rules​

Article image

Atomic rules are the foundation. They are fast, deterministic, and directly traceable to a specific observable from a threat report. The key discipline is:every atomic rule must cite its source, have a defined false-positive profile, and be reviewed for continued relevance because indicators age out.

[Single-Event Detection Rules in Cybersecurity Introduction

1. APT29 — SUNBURST DLL Loaded by SolarWinds Process​

SUNBURST was delivered as a trojanized update toSolarWinds.Orion.Core.BusinessLayer.dll. The backdoor checked for the presence of specific security tools and domains before activating, with a dormancy period of up to two weeks. The most reliable atomic indicator during initial triage was the combination of parent process, DLL path, and subsequent DNS activity.

Large code or log block · 195 lines · expand raw text
title:
 
SUNBURST
 
Backdoor
 
DLL
 
Load
 
-
 
SolarWinds
 
Orion
id:
 
4a3f1c2e-8b7d-4e9f-a2c5-1d6e8f3b7a4c
status:
 
experimental
description:
 
>
  Fires when the SolarWinds Orion business layer DLL is loaded by the expected
  Orion host process. This is a triage trigger, not a high-confidence alert:
  the detection condition (parent + DLL path) matches both the trojanized and
  the legitimate DLL equally. The analyst must compare the loaded DLL hash
  against vendor-supplied known-good hashes to determine whether this event
  represents the SUNBURST backdoor or a normal Orion update. Use this rule to
  ensure every Orion DLL load is reviewed, not to declare an incident.
references:
  
-
 
https://www.mandiant.com/resources/blog/evasive-attacker-leverages-solarwinds-supply-chain-compromises-with-sunburst-backdoor
  
-
 
https://msrc.microsoft.com/blog/2020/12/customer-guidance-on-recent-nation-state-cyber-attacks/
author:
 
Detection
 
Engineering
date:
 
2020-12-14
modified:
 
2024-01-01
tags:
  
-
 
attack.initial_access
  
-
 
attack.t1195.002
  
-
 
apt29
  
-
 
sunburst
logsource:
  
category:
 
image_load
  
product:
 
windows
detection:
  
selection:
    
ImageLoaded|endswith:
 
'\SolarWinds.Orion.Core.BusinessLayer.dll'
    
Image|endswith:
 
'\SolarWinds\Orion\SolarWinds.BusinessLayerHost.exe'
  
condition:
 
selection
falsepositives:
  
-
 
Legitimate
 
SolarWinds
 
Orion
 
updates
 
—
 
verify
 
DLL
 
hash
 
against
 
known-good
    
values
 
from
 
vendor
 
in
 
your
 
triage
 
workflow.
 
Alert
 
on
 
any
 
hash
 
NOT
 
in
 
your
    
approved
 
baseline.
 
This
 
rule
 
fires
 
on
 
the
 
parent/child
 
relationship;
 
hash
    
validation
 
is
 
a
 
manual
 
triage
 
step,
 
not
 
part
 
of
 
the
 
detection
 
condition.
level:
 
medium
  
# Triage trigger only — fires on benign Orion updates too. Confidence is
               
# determined by the analyst's hash comparison, not by this rule alone.

**Detection note:**This is a triage rule, not a high-confidence alert. It fires on the parent/child process relationship — which matches both the malicious and legitimate DLL equally. Every fire requires the analyst to compare the loaded DLL hash against vendor-supplied known-good values before any escalation. The rule’s value is ensuring no Orion DLL load goes unreviewed, not detecting the backdoor directly. Hash validation against vendor-supplied known-good values is a manual triage step: compare the loaded DLL hash against your approved SolarWinds baseline after the rule fires. This design keeps the detection alive against packer-modified variants while ensuring the analyst always verifies the hash before escalating.

2. APT41 — Web Shell Creation in IIS Web Root​

APT41 consistently deploys web shells immediately after exploiting public-facing applications (Citrix, ManageEngine, Exchange). The shell is written to the web root by the compromised web application process. This is one of the highest-fidelity single-event detections available for this actor.

title:

Web

Shell

Created

by

IIS

Worker

Process
id:

7b2e4f1a-3c9d-4b8e-f1a7-2e5c8d3b6f9a
status:

experimental
description:

>
Detects file creation of known web shell extensions in IIS web root paths
by the IIS worker process (w3wp.exe). APT41 consistently uses this pattern
immediately after exploiting public-facing applications. This is a high-confidence
indicator of post-exploitation web shell deployment.
references:

-

https://www.mandiant.com/resources/blog/apt41-us-state-governments

-

https://www.cisa.gov/news-events/cybersecurity-advisories/aa22-277a
author:

Detection

Engineering
date:

2022-03-15
tags:

-

attack.persistence

-

attack.t1505.003

-

apt41
logsource:

category:

file_event

product:

windows
detection:

selection_process:

Image|endswith:

-

'\w3wp.exe'

-

'\tomcat.exe'

-

'\java.exe'

selection_extension:

TargetFilename|endswith:

-

'.aspx'

-

'.asp'

-

'.ashx'

-

'.asmx'

-

'.php'

-

'.jsp'

-

'.jspx'

selection_path:

TargetFilename|contains:

-

'\inetpub\wwwroot\'
- '
\Inetpub\wwwroot\'

-

'\wwwroot\'
filter_legitimate:
TargetFilename|contains:
- '
\App_Data\'

-

'\obj\'
condition: selection_process and selection_extension and selection_path and not filter_legitimate
falsepositives:
- Application deployments by legitimate CI/CD pipelines using the same process
- Content management system uploads (if CMS runs under w3wp.exe)
- Mitigate with change-window allowlisting
level: critical

3. Lazarus — Trojanized Installer Executed from User Download Path​

Lazarus’s AppleJeus and Dream Job operations deliver trojanized installers to targets, typically via spear-phishing or fake LinkedIn job offers. The trojanized application is executed from a user download or temp path and immediately spawns a child process inconsistent with the legitimate application behavior.

Large code or log block · 183 lines · expand raw text
title:
 
Suspicious
 
Installer
 
Spawning
 
Unexpected
 
Child
 
Process
id:
 
9c4e2a7f-5d1b-4c8e-b3f6-7a2e9d4c1b8f
status:
 
experimental
description:
 
>
  Detects installer-type executables (MSI, NSIS-style) spawning unexpected
  child processes from user-writable paths. Characteristic of Lazarus Group
  trojanized installer delivery (AppleJeus, Dream Job operations).
  The trojanized installer appears legitimate but spawns a second-stage dropper.
references:
  
-
 
https://securelist.com/operation-applejeus/87553/
  
-
 
https://www.cisa.gov/sites/default/files/publications/AppleJeus_Report_508.pdf
author:
 
Detection
 
Engineering
date:
 
2021-05-01
tags:
  
-
 
attack.execution
  
-
 
attack.t1204.002
  
-
 
attack.initial_access
  
-
 
attack.t1566.002
  
-
 
lazarus
logsource:
  
category:
 
process_creation
  
product:
 
windows
detection:
  
selection_parent:
    
ParentImage|endswith:
      
-
 
'\msiexec.exe'
      
-
 
'\setup.exe'
      
-
 
'\install.exe'
      
-
 
'\installer.exe'
    
ParentCommandLine|contains:
      
-
 
'\Users\'
      - '
\AppData\Local\Temp\'
      
-
 
'\Downloads\'
  selection_suspicious_child:
    Image|endswith:
      - '
\powershell.exe'
      
-
 
'\cmd.exe'
      
-
 
'\wscript.exe'
      
-
 
'\cscript.exe'
      
-
 
'\mshta.exe'
      
-
 
'\regsvr32.exe'
      
-
 
'\rundll32.exe'
  
condition:
 
selection_parent
 
and
 
selection_suspicious_child
falsepositives:
  
-
 
Legitimate
 
software
 
installers
 
that
 
invoke
 
PowerShell
 
for
 
post-install
 
config
  
-
 
Suppress
 
with
 
signed-installer
 
allowlist
 
(verify
 
Authenticode
 
chain)
level:
 
high

4. APT29 — TEARDROP Execution via Encoded Command​

TEARDROP was APT29’s second-stage memory-only dropper used to load Cobalt Strike Beacons after SUNBURST. It was observed executing via heavily encoded PowerShell commands. The following rule detects the specific encoding pattern combined with a suspicious parent relationship.

Large code or log block · 199 lines · expand raw text
title:
 
Heavily
 
Encoded
 
PowerShell
 
with
 
Suspicious
 
Parent
 
(TEARDROP
 
Pattern)
id:
 
2f8a1c4e-6d3b-4f7a-c2e8-5b1d4f8c3e7a
status:
 
experimental
description:
 
>
  Detects PowerShell executing with base64-encoded commands and suspicious
  parent processes. Associated with APT29 TEARDROP dropper behavior
  post-SUNBURST compromise. The combination of encoded command, explicit
  bypass flags, and non-standard parent is highly suspicious.
references:
  
-
 
https://www.microsoft.com/security/blog/2020/12/18/analyzing-solorigate-the-compromised-dll-file-that-started-a-sophisticated-cyberattack/
author:
 
Detection
 
Engineering
date:
 
2020-12-20
tags:
  
-
 
attack.execution
  
-
 
attack.t1059.001
  
-
 
attack.defense_evasion
  
-
 
attack.t1027
  
-
 
apt29
logsource:
  
category:
 
process_creation
  
product:
 
windows
detection:
  
selection_powershell:
    
Image|endswith:
      
-
 
'\powershell.exe'
      
-
 
'\pwsh.exe'
  
selection_encoded:
    
CommandLine|contains:
      
-
 
' -EncodedCommand '
      
-
 
' -enc '
      
-
 
' -e '
  
selection_bypass:
    
CommandLine|contains:
      
-
 
'-ExecutionPolicy Bypass'
      
-
 
'-ep bypass'
      
-
 
'-nop'
      
-
 
'-NonInteractive'
  
selection_suspicious_parent:
    
ParentImage|endswith:
      
-
 
'\SolarWinds.BusinessLayerHost.exe'
      
-
 
'\mmc.exe'
      
-
 
'\wbem\WmiPrvSE.exe'
      
-
 
'\services.exe'
  
condition:
 
selection_powershell
 
and
 
selection_encoded
 
and
 
selection_bypass
 
and
 
selection_suspicious_parent
falsepositives:
  
-
 
Legitimate
 
management
 
tools
 
using
 
encoded
 
PowerShell
 
for
 
config
 
tasks
  
-
 
Baseline
 
against
 
known-good
 
management
 
automation
 
before
 
deploying
level:
 
high

5. Cross-Platform: Linux /proc/mem Access by Non-Root Process​

On Linux, credential material is stored in process memory — SSH agent keys, sudo session tokens, cloud credential daemons (aws-credentials-helper, gcloud auth), and application secrets all live in the address space of running processes. Adversaries who compromise Linux hosts use/proc/<pid>/memdirect reads orptrace(PTRACE_PEEKDATA)to extract credential material from live processes without touching disk. This is the functional Linux equivalent of LSASS memory access on Windows: the underlying technique is the same (read another process's memory to steal credentials), only the OS mechanism differs.

Large code or log block · 317 lines · expand raw text
title:
 
Suspicious
 
/proc/mem
 
Access
 
or
 
ptrace
 
on
 
Credential
 
Process
 
by
 
Non-Root
id:
 
3b8f2e1a-6c4d-4b9f-e2a1-8c3f6d2b5e4a
status:
 
experimental
description:
 
>
  Detects non-root processes opening /proc/<pid>/mem for reading, or
  issuing ptrace(PTRACE_PEEKDATA) calls, against processes that hold
  credential material (sshd, sudo, cloud credential helpers).
  This is the Linux functional equivalent of LSASS memory access (T1003.001)
  and is used by adversaries to extract credentials from live process memory
  without writing to disk. Requires auditd with SYSCALL auditing enabled.
references:
  
-
 
https://attack.mitre.org/techniques/T1003/007/
  
-
 
https://www.man7.org/linux/man-pages/man2/ptrace.2.html
author:
 
Detection
 
Engineering
date:
 
2024-03-01
tags:
  
-
 
attack.credential_access
  
-
 
attack.t1003.007
logsource:
  
product:
 
linux
  
service:
 
auditd
  
# SCHEMA NOTE: In auditd SYSCALL records, a0–a3 are syscall arguments
  
# stored as hex integers, NOT as string paths. The filepath accessed by
  
# open/openat appears in a correlated PATH record (type=PATH, nametype=NORMAL)
  
# sharing the same serial number. Standard Sigma cannot express this
  
# cross-record join natively; the detection below uses the auditd key field
  
# (set via -k in audit rules) as the primary filter, combined with the
  
# SIEM-level PATH record join described in the implementation note.
  
#
  
# Use the auditd -k (key) flag to tag relevant syscalls, then filter in
  
# your SIEM on the key and join PATH records to confirm the /proc/*/mem path.
detection:
  
selection_proc_mem_open:
    
type:
 
'SYSCALL'
    
syscall:
      
-
 
'open'
      
-
 
'openat'
    
key:
 
'proc_mem_access'
   
# set by auditd rule: -k proc_mem_access
    
uid|not:
 
'0'
    
# Path filter (/proc/<pid>/mem) must be applied at SIEM level by joining
    
# the PATH record (type=PATH, nametype=NORMAL, name|contains='/proc/')
    
# that shares the same serial number as this SYSCALL record.
  
selection_ptrace_peek:
    
type:
 
'SYSCALL'
    
syscall:
 
'ptrace'
    
key:
 
'ptrace_peek'
       
# set by auditd rule: -k ptrace_peek
    
# a0 holds PTRACE_PEEKDATA (2) or PTRACE_PEEKTEXT (1)
    
# auditd logs a0–a3 as unsigned decimal integers WITHOUT 0x prefix
    
# in most kernel/auditd configurations. PTRACE_PEEKTEXT=1, PTRACE_PEEKDATA=2.
    
a0:
      
-
 
'1'
      
-
 
'2'
    
uid|not:
 
'0'
  
filter_target_process_benign:
    
# Filter known-safe callers by the CALLING process name (comm field)
    
# For target-process filtering (sshd, sudo), join OBJ_PID records
    
# in the SIEM — see implementation note below
    
comm|not:
      
-
 
'gdb'
      
-
 
'strace'
  
# Implementation note: auditd does not expose the target PID's process name
  
# in the SYSCALL record for /proc/<pid>/mem reads. To confirm the TARGET
  
# process is a credential holder (sshd, sudo, cloud-credential-helper),
  
# extract the numeric PID from the PATH record name field, then join against
  
# a concurrent PROCTITLE or EXECVE record with matching pid in the SIEM.
  
condition:
 
(selection_proc_mem_open
 
or
 
selection_ptrace_peek)
 
and
 
not
 
filter_target_process_benign
falsepositives:
  
-
 
Debuggers
 
(gdb,
 
strace)
 
run
 
by
 
developers
 
—
 
allowlist
 
by
 
supplementary
    
group
 
membership
 
(e.g.,
 
members
 
of
 
'debugger'
 
or
 
'dev'
 
group)
  
-
 
Java
 
and
 
JVM
 
profilers
 
that
 
use
 
/proc/*/mem
 
for
 
heap
 
inspection
  
-
 
Some
 
container
 
runtimes
 
that
 
inspect
 
child
 
process
 
memory
 
during
 
startup
  
-
 
Suppress
 
known-safe
 
callers
 
by
 
binary
 
path
 
and
 
UID,
 
not
 
just
 
process
 
name
level:
 
high

Auditd prerequisite rules(add to/etc/audit/rules.d/credential-memory.rules):

# Monitor open/openat syscalls by any non-root process and tag with key.
#
NOTE:
-F path=/proc monitors the /proc directory inode only — it does NOT
# match /proc/<pid>/mem subdirectory paths. Path filtering must be done at
# the SIEM layer by joining the PATH record (nametype=NORMAL) that shares
# the same serial number as this SYSCALL record.
-
a always
,
exit
-
F
arch
=
b64
-
S open
,
openat
-
F
uid
!=
0

-
k proc_mem_access
# Monitor ptrace PEEKDATA (a0=2) and PEEKTEXT (a0=1) calls by non-root.
# auditd -F a0= uses decimal values; auditd logs a0 in hex in the record,
# but the -F filter and Sigma a0 field both use decimal integers.
-
a always
,
exit
-
F
arch
=
b64
-
S ptrace
-
F
a0
=
1

-
F
uid
!=
0

-
k ptrace_peek
-
a always
,
exit
-
F
arch
=
b64
-
S ptrace
-
F
a0
=
2

-
F
uid
!=
0

-
k ptrace_peek

Collection-Based Rules​

Article image

Collection rules introduce temporal context. Rather than a single event, they watch for a pattern of events of the same type accumulating over a time window. The key design decisions are: what to count, what entity to group by, and what threshold to use.

Thresholds should be derived from your baseline, not invented. If you don’t know your normal authentication failure rate, you will either miss attacks or generate constant noise.

> Backend note: The rules in this section use Sigma’s aggregation syntax ( timeframe: + condition: ... | count() by ... ). This syntax is valid Sigma, but backend support varies. The Splunk, Elastic, and Sentinel backends in sigma-cli each transpile aggregation pipes differently. Test the transpiled output against your specific backend before deploying — the aggregated SPL or KQL may require minor adjustments to threshold syntax or field grouping.

1. APT29 — Spike in OAuth Token Requests from a New IP​

APT29’s 2023–2024 Microsoft intrusion abused OAuth device-code flow to obtain tokens for Microsoft Graph API access. The pattern involved a single source IP generating many token requests across multiple accounts. A collection rule catches the volume before a correlational rule catches the sequence.

Article image
title: OAuth Token Request Spike from Single Source IP
id: 1e3c7f9a-4b2d-4e8c-f7a3-9c1e4b7f2d8a
status: experimental
description: >
Detects an unusually high volume of OAuth2 token requests originating from
a single IP address within a short time window. APT29 used this pattern
in device-code phishing campaigns targeting M365 and Azure AD tenants.
Baseline your
normal token-request rate before setting thresholds.
Attribution note
: this technique is associated with Midnight Blizzard (APT29),

NOT
Volt Typhoon — these are distinct threat actors with no shared TTPs in
this technique.
Threshold
note
: run '
count
(distinct UserPrincipalName) by IPAddress,

bin
(TimeGenerated,
10
m)' against
90
days of historical SigninLogs
and
set
the threshold at p99.
5
of that distribution per IP,
not
a global constant.
references
:
-
https
:
//msrc.microsoft.com/blog/2024/01/microsoft-actions-following-attack-by-nation-state-actor-midnight-blizzard/
-
https
:
//www.microsoft.com/en-us/security/blog/2023/09/14/midnight-blizzard-compromises-microsoft-corporate-email-accounts/
author
: Detection Engineering
date
:
2024
-
01
-
26
tags
:
- attack.credential_access
- attack.t1528
- attack.initial_access
- attack.t1566
- apt29
logsource
:

product
: azure

service
: signinlogs
detection
:

selection
:

ResultType
:
'0'
# Successful token issuance

TokenIssuerType
:
'AzureAD'

AuthenticationProtocol
:
'deviceCode'

timeframe
:
10
m

condition
: selection |
count
(UserPrincipalName) by IPAddress >
5
# PLACEHOLDER — replace with value from your
90
-day baseline p99 per source IP. The value
5
is illustrative only.
falsepositives
:
- Automated provisioning workflows performing device enrollment
- VPN concentrators appearing as single IP for many users
level
: high
# Splunk equivalent:
# index=azure_signinlogs ResultType=0 AuthenticationProtocol=deviceCode
# | bucket _time span=10m
# | stats dc(UserPrincipalName) as unique_users by _time, IPAddress
# | where unique_users > 5

2. APT41 — Repeated Exploitation Attempts Against Same Service​

Article image

APT41 systematically probes and exploits public-facing services. Their pattern frequently shows multiple exploitation payloads in rapid succession against the same endpoint — testing different bypass variants — before a successful shell. A collection rule on WAF/IDS events or web server error logs catches this preparatory phase.

Large code or log block · 186 lines · expand raw text
title:
 
Repeated
 
Web
 
Application
 
Exploitation
 
Attempts
 
from
 
Single
 
Source
id:
 
3d7b2e5a-8f1c-4d9e-a3b7-2f5c8d1e4b7f
status:
 
experimental
description:
 
>
  Detects multiple web application exploitation attempt signatures
  (SQL injection, command injection, path traversal, deserialization)
  originating from a single IP against the same target within a short window.
  Characteristic of APT41 pre-exploitation enumeration against Citrix,
  ManageEngine, and Exchange endpoints.
references:
  
-
 
https://www.mandiant.com/resources/blog/apt41-initiates-global-intrusion-campaign-using-multiple-exploits
author:
 
Detection
 
Engineering
date:
 
2022-06-01
tags:
  
-
 
attack.initial_access
  
-
 
attack.t1190
  
-
 
apt41
logsource:
  
category:
 
webserver
  
product:
 
iis
  
# Field names below (sc-status, cs-uri-query, c-ip) are IIS W3C Extended
  
# Log Format fields. For Apache Combined Log Format, replace with:
  
# sc-status → status, cs-uri-query → request, c-ip → clientip.
  
# Adjust logsource product accordingly.
detection:
  
selection_exploit_pattern:
    
sc-status:
      
-
 
'400'
      
-
 
'403'
      
-
 
'404'
      
-
 
'500'
    
cs-uri-query|contains:
      
-
 
'../'
      
-
 
'%2e%2e'
      
-
 
'cmd='
      
-
 
'exec('
      
-
 
'${jndi:'
      
-
 
'union+select'
      
-
 
'eval('
      
-
 
'Runtime.exec'
  
timeframe:
 
5m
  
condition:
 
selection_exploit_pattern
 
|
 
count()
 
by
 
c-ip
 
>
 
10
falsepositives:
  
-
 
Legitimate
 
penetration
 
tests
 
(coordinate
 
with
 
red
 
team
 
schedule)
  
-
 
Vulnerability
 
scanners
 
(allowlist
 
known
 
scanner
 
IPs)
level:
 
high

3. Lazarus — Bulk File Staging Before Exfiltration​

Article image

Before exfiltrating cryptocurrency wallet files or financial documents, Lazarus operators stage data by compressing it into archives. A collection rule watching for rapid creation of multiple archive files by a single process catches this staging behavior regardless of the specific archiver used.

Large code or log block · 185 lines · expand raw text
title:
 
Bulk
 
Archive
 
Creation
 
Suggesting
 
Data
 
Staging
id:
 
6f2a4c8e-1b9d-4f3a-e8c2-4b7f1d6c9e2a
status:
 
experimental
description:
 
>
  Detects rapid creation of multiple archive files (ZIP, 7z, RAR, tar) by
  a single non-standard process. Lazarus Group consistently stages data into
  compressed archives prior to exfiltration. This rule catches the staging
  phase before exfiltration begins.
references:
  
-
 
https://www.cisa.gov/sites/default/files/2023-04/aa23-108a_joint_csa_dprk_cryptocurrency_theft_0.pdf
author:
 
Detection
 
Engineering
date:
 
2023-04-20
tags:
  
-
 
attack.collection
  
-
 
attack.t1560.001
  
-
 
attack.exfiltration
  
-
 
lazarus
logsource:
  
category:
 
file_event
  
product:
 
windows
detection:
  
selection_archive:
    
TargetFilename|endswith:
      
-
 
'.zip'
      
-
 
'.7z'
      
-
 
'.rar'
      
-
 
'.tar'
      
-
 
'.tar.gz'
      
-
 
'.tgz'
  
filter_legitimate_archivers:
    
Image|endswith:
      
-
 
'\7z.exe'
      
-
 
'\WinRAR.exe'
      
-
 
'\WinZip.exe'
  
timeframe:
 
3m
  
condition:
 
(selection_archive
 
and
 
not
 
filter_legitimate_archivers)
 
|
 
count(TargetFilename)
 
by
 
Image
 
>
 
5
  
# Parentheses required — pipe operator has lower precedence than 'and'/'not' in Sigma
falsepositives:
  
-
 
Backup
 
software
 
creating
 
many
 
archives
 
rapidly
  
-
 
CI/CD
 
build
 
pipelines
 
packaging
 
artifacts
  
-
 
Allowlist
 
known
 
backup
 
and
 
build
 
process
 
images
level:
 
medium

Correlational Rules​

Article image

Correlational rules are where detection becomes genuinely difficult for an adversary to evade without restructuring their operation. They require a SIEM capable of joining events across different log sources on a common entity — typically hostname, username, or process ID — within a defined time window.

The discipline here is choosing the right entities for joining and keeping correlation windows tight enough to reduce noise but wide enough to capture the actual technique timing.

1. APT29 — OAuth Token Grant Followed by Immediate Privileged Graph API Access​

The 2024 Midnight Blizzard intrusion into Microsoft’s corporate network followed a specific sequence: device-code phishing → token grant → immediate access to Microsoft Graph API for email and file enumeration. The correlation across authentication logs and application activity logs is highly specific.

PLATFORM-NATIVE ANALYTIC — Microsoft Sentinel KQL*(Not expressible as standard Sigma: requires cross-table join between SigninLogs and MicrosoftGraphActivityLogs with temporal window logic. Sigma has no native multi-source join or timeframe-with-offset semantics.)*

Prerequisites:

  • SigninLogsingested into Log Analytics workspace (Azure AD diagnostic settings)

  • MicrosoftGraphActivityLogsingested (Microsoft 365 diagnostic settings → Log Analytics)

  • Both tables must be present for the join to produce results

**ATT&CK:**T1528 (Steal Application Access Token), T1087.004 (Cloud Account Discovery) **Tags:**apt29, midnight-blizzard References:

**False positives:**Legitimate users accessing email immediately after OAuth grant on a new device. Allowlist known corporate IP ranges and managed device identifiers.

**Confidence when fires:**Critical — device-code token grant → privileged Graph access within 5 minutes is highly anomalous.

Article image
// Platform: Microsoft Sentinel
// IMPORTANT JOIN
NOTE:
MicrosoftGraphActivityLogs.UserId is an Azure AD
// object GUID (e.g. "f47ac10b-58cc-4372-a567-0e02b2c3d479").
// SigninLogs.UserPrincipalName is a UPN string (e.g. "user@contoso.com").
// Joining on UserPrincipalName when the GraphAccess side carries a GUID
// returns zero results. Join on UserId (GUID) present in both tables.
let
TokenGrants =
SigninLogs
|
where
AuthenticationProtocol ==
"deviceCode"
|
where
ResultType ==
0
| project
TokenTime = TimeGenerated,
UserId,
// GUID — join key
UserPrincipalName,
// UPN — display only
IPAddress,
CorrelationId;
let
GraphAccess =
MicrosoftGraphActivityLogs
|
where
RequestUri
has_any
(
"/me/messages"
,
"/users"
,
"/me/drive"
,
"/directory"
)
|
where
ResponseStatusCode
between
(
200
..
299
)
| project
GraphTime
= TimeGenerated,
UserId,
// GUID — join key
RequestUri;
TokenGrants
|
join
kind=inner (GraphAccess)
on
UserId
|
where
GraphTime
between
(
TokenTime .. (TokenTime +
5
m
))
| project
TokenTime,
GraphTime,
UserId,
UserPrincipalName,
IPAddress,
RequestUri,
CorrelationId

2. APT41 — Exploitation → Web Shell → Lateral Movement Chain​

APT41’s intrusion pattern is highly predictable: exploit a public-facing service, write a web shell, use the web shell to execute discovery commands, then move laterally via WMI or WinRM. Each step leaves traces in different log sources; the correlational rule joins them.

PLATFORM-NATIVE DESIGN SPEC — Splunk SPL pseudocode*(Not expressible as standard Sigma: requires multi-event temporal join across three different log sources — Sysmon Event IDs 11, 1, and 3 — within a time-windowed sequence. Sigma has no native multi-source sequence correlation syntax.)*

**ATT&CK:**T1505.003 (Web Shell), T1016 (System Network Configuration Discovery), T1021.006 (WinRM Lateral Movement) **Tags:**apt41 References:

**False positives:**Legitimate application deployments writing ASPX followed by diagnostics. Coordinate with change management to suppress during planned deployments.

**Confidence when fires:**Critical — three-phase chain within 30 minutes is high-confidence APT41-style post-exploitation.

Article image
Large code or log block · 239 lines · expand raw text
|
 comment 
"DESIGN SPEC — adapt index names, field names, and time windows to your environment"
|
 comment 
"Phase 1: Web shell file creation by web application process"
index
=
YOUR_SYSMON_INDEX
 
EventCode
=
11
    
Image
 
IN
 (
"*
\\
w3wp.exe"
,
"*
\\
java.exe"
,
"*
\\
tomcat.exe"
)
    
TargetFilename
 
IN
 (
"*.aspx"
,
"*.asp"
,
"*.php"
,
"*.jsp"
,
"*.jspx"
)
|
 eval phase1_time
=
_time, host_key
=
host
|
 table host_key, phase1_time, 
TargetFilename
|
 comment 
"Phase 2: Discovery commands from web process (within 5 min of phase 1)"
|
 join type
=
inner host_key [
    search index
=
YOUR_SYSMON_INDEX
 
EventCode
=
1
        
ParentImage
 
IN
 (
"*
\\
w3wp.exe"
,
"*
\\
java.exe"
,
"*
\\
tomcat.exe"
)
        
Image
 
IN
 (
"*
\\
whoami.exe"
,
"*
\\
net.exe"
,
"*
\\
ipconfig.exe"
,
                  
"*
\\
nltest.exe"
,
"*
\\
systeminfo.exe"
,
"*
\\
quser.exe"
)
    
|
 eval phase2_time
=
_time, host_key
=
host
    
|
 
where
 phase2_time 
>=
 phase1_time 
AND
 phase2_time 
<=
 phase1_time 
+
 
300
    
|
 table host_key, phase2_time
]
|
 comment 
"Phase 3: WMI/WinRM lateral movement (within 30 min of phase 1)"
|
 join type
=
inner host_key [
    search index
=
YOUR_SYSMON_INDEX
 
EventCode
=
3
        
Image
 
IN
 (
"*
\\
wmiprvse.exe"
,
"*
\\
wsmprovhost.exe"
)
        
DestinationPort
 
IN
 (
"5985"
,
"5986"
,
"135"
)
        
NOT
 [ search index
=
YOUR_SYSMON_INDEX
 
EventCode
=
3
              
|
 
where
 cidrmatch(
"10.0.0.0/8"
, 
DestinationIp
)
                   
OR
 cidrmatch(
"192.168.0.0/16"
, 
DestinationIp
)
                   
OR
 cidrmatch(
"172.16.0.0/12"
, 
DestinationIp
) ]
    
|
 eval phase3_time
=
_time, host_key
=
host
    
|
 
where
 phase3_time 
>=
 phase1_time 
AND
 phase3_time 
<=
 phase1_time 
+
 
1800
    
|
 table host_key, phase3_time
]
|
 table host_key, phase1_time, phase2_time, phase3_time, 
TargetFilename

3. Lazarus — Spear Phish Execution → Persistence → C2 Beacon​

Dream Job and TraderTraitor operations follow a documented sequence: user opens a weaponized document or installer, a dropper establishes persistence (Run key or scheduled task), and then a C2 beacon makes its first outbound connection. The correlational rule joins process creation, registry modification, and network events.

PLATFORM-NATIVE ANALYTIC — Elastic EQL*(Not expressible as standard Sigma: requires a native EQL**sequence*construct with*maxspan*and*by host.name*binding across three event categories. Sigma has no equivalent multi-event sequence syntax, and sigma-cli does not transpile to EQL.)

**ATT&CK:**T1566.001 (Spearphishing Attachment), T1547.001 (Registry Run Keys), T1071.001 (Web Protocol C2) **Tags:**lazarus, dream-job, trader-traitor References:

**False positives:**Macro-enabled Office templates that legitimately modify Run keys (rare). Software installers using Office interop. Verify Authenticode chain on the parent process before escalating.

**Confidence when fires:**Critical — three-stage chain on same host within 15 minutes.

Article image
/* Platform: Elastic Security (EQL Rule)
Requires: Sysmon-enriched endpoint events ingested into Elastic.

NOTE:
the ':' operator in EQL is case-insensitive and supports wildcards.
'like~' is NOT a valid EQL operator — use ':' for wildcard matching. */
sequence with maxspan
=
15m by host.name

/* Stage 1: Office/PDF spawns unexpected child */
[process
where
process.parent.name
in
(

"WINWORD.EXE"
,
"EXCEL.EXE"
,
"POWERPNT.EXE"
,

"AcroRd32.exe"
,
"msiexec.exe"
)
and process.name
in
(

"powershell.exe"
,
"cmd.exe"
,
"wscript.exe"
,
"mshta.exe"
)]

/* Stage 2: Child creates Run key or scheduled task persistence */
[registry
where
registry.path :
"*
\\
Software
\\
Microsoft
\\
Windows
\\
CurrentVersion
\\
Run*"
and process.name
in
(

"powershell.exe"
,
"cmd.exe"
,
"wscript.exe"
,
"mshta.exe"
,
"reg.exe"
)]

/* Stage 3: New process beacons to external IP on non-standard port */
[network
where
network.direction
==

"egress"
and not cidrMatch(destination.ip,

"10.0.0.0/8"
,
"172.16.0.0/12"
,
"192.168.0.0/16"
,
"127.0.0.0/8"
)
and destination.port not
in
(
80
,
443
)]

7. TTP-Based Rules​

TTP-based detection is the most durable layer. A rule that detects a technique survives tool changes, infrastructure rotation, and even operator changes within a group. The core insight:every technique has a minimum behavioral footprint that no implementation can fully avoid, because the footprint is determined by what the technique does to the operating system, not by how it does it.

1. LSASS Memory Access (T1003.001) — Technique Used by All Three Actor Groups​

All three APTs use credential dumping. APT29 uses Mimikatz variants and custom tooling. APT41 uses ProcDump and comsvcs.dll. Lazarus uses custom LSASS readers. All of them must open a handle tolsass.exewith read-memory access rights. The TTP rule catches all variants.

title: LSASS Memory Read Access by Non-System Process
id: 5e2c7a3f-1b8d-4e5c-a3f7-8c2e5b1d4a7f
status: experimental
description: >
Detects processes opening a handle to LSASS with memory-read access rights.
This is the universal footprint of LSASS-based credential dumping regardless
of the specific tool used — Mimikatz, ProcDump, comsvcs.dll MiniDump,
custom loaders, or any other implementation must
all open this handle.
Used by APT29, APT41, and Lazarus Group in documented operations.
references
:
-
https
:
//attack.mitre.org/techniques/T1003/001/
-
https
:
//www.microsoft.com/security/blog/2022/10/05/detecting-and-preventing-lsass-credential-dumping-attacks/
author
: Detection Engineering
date
:
2023
-
01
-
10
tags
:
- attack.credential_access
- attack.t1003.
001
- apt29
- apt41
- lazarus
logsource
:

category
: process_access

product
: windows

service
: sysmon
detection
:

selection
:
TargetImage|
endswith
:
'\lsass.exe'
GrantedAccess|
contains
:
-
'0x1010'
# PROCESS_VM_READ | PROCESS_QUERY_INFORMATION
-
'0x1410'
# PROCESS_VM_READ | PROCESS_QUERY_INFORMATION | PROCESS_DUP_HANDLE
-
'0x143a'
# typical Mimikatz
-
'0x1fffff'
# PROCESS_ALL_ACCESS
-
'0x1f3fff'
# PROCESS_ALL_ACCESS (older)

filter_legitimate
:
SourceImage|
endswith
:
-
'\MsMpEng.exe'
-
'\csrss.exe'
-
'\werfault.exe'
-
'\taskmgr.exe'
# remove if you don't allow task manager
-
'\svchost.exe'

condition
: selection
and

not
filter_legitimate
falsepositives
:
- EDR agents themselves (add your EDR process to filter_legitimate)
- Windows Error Reporting accessing LSASS during a crash
- AV scanning LSASS memory (rare but possible)
level
: critical

2. DLL Side-Loading (T1574.002) — Technique Illustrated by APT41 Operations​

APT41 is one of the most consistent users of DLL side-loading in documented threat activity. The technique requires a signed legitimate executable loading an unsigned or attacker-controlled DLL from the same directory. The TTP rule detects this regardless of which signed binary is abused.

Large code or log block · 216 lines · expand raw text
title:
 
Signed
 
Executable
 
Loading
 
Unsigned
 
DLL
 
from
 
Non-Standard
 
Path
id:
 
2b7f4e1a-6c3d-4b8f-e1a2-7c4b6d3f8e1a
status:
 
experimental
description:
 
>
  Detects a signed, legitimate executable loading an unsigned DLL from
  a user-writable or non-standard path. DLL side-loading (T1574.002) is
  used to execute malicious code under the cover of a trusted process.
  This rule is technique-based — it does not care which binary is abused
  or which actor is operating. APT41 is used as the illustrative example
  because of their documented consistent use of this pattern, but the rule
  will fire on any actor that exploits this technique.
references:
  
-
 
https://www.mandiant.com/resources/blog/apt41-dual-espionage-and-cyber-crime-operation
  
-
 
https://attack.mitre.org/techniques/T1574/002/
author:
 
Detection
 
Engineering
date:
 
2022-07-20
tags:
  
-
 
attack.defense_evasion
  
-
 
attack.persistence
  
-
 
attack.t1574.002
  
-
 
apt41
logsource:
  
category:
 
image_load
  
product:
 
windows
  
service:
 
sysmon
  
# Sysmon Event ID 7 (ImageLoaded): the fields Signed and SignatureStatus
  
# describe the LOADED DLL/image, not the loading (parent) process.
  
# To verify the loading process is itself a signed legitimate binary,
  
# you must join this event with a preceding Event ID 1 (ProcessCreate)
  
# on ProcessId, or use EDR-level enrichment that annotates the loading
  
# process's signing status at query time.
  
# There is no 'DllSigned' field in Sysmon — that field does not exist.
detection:
  
selection_unsigned_dll_in_userpath:
    
ImageLoaded|startswith:
      
-
 
'C:\Users\'
      - '
C:\ProgramData\'
      
-
 
'C:\Windows\Temp\'
      - '
C:\Temp\'
    
ImageLoaded|endswith:
 
'.dll'
    
Signed:
 
'false'
  
filter_known_paths:
    
ImageLoaded|contains:
      
-
 
'\AppData\Local\Microsoft\'
      - '
\AppData\Local\Google\'
  
condition:
 
selection_unsigned_dll_in_userpath
 
and
 
not
 
filter_known_paths
  
# LIMITATION: This rule detects unsigned DLLs loaded from user-writable paths.
  
# It cannot natively verify within a single Sysmon Event ID 7 whether the
  
# LOADING process is itself a signed legitimate binary. For full confidence,
  
# enrich with EDR telemetry that annotates the loading process signing status,
  
# or join with Event ID 1 (ProcessCreate) on the loading process's PID.
falsepositives:
  
-
 
Legitimate
 
applications
 
that
 
ship
 
with
 
unsigned
 
helper
 
DLLs
 
in
 
user
 
paths
  
-
 
Some
 
Python
 
distributions
 
and
 
development
 
toolchains
 
load
 
unsigned
 
DLLs
  
-
 
Build
 
an
 
environment-specific
 
unsigned
 
DLL
 
allowlist
 
per
 
application
level:
 
high

3. Bring Your Own Vulnerable Driver — Lazarus POORTRY/WHIPEDOUT (T1014)​

Lazarus used a Dell-signed but vulnerable driver (DBUtil_2_3.sys, laterPOORTRY) to disable EDR processes from kernel space. The BYOVD pattern produces two distinct detectable events: the driver load (Sysmon Event ID 6) and the subsequent security-tool process termination (Sysmon Event ID 5). These are written as two separate rules below. They must be correlated by the analyst or by a SIEM join within a 10-minute window onhost.name— a single event alone is lower confidence.

> WARNING: Never deploy hash-based rules with placeholder or unverified hashes. Pull current vulnerable driver hashes from https://www.loldrivers.io before production deployment. The example Dell DBUtil hash below is illustrative — verify it is still current and correct before use.

Rule 3a — Vulnerable Driver Load (Sysmon Event ID 6)

Large code or log block · 204 lines · expand raw text
title:
 
Known
 
Vulnerable
 
Driver
 
Loaded
 
(BYOVD
 
-
 
Phase
 
1
)
id:
 
9e3f6a2c-4d1b-4e9f-c2a6-3e8f1b4c7d2e
status:
 
template
description:
 
>
  Detects loading of a known-vulnerable signed driver consistent with
  BYOVD (Bring Your Own Vulnerable Driver) technique used by Lazarus Group
  (POORTRY, WHIPEDOUT, Dell DBUtil). Phase 1 of a two-rule correlation.
  Correlate with Rule 7.3b (security tool termination) within 10 minutes
  on the same host for high-confidence alert.
  WARNING: This rule will NOT fire until you populate the hash blocklist.
  Pull current vulnerable driver hashes from loldrivers.io and add them
  to the detection block before deployment. Never deploy with placeholder hashes.
references:
  
-
 
https://www.mandiant.com/resources/blog/hunting-attestation-signed-malware
  
-
 
https://www.microsoft.com/en-us/security/blog/2022/10/19/hunting-for-kernel-driver-abuse/
  
-
 
https://attack.mitre.org/techniques/T1014/
  
-
 
https://www.loldrivers.io
author:
 
Detection
 
Engineering
date:
 
2022-11-01
tags:
  
-
 
attack.defense_evasion
  
-
 
attack.t1014
  
-
 
lazarus
logsource:
  
category:
 
driver_load
  
product:
 
windows
  
service:
 
sysmon
detection:
  
selection_vuln_driver:
    
# -----------------------------------------------------------------------
    
# TEMPLATE — rule will not fire until hashes are populated.
    
# Obtain current vulnerable driver hashes from https://www.loldrivers.io
    
# and replace the sentinel string below with real SHA256 hashes.
    
# Example entry format (verify against loldrivers.io before use):
    
#   Hashes|contains:
    
#     - 'a3ad5f25e6...actual_sha256_from_loldrivers'
    
# -----------------------------------------------------------------------
    
# The sentinel string below is intentionally unmatchable — it ensures
    
# the rule produces zero results until real hashes are substituted.
    
# DO NOT remove it without replacing it with actual loldrivers.io hashes.
    
Hashes|contains:
      
-
 
'LOLDRIVERS_HASH_REQUIRED_SEE_DESCRIPTION'
    
Signed:
 
'true'
    
SignatureStatus:
 
'Valid'
  
condition:
 
selection_vuln_driver
falsepositives:
  
-
 
Legitimate
 
use
 
of
 
vulnerable
 
drivers
 
by
 
legacy
 
software
 
(remediate:
 
patch
 
or
 
remove)
  
-
 
Maintain
 
and
 
sync
 
loldrivers.io
 
blocklist
 
via
 
CI/CD
 
pipeline
  
-
 
Supplement
 
with
 
Windows
 
Defender
 
Application
 
Control
 
(WDAC)
 
or
 
Microsoft
 
Vulnerable
 
Driver
 
Blocklist
level:
 
high

Rule 3b — Security Tool Process Termination (Sysmon Event ID 5)

Large code or log block · 169 lines · expand raw text
title:
 
Security
 
Product
 
Process
 
Terminated
 
(BYOVD
 
-
 
Phase
 
2
)
id:
 
1f4a7c2e-8b3d-4f1a-e7c4-2b8f5d3a9e1c
status:
 
experimental
description:
 
>
  Detects unexpected termination of a known security product process.
  Phase 2 of a two-rule BYOVD correlation. On its own this is medium
  confidence (crash or update can cause same signal). Correlate with
  Rule 7.3a (vulnerable driver load) within 10 minutes on same host
  for high-confidence BYOVD alert.
references:
  
-
 
https://www.mandiant.com/resources/blog/hunting-attestation-signed-malware
  
-
 
https://attack.mitre.org/techniques/T1562/001/
author:
 
Detection
 
Engineering
date:
 
2022-11-01
tags:
  
-
 
attack.defense_evasion
  
-
 
attack.t1562.001
  
-
 
lazarus
logsource:
  
category:
 
process_termination
  
product:
 
windows
  
service:
 
sysmon
detection:
  
selection_security_tool_terminated:
    
Image|endswith:
      
-
 
'\MsMpEng.exe'
      
-
 
'\CSFalconService.exe'
      
-
 
'\CylanceSvc.exe'
      
-
 
'\cb.exe'
      
-
 
'\SentinelAgent.exe'
      
-
 
'\bdagent.exe'
      
-
 
'\ekrn.exe'
  
condition:
 
selection_security_tool_terminated
falsepositives:
  
-
 
Legitimate
 
EDR
 
agent
 
update
 
or
 
restart
 
(correlate
 
with
 
update
 
event
 
logs)
  
-
 
Planned
 
maintenance
 
with
 
change
 
ticket
  
-
 
Service
 
crash
 
due
 
to
 
unrelated
 
bug
level:
 
medium
  
# Escalate to critical when correlated with Rule 7.3a within 10 minutes

**Correlation note:**In Microsoft Sentinel, join these two rules onComputer(host) within a 10-minute window using a scheduled analytics rule. In Splunk, use| joinonhostacross both searches within the same time window. A standalone fire of either rule alone warrants investigation but not incident declaration.

4. Golden SAML — APT29 Authentication Bypass (T1556.006)​

Golden SAML attacks forge SAML assertions to authenticate as any user in federated identity environments. APT29 used this after compromising ADFS signing certificates. The behavioral footprint: a SAML authentication succeeds from an IP and device that have no prior authentication history, with no corresponding MFA event, for a highly privileged account.

PLATFORM-NATIVE ANALYTIC — Microsoft Sentinel KQL*(No**detection:*block: this logic requires a*leftanti*join against a 30-day historical window and a Watchlist variable — constructs that have no equivalent in Sigma syntax. sigma-cli would reject a Sigma rule with no*detection:*block.)

**ATT&CK:**T1556.006 (Modify Authentication Process — Golden SAML) **Tags:**apt29 References:

**False positives:**Legitimate federated sign-ins from new corporate IP ranges. Service accounts using certificate-based auth without MFA. Review with identity team before deploying.

**Confidence when fires:**Critical — SAML bypass with no MFA, new IP, and no prior history for a high-privileged account is highly anomalous.

// Platform: Microsoft Sentinel
// Define high_priv_accounts — choose one approach:
// Option A: Sentinel Watchlist (recommended for production)
// let high_priv_accounts = (_GetWatchlist('HighPrivAccounts') | project UPN);
// Option B: Hardcoded list (acceptable for initial testing only)
// let high_priv_accounts = datatable(UPN:string)[
// "admin@contoso.com", "globaladmin@contoso.com"
// ] | project UPN;
// Build this list from Azure AD Privileged Identity Management (PIM) directory roles:
// Global Administrator, Exchange Administrator, SharePoint Administrator, etc.
let
high_priv_accounts = (_GetWatchlist(
'HighPrivAccounts'
) | project UPN);
SigninLogs
|
where
AuthenticationRequirement !=
"multiFactorAuthentication"
|
where
ResourceDisplayName contains
"Federation"
|
where
ConditionalAccessStatus ==
"notApplied"
|
where
HomeTenantId != ResourceTenantId
// cross-tenant federation sign-in
|
join
kind=leftanti (
SigninLogs
|
where
TimeGenerated > ago(
30
d)
| summarize PreviousLogins=count()
by
UserPrincipalName, IPAddress
|
where
PreviousLogins >
0
)
on
UserPrincipalName, IPAddress
|
where
UserPrincipalName
in
(
high_priv_accounts
)
| project TimeGenerated, UserPrincipalName, IPAddress, AppDisplayName, Location

Anomaly Detection Rules​

Article image

Anomaly detection moves from “did this specific bad thing happen” to “did this entity behave in a way inconsistent with its established baseline.” These rules are the hardest to build, require the most tuning, and produce the most initial noise — but they are also the hardest for a sophisticated adversary to evade in an environment where baselines are maintained.

The prerequisite for every anomaly rule: a meaningful baseline period (minimum 30 days, ideally 90) and a per-entity, not per-environment, baseline. A global threshold on a single metric will catch only the loudest signals.

1. APT29 — Service Account Accessing Resources at Anomalous Hours​

APT29 uses compromised service accounts for long-dwell lateral movement. Service accounts have extremely predictable behavioral patterns — they typically authenticate at the same times, from the same systems, accessing the same resources. Any deviation is high-signal.

Article image
Anomaly Rule: Service Account Temporal Deviation
Entity:
Service account (identified
by
naming convention, e.g., svc_*, *-sa, *$)
Baseline dimension: Hour-
of
-day authentication distribution per account
Baseline period:
90
days
Metric:
Authentication events per hour
Anomaly condition: Authentication
in
an hour-bucket
with
zero
or
near-zero
historical frequency (>
3
standard deviations
from
mean)

AND
accessing a resource
not

in
the account
's access history
Alert payload must include:
- Account name
- Source IP
- Destination resource
- Time deviation
from
historical pattern
- Historical access pattern summary
Implementation note (Splunk MLTK):
| fit DensityFunction
"hour_of_day_auth_count"

by

"ServiceAccountName"

from
base_search

into
model:svc_temporal_model
| apply model:svc_temporal_model
|
where

'IsOutlier(hour_of_day_auth_count)' = 1
APT29 relevance: Compromised service accounts were used
in
SolarWinds post-compromise
for
months. The actors authenticated
outside business hours (UTC+
3
working hours observed
in
several
Mandiant/CrowdStrike analyses)
using
accounts that normally only
authenticated
09
:
00
-
17
:
00
local time.

Reference KQL implementation — 1 (review prerequisites before deploying)​

// Platform: Microsoft Sentinel
// Requires: UEBA enabled (BehaviorAnalytics table), SigninLogs ingested
// Baseline assumption: BehaviorAnalytics uses a rolling 30-day lookback
// maintained by Sentinel UEBA — no manual baseline setup required,
// but UEBA must be enabled for ≥30 days before signals are reliable.
// License note: BehaviorAnalytics requires Microsoft Sentinel UEBA feature
// (included in standard Sentinel workspace, but must be explicitly enabled
// in Settings → Entity behavior).
BehaviorAnalytics
|
where
TimeGenerated > ago(
1
d)
|
where
UserPrincipalName matches regex
@"^svc_|[-_]sa$|\$$"
|
where
ActivityInsights
has_any
(

"UncommonlyUsedApp"
,

"UncommonlyUsedDevice"
,

"FirstTimeUserUsedApp"
,

"ActivityFromInfrequentCountry"
)
|
join
kind
=inner (
SigninLogs
|
where
TimeGenerated > ago(
1
d)
|
where
UserType ==
"Member"
|
where
ResultType ==
0
| project
SigninTime = TimeGenerated,
UserPrincipalName,
IPAddress,
ResourceDisplayName,
Location,
AuthenticationRequirement
)
on
UserPrincipalName
|
where
SigninTime
between
(
TimeGenerated .. (TimeGenerated +
10
m
))
| project
BehaviorTime
= TimeGenerated,
SigninTime,
UserPrincipalName,
IPAddress,
ResourceDisplayName,
Location,
ActivityInsights,
AuthenticationRequirement
| order
by
BehaviorTime desc

2. APT41 — Vendor Software Loading Anomalous DLL Count​

APT41 abuses trusted software by planting DLLs in the application directory. A legitimate application’s DLL load profile is highly stable across versions — the same DLLs, from the same paths, in roughly the same order. A sudden expansion in the number or diversity of loaded DLLs from a vendor application is an anomaly that survives hash rotation.

Anomaly Rule: Vendor Application DLL Load Profile Deviation
Entity: (Vendor application executable, host)
Baseline dimension:

-
Count
of

unique
DLLs loaded
per
session

-
Distribution
of
DLL signing status (
%
signed
by
vendor cert)

-
Distribution
of
DLL load paths (
%

from
application directory)
Baseline
period
:
60
days
Anomaly conditions (
any

one
triggers):

-
DLL count
per
session
>
mean
+

2
SD

-

%
unsigned DLLs
in
session
>
mean
+

3
SD

-

Any
DLL loaded
from
a
user
-
writable path that has zero historical
frequency
for
this (application, host) pair
Vendor applications
to
prioritize:

-
Security tools (AV, VPN clients, backup agents)

-
Business applications
with
wide network access

-
IT management tools (SCCM agents, monitoring agents)
Implementation note:
Build a rolling
60
-
day
profile
per
(ImageLoaded parent, host) pair.

For

each

new
ImageLoad event, compare against the profile.
Statistical threshold: flag
any
DLL
where
frequency
in
baseline
<

1
%
.
APT41 relevance: KEYPLUG, DEADEYE,
and
DUSTPAN were
all
delivered
via DLL side
-
loading
into
legitimate vendor applications.
The vendor
binary
was signed
and
trusted; the sideloaded DLL was
not

in
the application
's historical load profile.

Reference KQL implementation — 8.2 (review prerequisites before deploying)​

// Platform: Microsoft Sentinel
// Requires: SecurityEvent (Windows Event Log) or DeviceImageLoadEvents (MDE)
// ingested. This query uses DeviceImageLoadEvents from Microsoft Defender
// for Endpoint via the AdvancedHunting schema.
// Baseline assumption: rolling 60-day lookback using summarize/dcount.
// Run this as a scheduled analytics rule on a 1-hour cadence.
// Note: "unsigned DLL from user-writable path" is the proxy for the anomaly;
// a proper ML baseline requires Sentinel UEBA or a custom watchlist of
// per-application DLL load histograms built from 60 days of DeviceImageLoadEvents.
let
BaselineDays =
60
d;
let
DetectionHours =
1
h;
// Step 1: Build per-(device, initiating process) DLL profile over baseline period
let
DLLBaseline =
DeviceImageLoadEvents
|
where
TimeGenerated
between
(
ago(BaselineDays
) ..
ago
(
DetectionHours
))
|
where
InitiatingProcessFileName !
in
~ (
"7z.exe"
,
"WinRAR.exe"
,
"WinZip.exe"
)
| summarize
BaselineDLLCount
= dcount(FileName),
BaselineUnsignedPct = countif(
not
(InitiatingProcessSignatureState ==
"Signed"
))
*
100
/ count()

by
DeviceName, InitiatingProcessFileName;
// Step 2: Measure current session (last 1 hour)
let
CurrentSession =
DeviceImageLoadEvents
|
where
TimeGenerated > ago(DetectionHours)
|
where
FolderPath matches regex
@"(?i)^C:\\(Users|ProgramData|Windows\\Temp|Temp)\\"
| summarize
CurrentDLLCount = dcount(FileName),
CurrentUnsignedPct = countif(
not
(InitiatingProcessSignatureState ==
"Signed"
))
*
100
/ count(),
UnsignedDLLNames = make_set(iff(

not
(InitiatingProcessSignatureState ==
"Signed"
),
FileName,
""
))

by
DeviceName, InitiatingProcessFileName;
// Step 3: Flag sessions where current metrics exceed baseline by ≥2 SD
// (approximated here as >2× baseline values — replace with MLTK percentiles
// if available via Sentinel Custom Analytics / Anomaly rules)
CurrentSession
|
join
kind=inner (DLLBaseline)
on
DeviceName, InitiatingProcessFileName
|
where
CurrentDLLCount > BaselineDLLCount *
2

or
CurrentUnsignedPct > BaselineUnsignedPct *
3
| project
DeviceName,
InitiatingProcessFileName,
BaselineDLLCount,
CurrentDLLCount,
BaselineUnsignedPct,
CurrentUnsignedPct,
UnsignedDLLNames
| order
by
CurrentUnsignedPct desc

3. Lazarus — Cryptocurrency Process Accessing Financial API Endpoints​

TraderTraitor and AppleJeus operations target cryptocurrency exchange employees and software. Once access is gained, operators use the victim’s legitimate credentials and applications to interact with exchange APIs. An anomaly rule on the volume, timing, and destination of financial API calls from a user’s session can detect this — a user who normally executes 5–10 trades per day suddenly executing hundreds, or doing so at 3AM local time.

Large code or log block · 199 lines · expand raw text
Anomaly Rule: 
User
 Financial API 
Call
 Volume 
and
 Timing Deviation
Entity: 
User
 account (tied 
to
 exchange employee 
or
 crypto software 
user
)
Baseline dimensions:
  
-
 Daily volume 
of
 API calls 
to
 trading
/
withdrawal endpoints
  
-
 
Time
-
of
-
day
 distribution 
of
 API calls
  
-
 Geographic origin 
of
 API calls (IP geolocation)
  
-
 Device fingerprint consistency
Baseline 
period
: 
90
 days
Anomaly conditions (weighted score; alert 
at
 threshold):
  [HIGH weight]   API 
call
 volume 
>
 mean 
+
 
4
 SD 
in
 
any
 
1
-
hour
 
window
        
+
40
  [HIGH weight]   Withdrawal API calls 
from
 a 
new
 geographic location        
+
40
  [HIGH weight]   API session 
from
 an IP 
with
 
no
 prior 
user
 history          
+
35
  [MEDIUM weight] API calls 
at
 an 
hour
-
bucket 
with
 
<
1
%
 historical frequency  
+
25
  [MEDIUM weight] 
New
 device fingerprint 
in
 session                          
+
25
  [LOW weight]    Multiple API key rotations 
in
 same session                 
+
15
Alert 
at
 score 
>=
 
60.
Implementation note:
  This style 
of
 rule 
is
 best implemented 
in
 a UEBA platform 
or
 a custom
  risk
-
scoring layer 
in
 your SIEM. 
Each
 
condition
 contributes 
to
 a
  
per
-
session risk score 
for
 the 
user
 entity. Threshold breach triggers
  an investigation alert, 
not
 a block (
initial
 deployment) 
or
 a step
-
up
  authentication challenge (mature deployment).
Lazarus relevance: TraderTraitor actors use compromised credentials
  
to
 initiate cryptocurrency withdrawals. The behavioral signature 
is
:
  legitimate credentials 
+
 
new
 IP
/
device 
+
 high
-
volume withdrawal
  
+
 unusual time. 
Each
 signal alone 
is
 ambiguous; combined they 
are
  high
-
confidence. The FBI 
and
 CISA April 
2022
 advisory documents
  this 
pattern
 across multiple exchange compromises.

Reference KQL implementation — 8.3 (review prerequisites before deploying)​

Large code or log block · 155 lines · expand raw text
// Platform: Microsoft Sentinel
// Requires: Custom log table (CryptoExchangeAPILogs_CL) from exchange API
//   gateway, or equivalent CommonSecurityLog/custom connector ingestion.
//   This query pattern applies to any API gateway log with UserAccount,
//   RequestType, SourceIP, and BytesSent fields.
// Baseline assumption: rolling 90-day lookback. Run as scheduled analytics
//   rule every 30 minutes. Replace CryptoExchangeAPILogs_CL with your
//   actual API log table name — this is an illustrative table name.
// Note: For exchange-specific SIEM integrations, adapt field names to match
//   your gateway log schema (e.g., cs-username, c-ip, cs-uri-stem).
let
 BaselineDays   = 
90
d;
let
 DetectionMins  = 
60
;
let
 WithdrawalVerbs = 
dynamic
([
"withdrawal"
, 
"transfer"
, 
"send"
, 
"payout"
]);
// Build per-user hourly baseline: mean and p95 as approximate spread proxy.
// Note: percentile(HourlyRequests, 95) is an approximation (T-Digest) —
// sufficient for anomaly thresholding but not exact statistical inference.
let
 UserBaseline =
    CryptoExchangeAPILogs_CL
    | 
where
 TimeGenerated > ago(BaselineDays)
    | 
where
 RequestType_s 
has_any
 (
WithdrawalVerbs
)
    
// Step 1: count requests per user per hour bucket
    | summarize
        HourlyRequests
 = count()
      
by
 UserAccount_s, hour_bucket = bin(TimeGenerated, 
1
h)
    
// Step 2: aggregate per-user statistics across all hour buckets
    | summarize
        BaselineMean    = avg(todouble(HourlyRequests)),
        Baseline95thPct = percentile(todouble(HourlyRequests), 
95
)
      
by
 UserAccount_s;
// Measure current window
let
 CurrentWindow =
    CryptoExchangeAPILogs_CL
    | 
where
 TimeGenerated > ago(DetectionMins * 
1
m)
    | 
where
 RequestType_s 
has_any
 (
WithdrawalVerbs
)
    | summarize
        CurrentRequestCount
  = count(),
        DistinctSourceIPs    = dcount(SourceIP_s),
        RequestedAmount      = sum(todouble(Amount_d))
      
by
 UserAccount_s, SourceIP_s;
// Score and alert
CurrentWindow
| 
join
 kind=inner (UserBaseline) 
on
 UserAccount_s
// Known-new IP: no prior logins from this IP for this user in baseline
| 
join
 kind=leftanti (
    CryptoExchangeAPILogs_CL
    | 
where
 TimeGenerated > ago(BaselineDays)
    | distinct UserAccount_s, SourceIP_s
) 
on
 UserAccount_s, SourceIP_s
| extend
    VolumeScore  = iff(CurrentRequestCount > Baseline95thPct * 
2
, 
40
, 
0
),
    NewIPScore   = 
40
,   
// already filtered to new IPs via leftanti join
    
// hourofday(now()) returns UTC hour, not local time. For non-UTC
    
// organizations, adjust: hourofday(now() + Xh) where X is your UTC offset.
    
// Example: UTC+3 → hourofday(now() + 3h). Hardcode offset or derive from
    
// a Watchlist if your org spans multiple timezones.
    HourScore    = iff(hourofday(now()) < 
6
 
or
 
hourofday
(
now(
)) > 22, 25, 0)
| extend TotalRiskScore
 = VolumeScore + NewIPScore + HourScore
| 
where
 TotalRiskScore >= 
60
| project
    UserAccount_s,
    SourceIP_s,
    CurrentRequestCount,
    Baseline95thPct,
    RequestedAmount,
    TotalRiskScore
| order 
by
 TotalRiskScore desc

4. APT29 — Unusual Outbound Data Volume from Service Following Token Grant​

APT29 post-compromise typically involves quiet, low-volume data exfiltration over extended periods — often weeks to months. But after a fresh OAuth token is issued, there is frequently a reconnaissance burst: the actor reads mailboxes, enumerates directories, or accesses SharePoint to map the environment. This produces a short-term data volume anomaly from the Microsoft Graph or Exchange APIs that is detectable against a per-account baseline.

Anomaly Rule: Post
-
Authentication Data Volume Burst
from
Cloud Service
Entity:
User
account (
in
cloud
identity

system
)
Trigger
event: OAuth2 token
grant
(
any
flow)
Measurement
window
:
60
minutes following token
grant
Baseline dimension: Bytes retrieved
from
cloud service APIs
per
session,

per

user
, rolling
90
-
day
distribution
Anomaly
condition
: Post
-
grant
data retrieval volume
>

95
th percentile

of
historical post
-
grant
sessions
for
this
user

AND
source IP has zero
or
low (
<
5
) prior session history
Alert enrichment
to
include:

-
Volume
of
data retrieved (bytes)

-
API endpoints accessed (Graph
/
me
/
messages,
/
drive,
/
users)

-
Number
of

distinct
objects accessed

-
IP geolocation
and
ASN

-
Comparison
to

user
's historical session volume
Implementation note (Microsoft Sentinel):
Join SigninLogs (token grant) with MicrosoftGraphActivityLogs
(subsequent API calls) on CorrelationId or UserId within a 1-hour window.
Aggregate ResponseBytes by UserId for the session.
Compare against a rolling 90-day per-user percentile model.
APT29 relevance: Documented in Microsoft'
s January
2024
disclosure.
Actors performed bulk mailbox enumeration
and
email reading
immediately after token issuance. The data volume
in
the
first

30
minutes
of
a compromised session was multiple orders
of
magnitude
above the same
user
's historical baseline.

Reference KQL implementation — 8.4 (review prerequisites before deploying)​

Large code or log block · 206 lines · expand raw text
// Platform: Microsoft Sentinel
// Requires: SigninLogs and MicrosoftGraphActivityLogs both ingested.
//   MicrosoftGraphActivityLogs requires Microsoft 365 diagnostic settings
//   configured to send Graph activity to the Log Analytics workspace.
// Schema note: both SigninLogs and MicrosoftGraphActivityLogs carry a UserId
//   field that is the same Azure AD object GUID. The join below uses UserId
//   (GUID) as the join key in both tables. Do NOT join on UserPrincipalName
//   against MicrosoftGraphActivityLogs.UserId — UPN vs GUID type mismatch
//   returns zero results. See §6.1 notes for full explanation.
// Baseline assumption: 90-day rolling per-user session volume percentile.
//   This query approximates the 90th percentile using a summarize over
//   the baseline window. For production, replace with a custom Anomaly
//   Detection scheduled rule or Watchlist-based percentile lookup.
let
 BaselineDays   = 
90
d;
let
 DetectionMins  = 
60
;
let
 SensitiveGraphPaths = 
dynamic
([
    
"/me/messages"
, 
"/users"
, 
"/me/drive"
,
    
"/directory"
, 
"/me/mailFolders"
, 
"/groups"
]);
// Schema notes for MicrosoftGraphActivityLogs (verified against Microsoft docs):
//   UserId            — string (Azure AD object GUID, e.g. "f47ac10b-...")
//   RequestUri        — string
//   ResponseBytes     — long  (native type; tolong() below is redundant but harmless)
//   ResponseStatusCode — int  (between 200..299 comparison is valid against int)
//   CallerIPAddress   — NOT present in standard MicrosoftGraphActivityLogs schema;
//                       enrich via SigninLogs join on CorrelationId if source IP needed
// Schema notes for SigninLogs (relevant fields):
//   UserId            — string (same Azure AD object GUID as above — valid join key)
//   UserPrincipalName — string (UPN, e.g. "user@contoso.com" — display only, not join key)
//   AuthenticationProtocol — string ("deviceCode" for device-code flow)
//   ResultType        — int   (0 = success)
//   IPAddress         — string
//   Location          — dynamic (LocationDetails object; project extracts the dynamic field)
// Step 1: Build per-user baseline — 90th percentile of ResponseBytes per session
let
 UserVolumeBaseline =
    MicrosoftGraphActivityLogs
    | 
where
 TimeGenerated > ago(BaselineDays)
    | 
where
 RequestUri 
has_any
 (
SensitiveGraphPaths
)
    | summarize SessionBytes
 = sum(ResponseBytes) 
by
 UserId, bin(TimeGenerated, 
1
h)
    | summarize Baseline90thPct = percentile(SessionBytes, 
90
) 
by
 UserId;
// Step 2: Identify device-code token grants in the last detection window
let
 RecentTokenGrants =
    SigninLogs
    | 
where
 TimeGenerated > ago(DetectionMins * 
1
m)
    | 
where
 AuthenticationProtocol == 
"deviceCode"
    | 
where
 ResultType == 
0
    | project
        TokenTime         = TimeGenerated,
        UserId,            
// GUID join key
        UserPrincipalName, 
// UPN — display only
        IPAddress,
        Location;
// Step 3: Measure Graph activity in the 60 minutes following each token grant.
// Look back 2× the detection window (DetectionMins * 2 * 1m) to ensure we capture
// Graph events that occurred before the query execution time.
let
 PostGrantActivity =
    MicrosoftGraphActivityLogs
    | 
where
 TimeGenerated > ago(DetectionMins * 
2
 * 
1
m)
    | 
where
 RequestUri 
has_any
 (
SensitiveGraphPaths
)
    | 
where
 ResponseStatusCode 
between
 (
200
 .. 
299
)
    | project
        GraphTime
     = TimeGenerated,
        UserId,        
// GUID join key
        RequestUri,
        ResponseBytes; 
// long — no cast needed, native type in schema
// Step 4: Join and flag sessions exceeding baseline
RecentTokenGrants
| 
join
 kind=inner (PostGrantActivity) 
on
 UserId
| 
where
 GraphTime 
between
 (
TokenTime .. (TokenTime + 
1
h
))
| summarize
    TotalResponseBytes
 = sum(ResponseBytes),
    EndpointsAccessed  = make_set(RequestUri),
    DistinctAPICalls   = count()
  
by
 UserId, UserPrincipalName, IPAddress, TokenTime, Location
| 
join
 kind=inner (UserVolumeBaseline) 
on
 UserId
// Null guard: users with insufficient baseline data (< 90 days of Graph activity)
// will have a null or zero Baseline90thPct. Exclude them to avoid divide-by-zero
// and spurious alerts on accounts with no established baseline.
| 
where
 
isnotnull
(
Baseline90thPct
) 
and
 Baseline90thPct > 0
| 
where
 TotalResponseBytes > Baseline90thPct * 3   
// >3× 90th percentile = anomaly
| extend
    BaselineExceedanceFactor
 = round(TotalResponseBytes / (Baseline90thPct + 
1
), 
1
)
| project
    TokenTime,
    UserPrincipalName,
    IPAddress,
    Location,
    TotalResponseBytes,
    Baseline90thPct,
    BaselineExceedanceFactor,
    DistinctAPICalls,
    EndpointsAccessed
| order 
by
 BaselineExceedanceFactor desc

The Detection Chain: Layering All Five Tiers​

Detection rules should not be evaluated in isolation. A single alert at any tier is an investigation trigger, not a confirmed incident. The value of layering is that correlation across tiers dramatically increases confidence and reduces analyst fatigue.

The following chain illustrates how all five tiers interact for the 3CX supply chain compromise (Lazarus Group, March 2023). 3CX is chosen because it demonstrates each tier firing on a different observable from the same incident — a property that makes it the clearest real-world example of why layers matter.

Large code or log block · 218 lines · expand raw text
[
ATOMIC
]         
3
CX desktop client (
3
CXDesktopApp.exe) loads d3dcompiler_47.dll
                 
from
 the application directory — 
binary
 name 
is
 legitimate,
                 but file hash does 
not
 
match
 the known
-
good vendor hash 
and
                 the DLL 
contains
 appended shellcode payload
                 → LOW confidence — known
-
good 
binary
 name flags the load path
                   anomaly; triage workflow compares hash against vendor baseline
                 ↓
[COLLECTION]     
Within
 a 
48
-
hour
 
window
, 
>
5
 hosts 
in
 the same environment
                 
execute
 the trojanized 
3
CX installer 
and
 subsequently 
connect
                 
to
 the same C2 FQDN cluster 
in
 HTTPS egress logs
                 (raw[.]githubusercontent[.]com 
/
 icon
-
staging repositories)
                 → MEDIUM confidence — abnormal install
-
rate 
pattern
 across
                   multiple endpoints 
to
 identical 
external
 infrastructure
                 ↓
[CORRELATIONAL]  
3
CXDesktopApp.exe spawns cmd.exe 
as
 a child process,
                 immediately followed 
by
 outbound HTTPS 
to
 github.com
/
IconStorages
                 (icon files containing base64
-
encoded C2 configuration);
                 a legitimate 
3
CX client has 
no
 documented reason 
to
 spawn
                 cmd.exe 
or
 
fetch
 
binary
 data 
from
 GitHub
-
hosted icon files
                 → HIGH confidence — two
-
event sequence 
on
 same host
/
process
                   lineage 
within
 
60
-
second
 
window
; escalated 
to
 Tier 
3
                 ↓
[TTP
-
BASED]      DLL side
-
loading 
pattern
 confirmed: signed 
3
CXDesktopApp.exe
                 loading an unsigned DLL 
from
 the application install directory
                 (T1574
.002
) — rule fires regardless 
of
 
specific
 DLL name
                 because the structural 
pattern
 (signed loader 
+
 unsigned DLL
                 
in
 same directory) 
matches
 the TTP independent 
of
 
any
 hash
                 → CRITICAL — technique confirmed, incident declared,
                   forensic acquisition initiated 
on
 affected hosts
                 ↓
[ANOMALY]        The service account associated 
with
 the 
3
CX application
                 begins authenticating 
to
 internal file servers 
and
 domain
                 controllers it has never previously accessed, 
at
 
02
:
00
 
local
                 
time
 — well outside its historical access
-
time
 distribution
                 (
for
 illustration: multiple standard deviations above the
                 
per
-
hour
 mean, exact figure depends 
on
 your baseline model)
                 
and
 accessing resources 
with
 zero prior session history
                 → Confirms 
lateral
 movement 
from
 compromised endpoint;
                   blast radius expanded 
to
 include downstream 
identity
                   infrastructure 
and
 file shares

At each tier, the analyst answers a different question — illustrated here using the 3CX incident:

  • **Atomic:**Does this specific DLL hash match a known-bad or non-baseline value for the 3CX application?

  • **Collection:**Are multiple hosts hitting the same C2 infrastructure after a recent 3CX update at an abnormal rate?

  • **Correlational:**Did the 3CX process spawn a shell and immediately fetch external binary data in the same session?

  • **TTP:**Is a signed binary loading an unsigned DLL from its own directory, regardless of which binary or DLL name is involved?

  • **Anomaly:**Is the service account associated with this application accessing systems and at times inconsistent with its 90-day behavioral baseline?

Alert Weighting Model​

A practical approach to managing alert volume across all five tiers is a per-incident risk score. Rather than treating each rule as a binary alert, assign a base score and let the score accumulate:

Article image

Multiple simultaneous rule fires on the same entity within a time window should be multiplicatively weighted, not additively: an atomic IOC hit plus a TTP rule fire plus an anomaly alert on the same user, same hour, is almost certainly a real incident.

> Scoring model disclaimer: The base scores and thresholds in this table are illustrative starting points, not validated empirical values. They must be calibrated against your environment’s actual false-positive rates and rule fidelity. Do not deploy with these exact numbers without a tuning period.

**Combined entity risk score formula:**When N rules fire on the same entity within the same detection window (60 minutes):

combined_score
= max(individual_scores) + Σ(remaining_scores ×
0.5
)

Example: TTP rule (70) + Anomaly multi-dimension (65) + Atomic behavioral (25) fire on the same user within the same hour:

combined_score
=
70
+ (
65
×
0.5
) + (
25
×
0.5
) =
70
+
32.5
+
12.5
=
115
→ Incident declaration

This formula prevents linear inflation while still rewarding corroborating signals. Adjust the 0.5 coefficient based on your environment’s baseline false-positive correlation. A coefficient closer to 1.0 rewards independent signals more aggressively; closer to 0.25 is appropriate when your rules share log sources and tend to co-fire on the same benign events.

Tuning, Validation, and Measurement​

1. Tuning Philosophy​

The failure mode for atomic and collection rules is high false positive rate, leading to alert fatigue and rule bypass. The failure mode for TTP-based and anomaly rules is insufficient telemetry, leading to missed detections.

Tune in this order:

Article image
  • **Start with the TTP-based rules.**They generate the fewest alerts but the most actionable ones. Tune the filter lists based on your legitimate software inventory.

  • **Add correlational rules next.**They require joined telemetry, so identify data gaps first. A correlational rule that joins on a log source you don’t have will never fire — even if the attack is present.

  • **Add collection rules.**Set thresholds from 30-day baseline data, not from intuition.

  • **Add atomic rules last.**These are cheapest to write and burn fastest. Accept that they will need monthly review.

  • **Deploy anomaly rules in monitor-only mode for the first 60 days.**Document the false positives, tune the entity exclusions, then set alert thresholds.

2. Validation: Testing Your Detection Coverage​

Every rule should be tested before production deployment and periodically thereafter. The minimum validation set for each detection layer:

Article image

Reference datasets for validation:

3. Measuring Detection Coverage​

Three complementary metrics matter:

**ATT&CK coverage score:**Map each rule you have to one or more ATT&CK technique IDs. Use the ATT&CK Navigator to visualize coverage gaps. A rule that fires on LSASS access covers T1003.001; a rule on web shell creation covers T1505.003. Build a coverage heatmap, prioritize the gaps that match your highest-priority adversary profiles.

**Mean Time to Detect (MTTD) by tier:**Log the time from simulated attack execution to alert generation for each tier. If your TTP-based rule for LSASS access takes 45 minutes to alert because of SIEM ingestion lag, that lag is the detection gap — address it in the data pipeline, not the rule.

**Alert fidelity rate:**Track confirmed true positives as a fraction of total alerts per rule over 30-day rolling windows. A rule below 10% fidelity rate should be tuned or retired. A rule at 100% fidelity over 90 days with zero fires should be tested — it may simply not be covering the technique it claims to cover.

4. Detection-as-Code Workflow​

Sigma rules in this guide (Sections 4 and 5, and the TTP rules 7.1–7.3) follow a detection-as-code pipeline:

CTI Report → Extract TTP
/
IOC → Write Sigma Rule → Code Review →
Test
in
Lab (
Atomic
Red Team
/
Mordor dataset) →
Merge

to
main → sigma
-
cli
convert
→ Deploy
to
SIEM →
Monitor fidelity → Review
on

30
-
day

cycle

Tools for this pipeline:

  • sigma-cli**:**Convert Sigma to Splunk SPL, Microsoft Sentinel KQL, Elastic Lucene/ES|QL, and others

  • pySigma**:**Python library for programmatic Sigma rule management

  • VECTR**:**Campaign tracking and red team exercise management (SecurityRiskAdvisors)

  • MITRE ATT&CK Navigator**:**Coverage visualization

> Note for Elastic users: sigma-cli converts Sigma rules to Elastic Lucene queries and ES|QL via the elasticsearch or esql backend. It does not produce native EQL (Elastic Event Query Language), which has distinct sequence syntax ( sequence by ... [process where ...] [network where ...] ). The correlational rules in Section 6 that use EQL sequence syntax must be written or adapted manually — they cannot be auto-generated from Sigma using current backends (as of early 2026).

Rule Lifecycle and Versioning​

Detection rules are not static artifacts. They decay as infrastructure changes, attackers adapt, and platform schemas evolve. A production detection program needs an explicit lifecycle policy.

Versioning convention

Sigma rules carry adateandmodifiedfield. Usemodifiedfor all updates — it is the authoritative version timestamp. Do not change theidUUID when updating a rule: a new UUID means a new rule, not a version bump. The UUID must be stable across the entire lifecycle of a rule. Use themodifieddate for version tracking, not a new UUID. For teams that need explicit semantic versioning, add acustomfield:

custom:

version:

'1.3.0'

# major.minor.patch — increment patch for filter tuning,

# minor for detection logic changes, major for technique scope changes

Five-tier review cadence

Article image

Deprecation criteria

A rule should be markedstatus: deprecatedand removed from production deployment when any of the following apply:

  • Itsfidelity rate(confirmed true positives ÷ total alerts) drops below**5%**over a 90-day rolling window despite reasonable tuning effort

  • Itslog source is decommissionedor a platform schema change breaks one or more field names in the detection condition

  • Ahigher-tier rule fully subsumes its detection surface: for example, a TTP-based LSASS rule that fires on all access-right patterns makes an older atomic rule that only checks one access mask redundant

Deprecated rules should be retained in source control with theirstatus: deprecatedflag and a comment explaining the deprecation reason and date. This preserves the analytical decision record and allows reactivation if the subsumption assumption later breaks.

Stable UUIDs — the non-negotiable rule

Every Sigma ruleidfield is a UUID that must never change after the rule is first published. If you fork a rule from the SigmaHQ repository and make changes, do not reuse the upstream UUID — generate a new one. Changing a UUID in your detection-as-code pipeline will break any alert tracking, suppression lists, or incident linkage that references the old UUID. Track what changed inmodified, not in theid.

Evasion Considerations: What Sophisticated Actors Do to Beat Each Layer​

The most important thing a detection engineer can understand about their own rules is exactly how they fail. Each detection tier has a characteristic evasion path that a motivated actor can follow — and that evasion path reveals precisely why the next tier up exists. This section is written from the attacker’s perspective, because that is the only perspective that produces honest detection coverage assessment.

1. Evading Atomic Rules​

Atomic rules match a specific observable: a file hash, an IP address, a domain name, a process name. The evasion options are trivial:

  • **Hash rotation:**Recompile the payload with a different compiler flag, swap a packer, or change a single byte in a resource section. The resulting hash is completely different; the functionality is identical. This takes minutes with automated build pipelines.

  • **Infrastructure rotation:**Rotate the C2 IP or domain before or immediately after the public report lands. Many sophisticated actors now run automated infrastructure provisioning that generates new IPs and domains on a schedule shorter than the typical report-to-blocklist lag. By the time an IOC appears in a threat feed and reaches a defender’s blocklist, it may already have been abandoned.

  • **File path and name manipulation:**A name-based atomic rule (Image|endswith: '\mimikatz.exe') is bypassed by renaming the binary. A rule that matches on both name and path is bypassed by moving it. Rules that depend on filenames rather than behavior are almost always trivially evaded.

  • **Stage-1 loader swap:**Even if the final payload hash is known, dropping a new loader that fetches and executes the payload in memory means the file that lands on disk (the loader) has never been seen before.

**Key insight:**Evading an atomic rule costs the attacker minutes to hours. Rotating infrastructure is now automated in many actor toolchains, making IP/domain IOCs useful for retrospective attribution but unreliable as real-time detection. The value of atomic rules is speed of deployment during an active incident — not durability.

2. Evading Collection Rules​

Collection rules fire when a count crosses a threshold within a time window. The evasion strategy is straightforward: operate below the threshold.

  • **Rate reduction:**If your collection rule fires on >10 OAuth token requests in 10 minutes from a single IP, spread the same 10 requests over 100 minutes. The individual events are identical; they simply no longer co-occur in the detection window.

  • **Source IP diversification:**Use residential proxies, compromised hosts, or cloud egress nodes to spread the same volume across multiple source IPs. Each source IP individually stays below the threshold even as the aggregate attack volume is unchanged.

  • **Threshold inference:**An attacker with access to your environment over an extended period can observe what volume of their own activity generates alerts. They calibrate their operational tempo to stay just below whatever ceiling your collection rules represent.

  • **Timing jitter:**Automated tools that generate bursty traffic are easy to detect with collection rules. Introducing human-like jitter (random delays, diurnal variation in request rate) causes the traffic to blend into legitimate usage patterns that are statistically similar to what the collection rule is trying to flag.

**Key insight:**A collection rule with a fixed global threshold is a ceiling that a patient attacker learns to operate under. The correct design is per-entity dynamic thresholds — percentile-based, derived from that specific entity’s own baseline — rather than environment-wide static values. A threshold that is appropriate for a high-volume user is almost certainly wrong for a service account.

3. Evading Correlational Rules​

Correlational rules join multiple events in a temporal sequence. Breaking any single link in the chain breaks the rule.

  • **Deliberate timing delays:**If your correlational rule fires on “web shell creation followed by lateral movement within 30 minutes,” the attacker simply waits 45 minutes between the web shell deployment and the first lateral movement command. The events are real and detectable individually; they just fall outside the join window.

  • **Tool substitution at one link:**A correlational rule that joins on specific process names (e.g.,wmiprvse.exe→ lateral movement) is broken by switching to a different lateral movement protocol that does not involve WMI — RDP, WinRM, SMB, SSH — because the named process no longer appears in the event stream at the expected link.

  • **Living-off-the-land at the join point:**If the correlation depends on detecting an unusual process (e.g., PowerShell spawned by a web server process), switching to a LOLBin that is routinely present in the environment (certutil, bitsadmin, msiexec) can make the individual events indistinguishable from legitimate administrator behavior. The join still fires, but the false-positive rate of the rule climbs to the point where the alert is suppressed or ignored.

  • **Multi-hop staging:**Rather than going directly from the compromised web server to lateral movement, an attacker can stage through an intermediate host that is not in your correlational rule’s scope, breaking the causal chain that the rule is designed to track.

**Key insight:**Correlational rules that join on process names rather than access patterns are broken by a single tool swap. The more durable design joins on what the process accessed, what permissions it requested, or what network destinations it reached — not what the executable was named. Behavioral joins survive tool changes; binary-name joins do not.

4. Evading TTP-Based Rules​

TTP rules detect a technique regardless of the specific tool implementing it. Evading them requires actually changing the underlying operating system interaction — a much higher cost.

  • **Memory-only techniques:**File-based TTP rules (DLL drops, web shell writes) are bypassed by moving entirely to memory-resident execution. Reflective DLL injection, process hollowing, and shellcode injected into existing processes produce no file creation events and do not trigger file-based TTP rules. LSASS access rules that rely on file-based indicators do not fire if credential dumping is performed via a legitimate API call that the rule does not monitor (e.g., SSP registration, shadow copies).

  • **Kernel-mode execution (BYOVD):**TTP rules that monitor process-level behavior are bypassed entirely if the attacker operates from kernel space. A driver running at ring 0 can suppress, modify, or replay telemetry before it reaches the EDR agent. This is why BYOVD (Bring Your Own Vulnerable Driver) is specifically used to kill EDR processes before conducting the high-value action.

  • **Abusing legitimate OS APIs:**A TTP rule for scheduled task creation that fires onschtasks.exeexecution is bypassed by creating the scheduled task directly via the Task Scheduler COM API (ITaskScheduler::AddWorkItem) from within a trusted process. The task is created; noschtasks.exeprocess is spawned; the rule does not fire.

  • **Legitimate tool execution:**If a TTP rule fires on PowerShell execution with encoded commands, switching to equivalent functionality in a language or runtime that is not monitored (Python via a legitimate interpreter, AutoHotkey, JScript in a .hta file) may achieve the same goal outside the detection perimeter.

**Key insight:**TTP rules fail when the technique’s required OS interaction is functionally indistinguishable from a legitimate privileged operation performed by the same class of process. The solution is not more pattern-matching on what the binary is called — it is contextual enrichment: who is calling this API, from which parent process, at what time, on what data, with what access rights. Context is what TTP rules alone cannot provide; anomaly detection and correlational rules supply the context.

5. Evading Anomaly Rules​

Anomaly detection is the hardest tier to evade, and the evasion strategies are correspondingly more sophisticated and time-intensive.

  • **Slow baseline poisoning:**Operate at low, legitimate-looking volume for 90 days or more before executing the high-value action. If the attacker’s traffic during the baselining period is indistinguishable from legitimate activity (because it IS low-volume legitimate-looking activity), the baseline absorbs it. When the attacker finally increases volume or changes behavior, the new baseline includes the attacker’s footprint, and the anomaly threshold is set relative to a contaminated baseline. This requires long dwell time but is within reach of patient state-sponsored actors with 6–12 month pre-positioning timelines.

  • **Behavioral mimicry:**If the attacker has observed the victim’s behavioral patterns (working hours, typical API call volume, device fingerprint, geographic login locations), they can deliberately mimic those patterns to remain within the normal band. A victim who always logs in from London between 09:00–17:00 and generates 50 API calls per session is relatively easy to impersonate if the attacker knows those parameters.

  • **Targeting baselining gaps:**Anomaly detection requires a baseline. New users, recently provisioned service accounts, new applications, or systems onboarded after a major change have short or absent baseline histories. These entities have high uncertainty in their anomaly models and are therefore poor targets for anomaly detection but excellent targets for attackers. A new employee’s account has no established behavioral baseline; any activity from it is, by definition, “normal” for that entity.

  • **Baselining horizon exploitation:**Most anomaly rules use a fixed lookback window (30, 60, 90 days). An attacker who compromises an account, conducts low-volume operations for 31 days, and then escalates has effectively aged their malicious activity outside the short-term anomaly window while remaining inside the baseline period — making their activity look like an established pattern.

**Key insight:**A well-resourced actor who has already conducted extensive reconnaissance may understand your environment’s behavioral baseline better than your own detection team does. Anomaly detection is hardest against patient actors with long dwell times — precisely the actors who represent the highest risk. The correct response is not to abandon anomaly detection but to ensure that the baseline includes multiple dimensions simultaneously (time, volume, geography, access pattern) so that mimicking all dimensions simultaneously becomes operationally difficult.

Synthesis: Why Layering Is the Only Correct Answer​

Each tier’s characteristic evasion path assumes the attacker is operating as if that tier were the only detection mechanism in place. An attacker who rotates hashes to evade atomic rules has not changed their tool, their technique, or their behavioral pattern — all of which remain visible to higher tiers. An attacker who slows their rate to evade a collection threshold has not changed the sequence of actions they take — which remains visible to correlational and TTP-based rules. An attacker who switches tools to break a correlational rule has still executed the same underlying technique, which remains visible to TTP-based detection. And an attacker who operates below every static rule threshold has still, inevitably, changed their behavior relative to what was normal for the compromised entity — which anomaly detection is designed to catch.

No single tier is sufficient. The correct architecture is all five tiers running simultaneously, with alert scoring that aggregates signals across tiers for the same entity within the same time window. An attacker who has successfully evaded four tiers while still being caught by the fifth has not successfully evaded your detection program.

Key Sources​

Adversary Behavior — Primary Intelligence Reports​

APT29 / Midnight Blizzard (SVR)

  • Mandiant,Highly Evasive Attacker Leverages SolarWinds Supply Chain(SUNBURST), December 2020 —mandiant.com

  • Microsoft MSTIC,Analyzing Solorigate: the compromised DLL file, December 2020

  • CISA, Advisory AA20–352A —Advanced Persistent Threat Compromise of Government Agencies, Critical Infrastructure, and Private Sector Organizations, December 2020

  • Microsoft Security Response Center,Microsoft Actions Following Attack by Nation State Actor Midnight Blizzard, January 2024

  • CyberArk Labs,Golden SAML: Newly Discovered Attack Technique Forges Authentication to Cloud Services, November 2019

  • Mandiant, APT29 ADFS abuse follow-up, 2021:https://www.mandiant.com/resources/blog/apt29-continues-targeting-microsoft

APT41 / Double Dragon (MSS-linked)

  • Mandiant,Double Dragon: APT41, a Dual Espionage and Cyber Crime Operation, August 2019

  • Mandiant,APT41 and Recent Activity, August 2022

  • U.S. Department of Justice,Seven International Cyber Defendants, Including “APT41” Associates, Charged, September 2020

  • CISA, Advisory AA22–277A —Impacket and Exfiltration Tool Used to Steal Sensitive Information from Defense Industrial Base Organization, October 2022

  • Kaspersky GReAT,Operation ShadowHammer, April 2019

Lazarus Group / TraderTraitor (RGB)

  • Kaspersky GReAT,Operation AppleJeus: Lazarus hits cryptocurrency exchange, August 2018

  • CISA/FBI/Treasury,TraderTraitor: North Korean State-Sponsored APT Targets Blockchain Companies, April 2022 (AA22–108A)

  • ClearSky,Operation Dream Job, January 2020

  • Mandiant / CrowdStrike,3CX Supply Chain Compromise, April 2023 —mandiant.com

  • FBI,Flash: Identification of Lazarus Group Cryptocurrency Theft, March 2023

  • CISA, Advisory AA21–048A —AppleJeus: Analysis of North Korea’s Cryptocurrency Malware, February 2021

BYOVD — Vulnerable Driver Research

  • Mandiant,Hunting Attestation Signed Malware (POORTRY/WHIPEDOUT), August 2022

  • Microsoft Security Blog,Hunting for Kernel Driver Abuse, October 2022

  • LoLDrivers project —loldrivers.io— community-maintained vulnerable/malicious driver hash reference

Telemetry and Schema References​

Detection Frameworks, Tooling, and Validation Datasets​

Evidence base: public threat intelligence through April 2026. Detection rules are illustrative; all thresholds, filter lists, and entity scopes require tuning for your environment before production deployment.

Follow for practical cybersecurity research​

If you’re interested in**Offensive security,**AI security, real-world attack simulations, CTI, and detection engineering— this is exactly what I focus on.

Stay connected:

→Subscribe on Medium:medium.com/@1200km →Connect on LinkedIn:andrey-pautov →GitHub — tools & labs:github.com/anpa1200 →Contact:1200km@gmail.com

Published · Last updated