排查LKM级监听后门核心是确认“谁在监听、但系统不承认”,即端口存在却无进程映射,需通过ss与netstat对比、inode断联验证、/proc/net/raw检查、模块脱链比对、dmesg加载痕迹溯源及sys_call_table函数指针异常检测等多维度交叉验证。

排查LKM级监听后门,核心是确认“谁在监听、但系统不承认”。这类后门不依赖用户态进程,而是直接在内核中注册原始套接字或劫持系统调用,绕过ss、netstat等工具的进程关联逻辑。不能只看端口,要看端口与进程之间的映射是否被切断。
检查监听端口与进程的映射断裂
运行ss -tulnp(需root权限),重点关注以下三类异常:
- PID列为
-或完全空白:说明该监听未绑定到任何用户态进程,极可能由内核模块直接创建(如raw socket或inet_bind hook) - 同一端口在
ss -tulnp中无PID,但在netstat -tulnp中有PID:说明netstat已被LD_PRELOAD或模块hook篡改,而ss更可信 - 监听地址为
0.0.0.0且端口号>60000(如:61234),同时无对应服务配置(查systemctl list-sockets和/etc/systemd/system/*.socket)
从内核网络子系统反查真实归属
当ss无法给出PID时,手动追踪inode并验证进程存在性:
- 查
/proc/net/tcp中目标端口(十六进制)对应的inode号:awk '$2 ~ /:FDE2/ {print $10}' /proc/net/tcp(FDE2是65026的十六进制小写) - 遍历所有进程fd,查找该inode:
for i in /proc/[0-9]*; do ls -l "$i/fd/" 2>/dev/null | grep -q "socket:\[12345\]" && echo "$i"; done - 若无任何输出,再检查
/proc/net/raw*——Rootkit常用raw socket实现隐蔽监听,绕过常规TCP/UDP表
定位可疑内核模块来源
监听后门往往由恶意LKM加载,需交叉验证其存在性与行为:
- 比对模块可见性:
lsmod | wc -l与ls /sys/module/ | wc -l,若后者多出3个以上,说明有模块被脱链隐藏 - 检查加载痕迹:
dmesg | grep -i 'insmod\|init_module\|loading.*ko',关注时间戳异常靠前、模块名含drv、acpi、hide、z0mb等仿冒词的记录 - 扫描非常规路径的.ko文件:
find /tmp /dev/shm /var/tmp /lib/firmware -name "*.ko" -type f 2>/dev/null,对结果执行file和strings {} | grep -E "(socket|bind|listen|inet)"
验证系统调用是否被劫持
监听后门常通过hooksys_bind、sys_listen或sys_socket来绕过进程关联,需检查函数指针是否异常:
- 获取系统调用表地址:
cat /proc/kallsyms | grep sys_call_table - 定位关键函数索引(x86_64):
__x64_sys_bind通常在索引10左右,__x64_sys_listen在索引11左右 - 使用
crash或自编模块读取该偏移处指针值;若指向0xffff...或/tmp、/dev/shm等用户空间地址,即为劫持证据


















