您的位置 首页 > 数码极客

如何检测内核级木马

Linux安全系列是一套完整的检查linux系统是否被入侵,后门排查,木马清除,黑客溯源,以及恢复攻击路径的方法介绍。

由于是第一篇,在说主题前面先简单介绍一下目前linux木马的现状,目前主流的linux木马都不是内核级的,因为内核木马很难满足各个发行版的兼容性要求且需要root权限,所以几乎都是用户层的。从功能上看,基本都是实现一个挖矿功能和一个反弹rootshell功能。rootshell的触发机制,使用定时反弹固定iP或Ping触发,也有更底层的任意端口触发和无端口触发(netfilter prerouting)。

它们最显著的三个共同特点:

1、运行后删除自身,只驻扎在内存中

有时使用lsof|grep deleted会有惊喜哦,如图:

2、运行后改名,且大多数木马改为内核形态的进程命名方式即[xxx],用以迷惑视线

3、修改/etc或环境变量进行动态链接库劫持,达到隐藏进程和端口的目的

cat /etc或使用ldd/bin/ps命令,可以看到异常,如图:



我们进入正题说下进程:

  1. Linux下有3个特殊的进程,idle进程(PID = 0), init进程(PID = 1)和kthreadd(PID = 2)
  2. idle进程,linux的第一个进程
  3. /sbin/init进程由idle通过kernel_thread创建,是所有用户进程的父进程或祖先
  4. [kthreadd]进程由idle通过kernel_thread创建,是所有内核进程的父进程



举个例子了解一下:

首先,内核进程的命名规则都是[xxx],用中括号括起来的,而用户层的进程正常情况下不会这样,那么,如果一个[xxx]形式的进程他的父进程是1(也就是/sbin/init),那是不是有问题?因为带中括号的进程的父进程正常情况下应该是2(也就是[kthreadd]),如图:



这是一个针对改名的例子,改名代码很简单,所以利用广泛

strncpy(argv[0],FAKE_NAME, strlen(argv[0]));

就能实现,有兴趣的可以自行测试做实验

那么如果后门没有改成[xxx]形式又如何发现呢?

我们来观察几条能得到进程名字的命令,看看哪些得到的是真名,哪些是假名:

ps -ef



cmdline



pstree



ls -l/proc/pid/exe



可以看到前两个得到的名字是一样的为[locked],后两个得到的名字也是一样的为rootkit

前面两为假名,后面两为真名

那么未改名前的名字(即真实名字)就可以通过后面这两种方式查出来

我们也可以把它写成脚本来进行全部循环比较,知识星球里给出了脚本下载。

进程隐藏:

进程的隐藏可以在不同的层面实现

用户层---系统调用层---内核层---文件系统层

常用的隐藏方法如下:

  1. 替换ELF文件
  2. 劫持LD_LIBRARY_PATH
  3. 劫持syscall_table
  4. 篡改syscall_table劫持系统调用
  5. Inlinehook 系统调用
  6. VFS层劫持
  7. kprobe
  8. 感染系统关键内核模块

对于ELF文件被替换,我们可以使用

rpm -Vf/bin/ps 来校验

S为 大小 5为 MD5 T为时间 M为属性

如果执行命令后出现S等字样,就说明被改变了,如果S和5同时改变,那么就是有问题的,ps命令将变得不可信



上图,可以看到SM5T全部改变了

关于 LD_LIBRARY_PATH的劫持,劫持的方法有两种,环境变量和 /etc

如何发现?我们使用file /bin/ps观察如下:



证实ps命令它是动态编译的,使用了系统的共享库,如果此时动态链接被劫持,那么运行该程序的时候也会把后门程序劫持后的共享库加载进去(类似windows下的LPK劫持),通常实现一些隐藏的目的

使用 ldd /bin/ps 命令可发现异常



正常应该全部为/lib 或者 /lib64下的系统动态链接库

如果最后一行(也有可能不是最后一行)是其他的so文件,那么就要考虑是否动态库被劫持了

进一步确认的话,可以跟干净的系统进行比较或者使用gdb调试,简单点也可以使用strings静态查看关键字符

对于上述两种应用层隐藏的方式,我们的反制方法:

当发现PS命令不可信的情况下,我们可以使用Linux静态命令工具箱busybox来执行操作系统命令,以求达到一个干净的环境

我们可以file busybox看到它是静态编译的,不受动态库环境变量的影响



使用busybox 执行ps命令



那么内核层的呢?

系统调用下的劫持,我们后面开篇单独讲。

关于VFS层的劫持,这个在rootkit中用得很多

大名鼎鼎的adore-ng和enyelkm就是使用的这个方式

Linux下一切皆文件,说一下ps命令的本质,ps命令的本质还是读取文件,ps程序通过 open /proc 打开 fd,通过 getdents <fd> 遍历目录,如图执行命令strace/bin/ps



可以看到它最终其实是实现了系统调用getdents

而通过劫持它在VFS层的回调函数readdir/iterate(高版本)的地址可以实现一切基于文件操作的隐藏,包括ls,dir,ps,top等

检查隐藏进程

不管是用户层的隐藏还是内核层的隐藏,我们想出一个办法,如果在内核态直接把所有进程遍历打印出来,然后再在用户态模拟ps执行命令,那么把两种结果进行循环比较,如果内核态的进程比ps模拟执行的进程多,那么隐藏进程就会被筛选出来

使用这个内核函数for_each_process()可以遍历内核态所有进程

根据这个原理,我写了一个隐藏进程检测工具,如下图检测工具运行结果:

对隐藏进程检测工具感兴趣的可以加入知识星球进行下载。

执行 tar -xvf



是简单的一个脚本,测试在cen环境下,其他发行版的大家可以自己延申

最后给大家一个一条命令隐藏进程的小技巧:

mount --bind



可以看到两次执行ps -ef|greprootkit的返回结果是不一样的,第二次看不到rootkit了

原因就是我们中间执行了这么一条命令

mount--bind /root/aaa /proc/12755

把12755的进程目录绑定到一个空目录上,这样ps遍历该进程目录的时候就为空,达到了隐藏进程的目的(包括top命令都隐藏了)

如果需要卸载用umount/proc/12755

那么怎么检查呢,我们观察,除kcore外只有其在/proc下字节为非0

因此我们给出一条检查命令

ls -l/proc|awk '$9!="kcore"&&$5==4096 {print $9}'



完整卸载命令如下:

umount/proc/`ls -l /proc|awk '$9!="kcore"&&$5==4096 {print $9}'`

责任编辑: 鲁达

1.内容基于多重复合算法人工智能语言模型创作,旨在以深度学习研究为目的传播信息知识,内容观点与本网站无关,反馈举报请
2.仅供读者参考,本网站未对该内容进行证实,对其原创性、真实性、完整性、及时性不作任何保证;
3.本站属于非营利性站点无毒无广告,请读者放心使用!

“如何检测内核级木马”边界阅读