BYOVD is not a magic trick anymore. Neither is slapping Ekko sleep obfuscation on a stock Havoc Demon and calling it stealthy. I’ve watched two separate engagements this quarter get lit up because someone pulled a C2 technique straight from a public blog post — including one of mine from 2024 — and assumed defenders haven’t been reading the same material.

They have. Some of them faster than us.

Let me tell you what’s actually happening with Havoc’s evasion stack right now, what still works, and what’s been burned.


Why This Matters Right Now

Havoc C2 (HavocFramework/Havoc) has become the go-to open-source framework for operators who want something that isn’t Cobalt Strike. The Demon implant ships with a genuinely impressive evasion toolkit: Ekko/Ziliean/FOLIAGE sleep obfuscation, indirect syscalls, AMSI/ETW patching via hardware breakpoints, return address spoofing. On paper, it’s a monster.

But here’s the problem. Every EDR vendor has Havoc samples. Their teams have been reversing the Demon agent for two years. Elastic has public detection rules for it. Microsoft Defender for Endpoint flags stock builds within minutes. The “stealth” is only as good as your customization — and most operators aren’t customizing.

The community is finally talking seriously about this. @C5pider (Havoc’s author) has been saying it implicitly for a while: the framework is a starting point, not a finished product. The whole point of the modular architecture is that you’re supposed to fork it, strip the signatures, change the defaults.


The Engagement That Hurt

Late last year I was on an internal red team assessment for a financial services company in Mumbai — mid-tier, around 800 employees, but well-funded IT security. They’d just rolled out CrowdStrike Falcon with kernel-level protection and had a 24/7 SOC on an MSSP contract. My first move was a BYOVD chain using a known vulnerable Realtek driver (the usual suspects: RTCore64.sys, exploiting the kernel read/write primitive to null out EDR callback routines). CrowdStrike caught the driver drop before I could even invoke the exploit. Under 3 minutes.

Fell back to a stock Havoc Demon with Ekko sleep obfuscation enabled. Same story — flagged within 8 minutes. The MSSP actually called the client’s IT head while I was still watching my terminal.

What eventually worked was a fully stripped Havoc build with a custom reflective loader, indirect syscalls compiled from scratch (not the built-in ones), and sleep obfuscation using a technique I’m calling “chained timers with stack spoofing” — basically combining the Ziliean approach with a manually built spoofed call stack so that when the memory scanner wakes us up during sleep, the stack trace looks like it’s coming from ntdll!NtWaitForSingleObject through a legitimate DLL. The key was making the sleeping shellcode look like it belonged to the process, not just encrypting it.

That’s the current meta. Not tools. Techniques applied with precision.


How Havoc’s Sleep Obfuscation Actually Works (And Where It Breaks)

Sleep obfuscation solves a specific problem: your shellcode sitting in executable memory is trivially scannable. When the implant is idle (between beacons), it encrypts itself, marks the memory as non-executable, waits, decrypts, and continues. The implementations Havoc ships are:

  • Ekko (crummie5/Ekko) — uses RtlCreateTimer and RtlRegisterWait to chain timer callbacks that do the encrypt → sleep → decrypt cycle while the main thread is sleeping.
  • Ziliean — similar concept, uses NtCreateTimer2 / NtSetTimer2 to avoid some of the more obvious Ekko IOCs.
  • FOLIAGE — uses SetFileCompletionNotificationModes + I/O completion ports to trigger the sleep. Clever but more complex.

Here’s what an Ekko timer chain looks like in memory — the WaitTimer routine that executes during the obfuscated sleep:

00007FFA4B221034  mov qword ptr [rsp+8],rbx
00007FFA4B221039  push rdi
00007FFA4B22103A  sub rsp,30h
00007FFA4B22103E  xor ebx,ebx
00007FFA4B221040  lea rax,[ntdll!RtlRegisterWait]
00007FFA4B221047  call qword ptr [rax]
; -> Encrypted shellcode region marked PAGE_NOACCESS
; -> XOR decrypt key in CONTEXT record

The problem is that all three ship with detectable patterns in how they build the CONTEXT structure for the ROP gadget chain. EDR products scan for the specific sequence of NtContinue calls with manipulated context registers. Defender for Endpoint has had this signature for months.

What actually works now:

// Stack spoof the sleep callback so it appears to originate from
// a legitimate DLL. Use a trampoline gadget inside ntdll.
PVOID spoof_frame = find_gadget(L"ntdll.dll", "jmp [rsp+48h]");

CONTEXT ctx = {0};
ctx.Rip = (DWORD64)NtWaitForSingleObject;
ctx.Rsp = (DWORD64)spoofed_stack;  // fabricated call stack
ctx.Rsp -= 8;
*(PVOID*)ctx.Rsp = spoof_frame;    // trampoline back into our code

Pair this with stomping the shellcode region to PAGE_READWRITE (not NOACCESS — the access change itself is an IOC on some sensors) and XOR encrypting in-place. Boring, manual, but way cleaner on memory scanners.


The Syscall Problem Nobody Talks About Enough

Havoc implements indirect syscalls for its Nt* API calls. The idea: instead of calling ntdll!NtAllocateVirtualMemory directly (where EDR hooks live in the prologue), you jump into the middle of the syscall stub after the mov eax, <syscall_number> instruction, then syscall from inside ntdll so the return address looks legitimate.

The basic indirect call in Havoc’s Demon looks something like this:

; Find the syscall stub in ntdll at runtime
; Jump past the EDR hook trampoline (first 5 bytes)
mov eax, SyscallNumber      ; e.g., 0x18 for NtAllocateVirtualMemory
mov r10, rcx
jmp qword ptr [SyscallAddr] ; points into ntdll's syscall instruction
syscall
ret

What’s breaking this now: Elastic’s defense team documented that they scan for jmp instructions that target syscall gadgets in ntdll. If your implant has a bunch of indirect calls all jumping to the exact same syscall; ret gadget address, that’s a pattern. They’re correlating the call frequency and the gadget address across threads.

The fix is gadget diversity — pull multiple different syscall; ret gadgets from different offsets in different loaded DLLs (ntdll, win32u.dll both work) and round-robin them. Yes, it’s annoying to implement. Yes, it matters.


The AMSI Patch That Got Me Caught

I need to document this failure because it was embarrassing.

Havoc patches AMSI and ETW via hardware breakpoints — elegant approach, doesn’t write to executable memory, avoids the classic amsi.dll patch detection. The breakpoint fires on amsi!AmsiScanBuffer, redirects execution, returns a clean result. I’d used this on maybe a dozen engagements.

On one engagement (a healthcare org, about six months ago), I got tagged within 20 minutes. I was confused until the blue team debrief. Turns out they were running AMSITrigger as a canary — a PowerShell script that intentionally triggers AMSI at regular intervals and alerts if the expected response doesn’t come back. My hardware breakpoint was eating the canary call.

I sat there for a second just appreciating the elegance of that defense. Then I went back and rewrote the AMSI bypass to only hook within a specific process context and spoof the return value more carefully instead of swallowing it entirely.

Real engagements teach you things no lab ever will.


Read These People

@C5pider is the Havoc author — his commits are worth reading if you want to understand where the framework is going. More importantly, read Alice Climent-Pommeret’s writeup on Havoc’s Ekko implementation — she goes deep on how the timer chain interacts with the kernel scheduler, which explains why some EDR sensors catch it from a behavioral angle rather than a signature angle.

@_RastaMouse has been writing about custom Havoc payloads and Operator API extensions for months. If you’re still using the default Demon binary without modification, you haven’t done your homework. His SharpC2 work also gives you a clean alternative C2 architecture to understand.

Also go read the Elastic Security team’s Havoc detection research — yes, read the defender’s writeup. Knowing exactly how you’re being caught is more valuable than any offensive blog post.

For BYOVD specifically: CVE-2024-51324 (Baidu AV driver) is the latest burned one. The loldrivers.io project maintains an updated list of exploitable drivers — use it to check what’s still viable, not to pick your next BYOVD target blindly.


Tangent: The Framework Monoculture Problem

Here’s something I think about more than I probably should: we have a monoculture problem in red teaming right now. Havoc, Sliver, Brute Ratel — everyone’s running the same three tools. When I see a job posting for a red teamer that lists “Cobalt Strike, Sliver, Havoc” as required skills, I think that company is optimizing for checkbox compliance, not actual adversary simulation.

Real APT groups don’t use Havoc. They write custom implants, or they live entirely off built-in tooling — WMI, PowerShell remoting, LOLBINs. The framework monoculture means defenders are getting very, very good at detecting exactly the tools most red teamers use. Which is great for defenders! Less great for us trying to actually test something.

The best engagement I’ve run in the past year used zero C2 frameworks. Pure scheduled tasks, WMI subscriptions, and abusing a misconfigured OAuth app in the target’s M365 tenant to exfiltrate data through Graph API calls that looked like a legitimate integration. No beaconing. No shellcode. Three weeks of dwell time.

Anyway. Back to sleeping Demons.


My Take

The free ride on open-source C2 frameworks is over. Not because they’re bad tools — Havoc is genuinely well-engineered — but because they’re public tools. The signature coverage is comprehensive. The behavioral analytics are tuned.

If you’re doing serious red team work and you’re dropping stock Havoc Demon binaries, you’re not testing the client’s defenses. You’re testing whether their EDR has up-to-date signatures. The answer is usually yes. You haven’t learned anything.

The operators doing interesting work right now are treating frameworks as build systems, not weapons. They’re taking the evasion primitives — sleep obfuscation, indirect syscalls, process injection — and building bespoke implementations tuned to the specific environment. That takes malware development skills, not just tool-running skills.

The gap between “I can use Havoc” and “I understand what Havoc is doing and can replicate it from scratch” is where real capability lives. Close that gap.


Hot Take

Red teamers who can’t write their own reflective loader shouldn’t be on engagements against mature EDR stacks. I’ll die on this hill. Knowing how to configure a framework is operations, not research. The industry is confusing tool proficiency with security knowledge, and clients are paying for assessments that amount to “we ran Havoc and it got caught, so your defenses are good.” That’s not red teaming. That’s a very expensive product demo.

Learn to write shellcode. Learn the Windows internals behind what your tools do. Then the detection arms race actually becomes interesting.


Tools and repos referenced in this post: