无文件x64汇编C2框架,具备双通道ICMP/DNS协议跳转、直接系统调用执行以及基于ptrace的进程注入能力,用于隐蔽命令执行与数据外泄。
________ ___ ___ ________ ________ _________ ________ ________
|\ ____\|\ \|\ \|\ __ \|\ ____\|\___ ___\ |\ ____\|\_____ \
\ \ \___| \ \ \\\ \ \ \|\ \ \ \___|\|___ \ \_| \ \ \___|\|____|\ \
\ \ \ __ \ \ __ \ \ \\\ \ \_____ \ \ \ \ \ \ \ ____\_\ \
\ \ \|\ \ \ \ \ \ \ \\\ \|____|\ \ \ \ \ \ \ \___|\____ \ \
\ \_______\ \__\ \__\ \_______\____\_\ \ \ \__\ \ \______\\_________\
\|_______|\|__|\|__|\|_______|\_________\ \|__| \|______\|_________|
\|_________|
无文件、纯 x64 汇编 C2 植入体,采用双通道(ICMP / DNS)架构。零 libc。零磁盘。对标准 EDR 钩子不可见。
⭐️ 如果您觉得这项研究有用,请考虑为它点个 star 以支持后续开发
🚨 完整技术研究与源代码: 本仓库仅为摘要。如需完整的架构剖析、W^X 内存逃逸细节和 VTable 实现,请访问官方项目页面:ICMP-Ghost 技术解析
Ghost-C2 是一个完全用纯 x64 Linux 汇编编写的命令与控制(C2)框架,不依赖 libc。所有操作均通过直接系统调用完成。没有导入表、没有动态链接器痕迹、也没有磁盘写入。
它最初以原始 ICMP 隐蔽信道的形式构建,3.6.2 版本引入了**双通道协议跳转(Dual-Channel Protocol Pivoting)**架构。操作者可以在静默的 ICMP 原始套接字与规避检测的 DNS UDP 隧道之间无缝切换植入体的通信信道。植入体仅驻留于 RAM 中,通过基于 ptrace 的自定义加载器注入到运行中的系统进程里。
本项目旨在探索在不触及内核的情况下,用户态隐蔽性与网络状态同步究竟能走多远。
┌─────────────────────────────────────────────────────────────┐
│ OPERATOR MACHINE │
│ │
│ ┌──────────────┐ │
│ │ client.asm │ ← Terminal UI: Prompt IP/Domain + Cmd │
│ │ (Operator │ Encrypts payload with Rolling XOR │
│ │ Console) │ State Sync: ICMP mode / DNS mode │
│ └──────┬───────┘ │
│ │ │
└──────────┼──────────────────────────────────────────────────┘
│ Channel 1: Raw ICMP (Stateless, Port-less)
│ Channel 2: DNS UDP Port 53 (Asymmetric)
┌──────────┼──────────────────────────────────────────────────┐
│ │ TARGET MACHINE │
│ ▼ │
│ ┌──────────────┐ ┌─────────────────────────────────┐ │
│ │ loader.asm │────▶│ sniff.asm (PIC) │ │
│ │ (Phantom │ │ Lives in RAM only │ │
│ │ Loader) │ │ inside host process │ │
│ └──────────────┘ └────────────────┬────────────────┘ │
│ │ │
│ 1. Scans /proc for target PID │ Listens ICMP/DNS │
│ 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 Reply │
└─────────────────────────────────────────┼───────────────────┘
│ Encrypted Traffic
▼
[ client.asm ]
Receives & Validates
Decrypts Payload
Decompresses (Hybrid)
Reassembles & Prints
client.asm — 操作者控制台攻击者侧终端。负责 UI、动态内存管理和目标状态同步。可以 ICMP Echo 请求或 DNS TXT 查询的形式发送数据包。监听分片回复,防止缓冲区溢出,并重组输出。内置“活动目标重连(Active Target Reconnection)”模块,用于恢复失联会话。
sniff.asm — PIC 植入体代理运行在目标上的植入体。编译为原始二进制(位置无关、无 ELF 头),因此可注入到任意内存地址。它会根据操作者的跳转命令,动态更新内部 VTable,以在 ICMP 嗅探与 UDP DNS 绑定之间切换。
Phantom_Loader/loader.asm — 注入引擎投递机制。扫描 /proc,按 comm 名称查找目标进程,并通过多阶段 ptrace 状态机将 PIC shellcode 注入其中。注入后干净退出——不留任何痕迹。
Ghost-C2 v3.6.2 允许操作者在不丢失 agent 的情况下热切换网络协议。通过发送特定的跳转命令,Master 和 Agent 中的 VTable 都会被动态覆写:
!D(跳转到 DNS): 两个节点均关闭 ICMP 套接字并初始化 UDP 53 端口通信。通过混入企业 DNS 流量,适合绕过严格的第三层过滤。!I(跳转到 ICMP): Agent 关闭 UDP 套接字、解除端口绑定,并回落到静默的原始套接字嗅探。非常适合“幽灵(Phantom)”隐身模式。Ghost-C2 的数据传输引擎采用在 x86-64 汇编中深度优化的混合压缩与编码层。
每个外发的 ICMP 数据包在结构上都与标准 Linux ping 无法区分:
struct timeval。iputils 填充(0x10 至 0x1F)可绕过基本的启发式防火墙。双向通信均使用逐步移位的 QWORD 密钥进行加密。这使 Shannon 熵保持在较低水平(不同于熵值约为 8.0、会触发 DPI 异常的 AES)。滚动 XOR 产生的熵看起来就像自然的噪声数据。没有加密常量、没有 S 盒,YARA 没有任何可匹配的东西。
植入体会忽略所有 ID + SEQ ≠ 45,000 的 ICMP 数据包。植入体以 ID + SEQ = 55,000 的数据包进行回复。这可以防止操作系统回显混淆,并过滤掉互联网扫描器或蜜罐。
memfd_create 实现无文件执行命令输出从不落盘。Shell 输出通过匿名 RAM 文件(memfd_create)捕获,并命名为 [shm],以混入 /proc/PID/fd 中合法的共享内存映射。
突破现代内核禁止 RWX 内存的缓解机制。加载器采用两阶段方案(以 RW 权限 Remote mmap → 注入 → 以 RX 权限 Remote mprotect)。任何内存页都不会同时具有 W 和 X 权限。
所有系统调用号都被拆分到两条指令中,以对抗静态分析和基于 grep 的简单扫描器。
为保持严格的 OPSEC,Ghost-C2 agent(sniff.asm)不使用外部配置。你必须在编译和注入之前,直接在汇编代码中定义你的 Master C2 IP、端口和诱饵 DNS 域名。
打开 sniff.asm,滚动到 .text 段的最底部。(注意:由于 agent 是严格的位置无关代码(PIC),因此没有 .data 段。所有配置变量均以内联方式存储。)
修改以下值以匹配你的 Master 服务器:
db 127, 0, 0, 1 改为你 Master 的 IP。dw 0xB414(端口 5300)改为你所需的端口,需使用网络字节序(例如端口 53 为 0x3500)。nasm -f bin sniff.asm -o shellcode.bin
python3 -c "data = open('shellcode.bin', 'rb').read(); lines = ['\tdb ' + ', '.join(f'0x{b:02x}' for b in data[i:i+12]) for i in range(0, len(data), 12)]; open('c2_payload.txt', 'w').write('\n'.join(lines))"
c2_payload.txt 的内容。xor.py,用你复制的 shellcode 替换 raw_asm 变量的内容。python3 xor.py,然后复制加密后的输出。loader.asm。c2_payload: 标签。target db "cron", 10 可更改注入的目标进程。)nasm -f elf64 loader.asm -o loader.o
ld loader.o -o loader
以 root 权限在目标机器上执行(sudo ./loader)。至此,agent 完全以无文件方式运行。
在编译 Master 控制台之前,你必须确保其监听器和目标配置与你的 Agent 配置一致。打开 client.asm,导航到 .data 区域。
找到 master_bind_addr。这是 Master 监听入站 DNS 信标的位置。
UDP 端口:将 dw 0xB414 改为与你的 Agent 发送目标端口一致。
注意: 此处必须使用网络字节序。对于端口 53,使用 0x3500。
找到 target_addr。该端口用于执行 DNS 跳转(!D)或使用重连模块时。
端口对齐:将 dw 0xB414 改为与 Agent 监听的 UDP 端口一致。如果这些端口不匹配,将发生(死锁),因为 Master 会对着错误的虚空大喊。
配置完成后,汇编并链接 Master:
nasm -f elf64 client.asm -o client.o
ld client.o -o client