In advanced security operations, the line between “detected” and “invisible” is drawn at the syscall level. Since its inception, ICMP-Ghost (Ghost-C2) has focused on one goal: absolute invisibility.
With the release of v3.6.2, the project takes its most significant architectural leap: Dual-Channel Protocol Pivoting via an in-memory VTable. The implant can now hot-swap between Raw ICMP and DNS UDP tunneling at runtime — without restarting, without touching disk, and without leaving detectable artifacts. Combined with the existing PIC injection engine, VESQER compression, and layered DPI evasion — all written in pure x64 Assembly with zero external dependencies.
Ghost-C2 operates in two deployment modes: Standalone (direct binary execution) and Phantom Loader (PIC injection into a live host process). The techniques described below apply to both modes unless explicitly noted otherwise.
Architecture Overview

🔀 What’s New in v3.6.2: Dual-Channel VTable Architecture
The Problem with Single-Protocol C2
A C2 implant locked to one protocol is a C2 implant with a single point of failure. If ICMP is blocked at the network perimeter, the implant goes silent. If DNS anomaly detection kicks in, pivoting requires redeployment. Neither is acceptable in a production red team operation.
v3.6.2 solves this with an in-memory VTable — a function pointer table resident in the implant’s stack frame that defines which protocol engine handles all network I/O at any given moment.
VTable Architecture
The VTable lives at a fixed offset (rbp + 0x3000) within the implant’s stack anchor and holds three function pointers:
rbp + 0x3000 → _init (socket creation & binding)
rbp + 0x3008 → _recv (packet reception)
rbp + 0x3010 → _send (packet transmission)
On startup, the VTable is populated with ICMP function addresses by default. Every network operation calls through the VTable — not directly:
|
|
This means the protocol is completely transparent to the rest of the implant. The command parsing, compression, encryption, and fragmentation logic never change — only the three function pointers do.
Protocol Hot-Swapping (!D / !I Commands)
The operator triggers a protocol switch via two pivot commands embedded in the command stream:
| Command | Action |
|---|---|
!D |
Switch to DNS UDP tunneling on port 53 |
!I |
Switch back to Raw ICMP |
When !D is received:
|
|
The switch happens in-memory, in microseconds. No process restart. No disk write. The implant seamlessly transitions from one network protocol to another while remaining inside the host process.
DNS Tunneling Module
The DNS module implements full UDP-based command exfiltration over port 53:
- Encoding: Custom Base32 alphabet (
ABCDEFGHIJKLMNOPQRSTUVWXYZ234567) for QNAME encoding — output data is encoded into DNS label format and transmitted as DNS query Question sections - Transaction ID Integrity: ID high byte + ID low byte =
0xFF— any packet that fails this check is silently dropped - Decoy Domain: Configurable domain in the DNS Question section for traffic blending
- Port Configuration: Defaults to port 5300 for local testing; change to 53 for operational deployment
|
|
State Synchronization
Both the operator console (client.asm) and the implant (sniff.asm) maintain synchronized VTable state. When the operator issues !D, both sides switch their VTable simultaneously — the operator’s console updates its listening socket to DNS UDP, and the implant switches its beacon channel. Neither side needs to renegotiate; the protocol is defined by the command itself.
Why This Matters Operationally
- ICMP blocked at perimeter? Issue
!D, pivot to DNS — traffic now exits via port 53, which is almost never firewalled - DNS anomaly detection triggered? Issue
!I, pivot back to ICMP — no redeployment needed - Single implant, two egress paths — the defender must block both simultaneously to break the C2 channel
🛠 The Philosophy of Pure x64 Assembly
Most modern C2 agents are bloated by libc dependencies and predictable compiler signatures. Ghost-C2 breaks this mold by using zero-dependency x64 Assembly.
By interacting directly with the Linux Kernel, we achieve:
- Microscopic Footprint: A binary small enough to hide in the smallest memory pockets.
- Signature Neutralization: Static analysis tools fail to find standard library signatures or typical C-runtime artifacts.
- Total Register Control: Precise control over the execution flow, ensuring no unexpected side effects or “noisy” syscall sequences.
All syscall numbers are split across two instructions to defeat static analysis and simple grep-based scanners:
|
|
👻 Fileless Execution via memfd_create
The first rule of stealth is “Never touch the disk.” Disk I/O is the primary hunting ground for EDRs and AVs.
Ghost-C2 utilizes the sys_memfd_create (319) syscall to create anonymous, RAM-resident files. Command outputs are hijacked via sys_dup2 (33) and redirected to these memory-backed file descriptors:
fork()
child: dup2(memfd, stdout) → execve("/bin/sh", ["-c", cmd])
parent: wait4() → lseek(0) → read loop → compress → encrypt → fragment → send
The memfd is named [shm], matching the format of legitimate shared memory mappings in /proc/PID/fd.
The forensic implications differ significantly between deployment modes:
- Standalone Mode: The memfd appears under the agent’s own PID. When the agent process terminates, all associated file descriptors are destroyed — leaving nothing for traditional forensics to recover.
- Phantom Loader Mode: The memfd appears under the host process’s PID (e.g.,
cron). Critically, the memfd is created, read, and closed within milliseconds during each command execution cycle — it exists only for the brief window betweenfork()andsys_close(). Even continuous/procpolling is unlikely to catch it, and if it does, the file descriptor belongs to a legitimate system service. A transient[shm]descriptor undercronis indistinguishable from normal shared memory operations and raises zero suspicion.
🗜️ DPCM-RLE Hybrid Compression (v3.6.0)
The newest addition to Ghost-C2’s pipeline is the VESQER compression engine — a custom DPCM+RLE hybrid compressor built entirely in x64 Assembly.
The Algorithm
Ghost-C2’s data transmission engine utilizes a hybrid compression and encoding layer that reduces data volume while ensuring the traffic profile remains natural:
Differential Pulse Code Modulation (DPCM): Instead of transmitting raw ASCII values, the engine calculates and sends the mathematical difference (Delta) between a reference character (Anchor) and the subsequent ones. This method drastically lowers the entropy of data with similar character ranges.
|
|
Run-Length Encoding (RLE): Working in tandem with DPCM, the RLE engine packs consecutive repeating delta values — frequently seen in outputs like ls -la where spaces, permission blocks, and date formats repeat heavily:
|
|
Performance & Efficiency
The advantages provided by the hybrid engine have been verified through rigorous field testing:
- Compression Ratio: Achieves an average data reduction of 40% to 55% for text-based command outputs (ASCII/UTF-8).
- Transmission Speed: Because the data volume is reduced, the total packet count is cut nearly in half. This significantly shortens the transfer time for large datasets (20KB+), even while Adaptive Jitter is active.
- 100% String Fidelity: Stack offsets are strictly confined to a safe memory region (
0x100000), and synchronization desyncs have been eliminated. Massive datasets of 20KB+ (e.g.,/etcdumps) are delivered to the Client without a single bit of deviation.
Stealth & Evasion Contributions
Beyond speed, compression plays a critical role in the implant’s stealth capabilities:
- Reduced Packet Footprint: Reducing data size by nearly 50% radically lowers the number of ICMP packets sent over the network. Fewer packets minimize the risk of triggering anomaly detection in IDS/IPS systems.
- Natural Noise Simulation: The combination of DPCM and Rolling XOR maintains traffic entropy at a level that avoids the “suspiciously high” signatures of standard AES encryption. To external observers, the traffic appears as natural network noise or compressed hardware logs.
- No Magic Bytes: Unlike zlib (
0x78 0x9C), gzip (0x1F 0x8B), or LZ4 (0x04 0x22 0x4D 0x18), VESQER produces zero identifiable headers. NDR/DPI systems that flag known compression signatures find nothing to match.
Standalone Repository: VESQER Baremetal Compressor
🛡️ Stealth Features: Defeating DPI & Heuristics
Protocol Mimicry
Every outgoing ICMP packet is structured to be indistinguishable from a standard Linux ping:
Offset 0-7 : ICMP Header (Type, Code, Checksum, ID, SEQ)
Offset 8-15 : Dynamic RDTSC timestamp ← mimics struct timeval
Offset 16-31 : 0x10, 0x11 ... 0x1F ← exact Linux iputils padding
Offset 32+ : Encrypted payload ← past most DPI scan depth
Signature-based IDS engines (Suricata, Snort) see standard padding and stop scanning before reaching the payload. This is the Stealth Gap.
Asymmetric Authentication
The implant ignores all packets where ID + SEQ ≠ 45,000. Random internet scanners, automated security tools, and honeypots will never trigger it. The implant replies with packets where ID + SEQ = 55,000, making the two directions mathematically distinct and preventing OS echo confusion.
Rolling XOR Cipher
Both directions are encrypted with a progressively shifting key:
|
|
This keeps Shannon entropy controlled — AES-encrypted ICMP traffic scores ~8.0 and triggers DPI anomaly alerts. Rolling XOR produces entropy that looks like compressed or naturally noisy data. No cryptographic constants, no S-boxes, nothing for YARA to match.
Adaptive Jitter (RDTSC-based)
Packet transmission intervals are randomized using the CPU’s hardware timestamp counter, not software timers. This produces timing patterns that are mathematically non-periodic — ML-based NTA engines (Darktrace, Cisco Stealthwatch) require periodicity to flag C2 beaconing:
|
|
Data Fragmentation
Large command outputs are automatically fragmented into 56-byte chunks, yielding 88-byte total ICMP packets (Header + Mimicry + Payload). This matches the standard Linux diagnostic ping profile and avoids triggering “MTU Exceed” or “Large Payload” signatures.
🎭 Process Identity: Standalone vs. Phantom Loader
How Ghost-C2 hides in the process tree depends entirely on the deployment mode:
Standalone Mode: Using sys_prctl (157) and manual argv[0] stack manipulation, the agent renames itself to a legitimate service (e.g., systemd-resolved). This defeats casual inspection via ps and htop, but /proc/PID/exe still points to the original binary path — a forensic artifact that a thorough investigator can uncover.
Phantom Loader Mode: Masquerading becomes irrelevant — the agent doesn’t exist as a separate process. It runs inside the host’s address space. The process tree shows only the legitimate host:
$ ps aux | grep cron
root 828 0.0 0.0 18176 3092 ? Ss Apr10 0:00 /usr/sbin/cron -f -P
root 17028 0.0 0.0 24196 1756 ? Ss 05:34 0:00 /usr/sbin/cron -f -P
One of these is the real cron. The other is Ghost-C2 running inside a cloned cron instance. Even /proc/PID/exe points to /usr/sbin/cron — because it is cron. The process lineage, binary path, and command-line arguments are all legitimate. There is nothing to masquerade because the disguise is structural, not cosmetic.
🔮 Phantom Loader — In-Memory PIC Injection (v3.5)
With the v3.5 release, Ghost-C2 transitions from a standard executable to a 100% Position Independent Code (PIC) memory-resident threat. Modern Linux kernels employ ruthless mitigations like Memory-Deny-Write-Execute (MDWE), NX, and strict ASLR. Ghost-C2 defeats these armors by executing entirely within the memory space of legitimate, unconfined root services.
The Injection Chain
The loader performs a deterministic, multi-step injection without any external dependencies:
1. Open /proc with sys_getdents64
2. Scan linux_dirent64 entries for numeric directories (PIDs)
3. Read /proc/<PID>/comm → compare against target name
4. ptrace(PTRACE_ATTACH, pid)
5. wait4() loop with branchless sleep (cmovz/cmovs)
6. PTRACE_GETREGS → save register state + RIP
7. PTRACE_POKEDATA → write syscall opcode (0x050F) at RIP
8. PTRACE_SETREGS → configure mmap arguments in registers
9. PTRACE_SINGLESTEP → execute remote mmap
10. wait4() → PTRACE_GETREGS → read mmap return value
11. PTRACE_POKEDATA loop → write PIC payload (8 bytes/iter)
12. PTRACE_SETREGS → configure mprotect (PROT_READ | PROT_EXEC)
13. PTRACE_SINGLESTEP → execute remote mprotect
14. PTRACE_POKEDATA → restore original bytes at RIP
15. PTRACE_SETREGS → set RIP = injected payload address
16. PTRACE_DETACH → host process resumes, now running the implant
The loader exits immediately after step 16. The host process continues its normal operation with Ghost-C2 running inside it.
W^X (Write XOR Execute) Evasion
Modern kernel mitigations forbid RWX memory. The loader uses a two-phase approach:
Phase 1: Remote mmap with PROT_READ | PROT_WRITE
→ Inject shellcode via PTRACE_POKEDATA
Phase 2: Remote mprotect → PROT_READ | PROT_EXEC
→ No page is ever simultaneously W and X
EDR memory scanners looking for RWX anomalies find nothing. The injected region appears as a legitimate r-xp mapping — indistinguishable from a shared library in /proc/PID/maps.
🔒 Payload Obfuscation (v3.5.5)
The agent payload is no longer stored in clear-text within the loader binary. It is pre-encrypted externally using an 8-byte (QWORD) Little-Endian XOR key. Decryption occurs dynamically within CPU registers only during the injection phase, ensuring the raw shellcode never touches the disk or loader memory in an unencrypted state.
Static Analysis Bypass
By obfuscating the payload, all static opcode signatures and recognizable syscall/ptrace patterns have been eliminated from the loader’s binary, effectively neutralizing signature-based detection.
Entropy Optimization
By opting for a streamlined XOR operation instead of high-entropy ciphers like AES or RC4, the file’s Shannon Entropy is maintained at a stealthy level (~6.0). This prevents triggering “Packed/Encrypted Malware” heuristic alerts common in modern EDR solutions:
DECIMAL HEXADECIMAL ENTROPY
------------------------------------------------------------------------
0 0x0 Falling entropy edge (0.060281)
9216 0x2400 Falling entropy edge (0.541848)
No critical high-entropy spikes that would flag the binary as a malicious packer.
🏗 Architectural Decision: Why No Interactive TTY?
A common question is: “Why no full PTY support?” In Ghost-C2, the absence of an Interactive TTY is a deliberate OPSEC choice.
- DPI Avoidance: TTYs require stateful, high-frequency data streams (every keystroke), which creates an “ICMP Storm” that triggers anomaly rules.
- Behavioral Artifacts: Allocating a PTY requires
ioctlsyscalls and/dev/ptmxaccess — actions heavily monitored by modern EDRs.
Ghost-C2 is a stateless exfiltration tool, not a remote admin utility. We trade convenience for absolute invisibility.
💻 Syscall Inventory (The Ghost’s DNA)
| Syscall | Function | Purpose |
|---|---|---|
sys_socket (41) |
Raw ICMP / UDP Socket | Protocol-agnostic lower-level network access |
sys_recvfrom (45) |
Packet Reception | ICMP / DNS listener (VTable-routed) |
sys_sendto (44) |
Packet Transmission | ICMP / DNS response with jitter (VTable-routed) |
sys_memfd_create (319) |
Anonymous RAM File | Fileless execution |
sys_fork (57) |
Process Forking | Command execution isolation |
sys_execve (59) |
Shell Execution | /bin/sh -c command runner |
sys_dup2 (33) |
I/O Redirection | stdout/stderr → memfd |
sys_nanosleep (35) |
Randomized Jitter | Beaconing disruption |
sys_prctl (157) |
Process Control | Masquerading & anti-dump |
sys_ptrace (101) |
Process Manipulation | Injection & anti-debug |
sys_mmap |
Memory Allocation | Remote RW region creation |
sys_mprotect |
Permission Control | RW → RX transition |
sys_getdents64 |
Directory Listing | /proc PID enumeration |
🛡️ Defense Analysis & The OPSEC Reality
From a Blue Team perspective, detecting an implant like Ghost-C2 requires moving beyond signature-based detection. The following analysis covers both deployment modes and their respective attack surfaces.
1. ICMP Payload Entropy vs. DPI Depth Limits
- The Defense: Blue teams monitor for high-entropy data in ICMP segments to detect encrypted tunneling.
- The OPSEC Reality: Ghost-C2 leverages “DPI Depth Limits”. The high-entropy payload is pushed past the 32-byte mark, hidden behind legitimate
0x10-0x1Fmimicry padding. Performance-tuned DPI engines like Suricata often classify the packet as “safe” before even reaching the encrypted payload. Additionally, with VESQER compression applied before Rolling XOR, the entropy profile avoids the ~8.0 ceiling that flags AES-encrypted traffic.
2. Protocol Pivot Detection
- The Defense: Alerting on sudden protocol shifts — e.g., a host that was sending ICMP traffic suddenly generating DNS queries.
- The OPSEC Reality: The pivot is operator-controlled and can be timed to coincide with natural DNS traffic windows. DNS queries to a configured decoy domain blend with normal resolution traffic. The transaction ID integrity check (
ID_high + ID_low = 0xFF) means only the legitimate operator can interact with the implant — random DNS traffic is silently dropped.
3. Anonymous FD Auditing (memfd Detection)
- The Defense: Inspecting
/proc/[pid]/fd/for links tomemfd:is a known technique for finding RAM-resident files. - Standalone Mode: This defense is viable if continuous host-level polling (Auditd/eBPF) is deployed. The memfd persists under the agent’s own PID for the duration of each command execution cycle.
- Phantom Loader Mode: This defense becomes nearly ineffective. The memfd is created, read, and destroyed within milliseconds during each command cycle — and it appears under the host process’s PID. A brief
[shm]descriptor undercronis indistinguishable from normal shared memory operations. Even aggressive eBPF polling would need sub-millisecond sampling to catch it, and even then, the descriptor belongs to a trusted system service.
4. Process Lineage & SOCK_RAW Detection
- The Defense: Alerting on processes that utilize
SOCK_RAWbut aren’t recognized network services. - Standalone Mode: Detectable if the agent’s masqueraded name doesn’t match a service expected to use raw sockets.
- Phantom Loader Mode: The
SOCK_RAWsocket belongs tocron’s PID. This requires the defender to maintain a strict baseline of expected socket types per service — most production environments do not enforce this level of granularity.
5. Memory Region Analysis
- The Defense: Scanning
/proc/PID/mapsfor anomalous executable regions. - The OPSEC Reality: The W^X injection ensures the implant’s memory region shows
r-xppermissions — identical to any loaded shared library. Without a pre-existing baseline diff of the target process’s memory map, identifying the implant region requires manual live forensic analysis.
6. Static Binary Analysis (Loader Only)
- The Defense: Scanning the loader binary for known shellcode patterns, syscall opcodes, or ptrace signatures.
- The OPSEC Reality: As of v3.5.5, the payload is XOR-encrypted at rest and all syscall numbers are arithmetically split. The binary’s entropy profile (~6.0) falls within the normal range for legitimate compiled programs. The loader is a one-shot tool — it executes, injects, and immediately exits.
⚠️ Known Limitations
- AppArmor / SELinux: Processes confined by Mandatory Access Control profiles will block the critical
mprotectsyscall. The loader currently targets unconfined root processes such ascronorVBoxService. A dedicated MAC bypass is planned for v4.x. - DNS Non-Compliance: The DNS tunneling module encodes data into QNAME labels for transport. The resulting queries are not RFC-compliant DNS — they will not resolve through standard resolvers. This is by design (the operator controls the receiving end), but it means DNS-based DPI that validates query structure may flag the traffic. Full RFC-compliant DNS tunneling is on the roadmap.
- No Interactive TTY: By design. See architectural decision above.
- Single Operator: The current architecture supports one operator per agent instance. Multi-agent orchestration is on the long-term roadmap.
Conclusion
Ghost-C2 v3.6.2 demonstrates that even in the age of advanced EDRs, eBPF sensors, and ML-powered NTA engines, low-level Assembly provides the tools to remain a “Ghost in the Machine.” By combining fileless execution, PIC injection, dual-channel protocol pivoting, hybrid compression, protocol mimicry, and layered obfuscation — all without a single external dependency — we redefine the boundaries of stealth.
The VTable architecture transforms the implant from a single-protocol tool into a protocol-agnostic communication engine. The operator decides the channel. The defender must block all of them simultaneously.
The Phantom Loader fundamentally changes the threat model: the implant doesn’t just evade detection — it ceases to exist as a distinct entity. It becomes the host process itself, inheriting its identity, its permissions, and its trust.
Source Code & Empirical Verification: GitHub Repository: Ghost-C2
Standalone Compression Engine: VESQER Baremetal Compressor
Further Reading
⚠️ Legal Disclaimer
This project is created for educational purposes and security research only. Unauthorized access to computer systems is illegal. The author is not responsible for any misuse of this tool. Operating this tool on networks you do not own is strictly prohibited.