【原创投稿】Linux Rootkit查杀工具Chkrootkit分析
字数 1880 2025-08-06 12:20:41
Linux Rootkit查杀工具Chkrootkit深度分析
一、Chkrootkit工具概述
Chkrootkit是一款用于在本地检查rootkit迹象的工具,最新版本为v0.57(2023/01/13更新)。该工具由多个独立可执行的文件组成,每个文件都可以单独运行,专注于检测不同类型的rootkit活动。
主要组件及功能
- chkrootkit:主检查脚本,用于检测已知rootkit的二进制文件修改
- ifpromisc.c:检查网络接口是否处于混杂模式
- chklastlog.c:检查上次日志删除情况
- chkwtmp.c:检查wtmp日志文件删除情况
- check_wtmpx.c:检查wtmpx日志文件删除情况(仅Solaris系统)
- chkproc.c:检查LKM(可加载内核模块)特洛伊木马程序的迹象
- chkdirs.c:检查LKM特洛伊木马程序的迹象
- strings.c:快速字符串替换工具
- chkutmp.c:检查utmp日志文件删除情况
二、核心组件深入分析
1. chkrootkit主脚本分析
作为基础命令文件,chkrootkit主脚本主要功能包括:
- 将已知病毒的检测定义为函数
- 通过系统命令检查文件、端口、进程等
- 综合调用其他组件进行rootkit检测
2. chkproc.c - 进程异常检测
该文件通过多维度检测进程,定位异常进程,主要检测方法包括:
2.1 通过ps命令查看进程
- 定义多种ps命令格式以适应不同系统:
static char *ps_cmds[] = { "ps -edf", "ps auxw", "ps mauxw 2>&1 ", "ps auxw -T|tr -s ' '|cut -d' ' -f2-", }; - 执行命令并提取PID:
ps = popen(pscmd, "r"); while (readline(buf, MAX_BUF, ps)) { p = buf; ret = atol(p); if (ret >= 0 && ret <= MAX_PROCESSES) { psproc[ret] = 1; // 标记存在的进程 } }
2.2 通过/proc目录查看进程
- 遍历/proc目录,每个数字命名的子目录对应一个进程PID:
DIR *proc = opendir("/proc"); while ((dir = readdir(proc))) { tmp_d_name = dir->d_name; if (!isdigit(*tmp_d_name)) continue; dirproc[atol(tmp_d_name)] = 1; // 标记存在的进程 }
2.3 通过线程查看进程
- 利用NTPL(Native POSIX Thread Library)线程模型:
- 每个线程有唯一TID和TCB
- /proc/[pid]/task/包含所有线程目录
- 新版Linux中,线程TID以"."开头
if (*tmp_d_name == '.') { tmp_d_name++; maybeathread = 1; } isathread[atol(tmp_d_name)] = 1; // 标记存在的线程
2.4 隐藏进程检测
- 对比三种检测结果,查找不一致:
if (!pdirproc[i] && !psproc[i] && !isathread[i]) { // 可能为隐藏进程 } - 进一步检查进程目录下的关键文件:
- cwd:进程当前工作目录
- exe:进程可执行文件路径
- file:进程打开的文件描述符列表
readlink("./cwd", path, sizeof(path)); // 获取工作目录 readlink("./exe", path, sizeof(path)); // 获取可执行文件路径
2.5 FreeBSD系统特殊检测
- 使用getpriority()检测进程:
errno = 0; getpriority(PRIO_PROCESS, i); if (!errno) { // 进程存在但未被其他方法检测到 }
2.6 EnyeLKM rootkit检测
- 检查特定LKM rootkit特征:
if (stat(ENYELKM, &sb) && kill(12345, 58) >= 0) { printf("Enye LKM found\n"); }
3. chkdirs.c - 隐藏目录检测
通过比较父目录链接数与子目录数发现隐藏目录:
3.1 获取父目录链接数
- 使用lstat()获取目录元数据:
lstat(".", &statinfo); linkcount = statinfo.st_nlink; - 硬链接数说明:
- 1:仅目录本身
-
1:有其他目录或文件链接到它
3.2 获取子目录数
- 递归遍历子目录:
dirhandle = opendir("."); while ((finfo = readdir(dirhandle))) { lstat(finfo->d_name, &statinfo); if (S_ISDIR(statinfo.st_mode)) { numdirs++; } }
3.3 目录信息结构体
- 用于递归遍历:
struct dirinfolist { char dil_name[NAME_MAX+1]; int dil_lc; struct dirinfolist *dil_next; };
3.4 差异计算
- 计算隐藏目录数量:
diff = linkcount - numdirs - 2; // 2为.和..目录
4. 日志文件检测组件
4.1 chklastlog.c
- 检测lastlog和wtmp文件异常
- 读取wtmp条目并与/etc/passwd比对
- 报告用户上次登录时间和会话信息
4.2 chkwtmp.c
- 检测wtmp/utmp文件截断
- 报告截断次数和时间戳为0的条目
4.3 chkutmp.c
- 获取当前活动用户及进程
- 结合ps命令和utmp文件信息
- 使用两个结构体:
struct ps_line {}; // 存储ps命令信息 struct utmp_line {}; // 存储utmp终端信息
5. ifpromisc.c - 混杂模式检测
- 检测网络接口混杂模式:
- 创建套接字查询接口列表
- 检查每个接口的混杂模式状态
- 扫描/proc/net/packet查找原始套接字
- 报告使用混杂模式的进程
三、技术要点总结
- 多维度交叉验证:通过ps、/proc、线程等多角度验证进程真实性
- 文件系统特性利用:利用硬链接数差异检测隐藏目录
- 日志完整性检查:验证系统日志文件是否被篡改
- 网络行为监控:检测异常网络接口模式
- 系统调用验证:通过getpriority等系统调用验证进程存在性
- 特定rootkit特征检测:如Enye LKM的特定行为
四、使用建议
- 定期运行完整检测,而非单独组件
- 结合系统日志分析检测结果
- 注意不同系统环境的命令差异
- 对检测到的异常进行多工具验证
- 关注BTRFS等特殊文件系统的限制(如chkdirs.c的警告)
五、局限性
- 依赖系统命令和文件,可能被高级rootkit绕过
- 部分检测方法在特定文件系统(如BTRFS)上受限
- 需要root权限进行完整检测
- 无法检测所有新型rootkit变种
通过深入理解Chkrootkit的工作原理和检测方法,系统管理员可以更有效地识别和应对潜在的rootkit威胁,同时也能根据这些原理开发更符合特定环境需求的检测工具。