Rootkit是一种特殊的恶意软件,它的功能是在安装目标上隐藏自身及指定的文件、进程和网络链接等信息,比较多见到的是Rootkit一般都和木马、后门等其他恶意程序结合使用。Rootkit一词更多地是指被作为驱动程序,加载到操作系统内核中的恶意软件。
chkrootkit简介
chkrootkit是一个linux下检RootKit的脚本,在某些检测中会调用当前目录的检测程序
下载源码:ftp://ftp.pangeia.com.br/pub/seg/pac/chkrootkit.tar.gz
解压后执行 make
命令,就可以使用了
一般直接运行,一旦有INFECTED,说明可能被植入了RootKit
1 | ./chkrootkit | grep INFECTED |
总体流程
首先删除别名,确保接下来的一些操作不会用了被RootKit改变了的别名
1 | ### workaround for some Bourne shell implementations |
一开始会检测一些必要的命令是否可用,可执行,因为检测基于这些命令
1 | cmdlist=" |
接下来就是检测ps的参数ax好不好使,好使就使用ax,不好使就用-fe
1 | # Check if ps command is ok |
当然还需检测你是否是root,就根据你的id号是否为0
1 | if [ `${id} | ${cut} -d= -f2 | ${cut} -d\( -f1` -ne 0 ]; then |
接下来就是默认执行所有测试,当然你也可以指定测试的命令
1 | if [ $# -gt 0 ] |
接下来只是对是否开启调试模式,用户是否指定了要检测的根目录进行处理
1 | if [ "${DEBUG}" = "t" ]; then |
最后便是循环调用各个check函数进行处理了
1 | for cmd in ${LIST} |
那么接下来每个check方法到底是怎么检测的呢?接下来
检测方法
通过分析脚本,总结出检测方法如下:
- 搜索通用的ROOTKIT特征的字符串
- 对某种特定的rootkits,或者命令的特殊的感染特征进行检测
- 对某种特定的rootkits的生成的特定文件的检测
- 对程序的SUID位的设置进行检测
- 对ldsopreload的检测
- 查找可疑的log文件
- 查找可疑的php文件
- 检测.history文件
- 检测有无程序监听了一些可疑的端口
- 检测Linux可加载内核模块
- 检测有无隐藏进程
- 检测目录的软链接异常
- 检测网络接口的异常
- 检测用户的登录日志
- 检测上一次登录
- 检测可疑的没有tty记录的进程
下面对上面这些方法结合脚本代码进行简单说明
搜索通用的ROOTKIT特征的字符串
搜索的是下面的比较通用的ROOTKIT字符串
1 | # Many trojaned commands have this label |
可以看到前两个都是shell相关的,相关的示例代码如下:
1 | chk_chfn () { |
程序针对Linux和FreeBSD系统分开处理,都是通过strings获取二进制程序中的字符串,再使用egrep命令去正则匹配,匹配成功就将返回值STATUS设置为INFECTED这个常量(这个在文件开头处定义了)
对某种特定的rootkits,或者命令的特殊的感染特征进行检测
比如这个amd命令的某个感染特征
1 | chk_amd () { |
下面这个检测crontab的nobody用户,并且定时任务中有数字的, 可能是Lupper.Worm
当然还是有CRONTAB_I_L这个特殊的检测
1 | chk_crontab () { |
对Ramen Worm进行特征匹配
1 | if ${egrep} "^asp" ${ROOTDIR}etc/inetd.conf >/dev/null 2>&1; then |
对某种特定的rootkits生成的特定文件的检测
如下面的HiDrootkit和t0rn
1 | ### HiDrootkit |
对程序的SUID位的设置进行检测
1 | chk_basename () { |
这个除了检测有无关键字,还检测SUID位有无设置
对ldsopreload的检测
1 | chk_ldsopreload() { |
检测是否有libshow.so,libproc.a,有就说明感染了恶意so文件
可以看到为了保险起见,作者使用的是自己目录下静态编译的strings进行检测
查找可疑的log文件
例子如下:
1 | files=`${find} ${ROOTDIR}dev ${ROOTDIR}tmp ${ROOTDIR}lib ${ROOTDIR}etc ${ROOTDIR}var \ |
查找可疑的php文件
查找一些可疑的php文件
1 | ### |
检测.history文件
看看history有没有被清空了,或者软连接到其他地方了
1 | if [ "${QUIET}" != "t" ]; then \ |
检测有无程序监听了一些可疑的端口
检测代码如下:
1 | bindshell () { |
检测Linux可加载内核模块
1 | lkm () |
loadable kernel module (LKM),这个是检测内核模块的 ,看看有无adore,sebek这些内核模块
之后调用chkproc,chkdirs进行检测,这两个下面检测有无隐藏进程,会说到
检测有无隐藏进程
这个代码在chkproc.c中,它通过暴力递归,看看有没有/proc目录存在,而ps查不出来的进程,那么就说明有进程隐藏了
1 | /* Brute force */ |
检测目录的软链接异常
chkdirs比较的是父目录的软链接数和子目录的个数
正常情况下,父目录的软链接数 = 子目录的个数 + 2
1 | if (!linkcount) { |
检测网络接口的异常
1 | sniffer () { |
这个是对网络接口的检测,看看有无开启网卡混杂模式(英语:promiscuous mode)
而PF_PACKET可以操作链路层的数据,可以读取和发送链路层的数据包
1 | ./ifpromisc -v |
检测用户的登录日志
检测用户的登录相关的log文件
SunOS使用的是check_wtmpx,比较的文件是/var/adm/wtmp,/var/adm/wtmpx,check_wtmpx部分代码,比较这两个文件的一些差异,比如下面的比较uid
1 | if ( memcmp( utmp_entry.ut_id, utmpx_entry.ut_id, 4 ) != 0 ) |
其他linux检测的是var/log/wtmp或者var/adm/wtmp
chkwtmp部分代码,查看有无删除了登录时间
1 | gettimeofday(&mytime, &dummy); |
检测上一次登录
使用chklastlog程序检测,下面是部分代码,用户的数据通过getpwent函数获取,其实就是通过/etc/passwd获取,检测基于两点
1、通过比较MAX_ID,与当前的遍历的用户的id,看看id是否大于环境变量MAX_ID
2、看看是否有这样的情况:用户名出现在lastlog,wtmp文件中,而在/etc/passwd中没有的
1 | if ( !nonuser(utmp_ent) && strncmp(utmp_ent.ut_line, "ftp", 3) && |
检测可疑的没有tty记录的进程
检测的是/var/run/utmp或者/var/adm/utmpx,方法是比较的是ps命令与/var/run/utmp文件之间的差别
1 | y = fetchps(ps_l); |
比如下面的检测结果,而我的/var/run/utmp中是没有tty7这个tty的记录的
1 | Checking `chkutmp'... The tty of the following user process(es) were not found |