NSRC技术分享——自制Linux Rootkit检测工具
2017-07-18 19:14 网络信息安全技术 阅读(590) 评论(0) 收藏 举报
### 前言
Linux系统中存在用户态与内核态,当用户态的进程需要申请某些系统资源时便会发起系统调用。而内核态如何将系统的相关信息实时反馈给用户态呢,便是通过proc文件系统。如此便营造了一个相对隔离的环境。
那么proc文件系统是如何呈现我们平时最关心的进程/网络连接信息的呢?在/proc目录下存在着一些以数字命名的目录,这些数字便对应了系统中正在运行的进程的pid。自然,对应进程的一些相关信息便保存在/proc/{pid}目录下。比如/proc/{pid}/fd目录中就保存了进程打开的文件描述符。
系统会将tcp协议的连接信息保存在/proc/net/tcp文件中。其他网络协议的连接信息也均保存在/proc/net对应协议的文件中。需要特别指出的是,上图中socket文件名中括号里的数字与下图中inode列是存在对应关系的。

综上所述,像ps和netstat这类命令便是读取了proc文件系统中提供的数据,然后将数据格式化输出给用户的。出于隐藏指定进程/网络连接的目的,大部分Rootkit对写proc文件的回调函数做了些手脚,造成黑客指定的一些进程/网络连接的信息不会出现在proc文件系统中。于是,也就实现了进程/网络连接的隐藏。
### 探索
那么,如何发现那些被隐藏的进程/网络连接呢?首先是进程,这个其实并不复杂。系统给我们提供了一个方便的全局变量current。current永远指向当前正在运行的进程的task_struct数据结构,而进程的主要信息都包含在这个名为task_struct的巨大结构体中。当我们遍历到系统中所有进程task_struct结构体中的pid值,然后再去/proc目录下去寻找是否有对应的值。一但我们得到的pid未出现在ps的返回结果中,那么说明该进程被隐藏了。
如何发现被隐藏的网络连接呢?其实还是基于上一步进一步挖掘,因为网络IO请求都是由进程发起的,那么理论上来说我们肯定可以从进程一步步“捋”到socket。Linux一切皆文件的准则告诉我们,所谓网络IO其实就是读写socket文件,而每个socket结构体中都会有一个对应的inet_sock结构体,来记录IP协议下网络连接的四元组信息。那么我们把这些四元组再和netstat命令的返回结果比对一下便可知是否存在隐藏的网络信道了。
总结出来在Kernel2.6.32中,进程-文件-网络三者之间大致的关系如下图所示。
fdtable结构体的成员fd字符数组中存储的是file结构体,每当进程开启了一个文件描述符之后会自动在fd数组中新增一个对应的file结构体。通过获取file结构体中的f_path成员,我们可以获得对应的path结构体。系统内置的d_path函数可以返回path结构体对应文件的绝对路径信息。当d_path返回了一个“socket:[xxx]”的信息时,就说明这是个socket文件,该进程在试图进行网络IO。我们引用这个file结构体的private_data成员就可以获得这个socket文件对应的socket结构体了。最后通过内置的inet_sk()函数我们就可以找到对应socket文件的inet_sock结构体,我们需要的四元组便存在这个结构体中。
### 代码
[C] 纯文本查看 复制代码
|
01
02
03
04
05
06
07
08
09
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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
#include <linux/init.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/file.h>#include <linux/dcache.h>#include <linux/fdtable.h>#include <linux/file.h>#include <linux/fs.h>#include <linux/limits.h>#include <linux/string.h>#include <linux/net.h>#include <net/inet_sock.h> static int __init mychk_init(void);static void __exit mychk_exit(void); module_init(mychk_init);module_exit(mychk_exit); MODULE_LICENSE("GPL"); void get_socket(struct file *f,char* sock_name){ struct socket *st = NULL; struct inet_sock *is = NULL; st = f->private_data; is = inet_sk(st->sk); printk(KERN_ALERT"%s: LA: %d.%d.%d.%d:%u FA: %d.%d.%d.%d:%u\n",sock_name,NIPQUAD(is->saddr),ntohs(is->sport),NIPQUAD(is->daddr),ntohs(is->dport));} char* get_path(struct path p) { char *buff = NULL; char *path = NULL; buff = kmalloc(PATH_MAX,GFP_KERNEL); if (!buff) return NULL; path = d_path(&p,buff,PATH_MAX); return path;} static int __init mychk_init(void) { struct task_struct *t = NULL; struct files_struct *f = NULL; struct file *file = NULL; struct fdtable *fdt = NULL; struct path p; char *msg = NULL; int i; list_for_each_entry(t,¤t->tasks,tasks) { printk(KERN_ALERT"Process:%s [%d]\n", t->comm, t->pid); task_lock(t); f = t->files; if(NULL != f){ fdt = f->fdt; for (i = 0;i<NR_OPEN_DEFAULT;i++) { if (fdt != NULL) { file = fdt->fd; if(file != NULL && file->f_path.dentry != NULL) { p = file->f_path; msg = get_path(p); if (msg != NULL && msg != strstr(msg,"socket")) printk(KERN_ALERT"-- %s\n",msg); else get_socket(file,msg); } } } } task_unlock(t); } return 0;} static void __exit mychk_exit(void) { printk(KERN_ALERT"Remove Module!\n");} |
###运行结果
Process:sshd [1840]
-- /dev/null
-- /dev/null
-- /dev/null
socket:[16185]: LA:192.168.11.144:22 FA: 192.168.11.1:61493
-- pipe:[16256]
-- pipe:[16256]
-- /dev/ptmx
-- /dev/ptmx
-- /dev/ptmx
Process:bash [1844]
-- /dev/pts/1
-- /dev/pts/1
-- /dev/pts/1
Process:mysqld_safe [3668]
-- /dev/null
-- /dev/null
-- /dev/null
Process:mysqld [3770]
-- /dev/null
-- /var/log/mysqld.log
-- /var/log/mysqld.log
-- /var/lib/mysql/ibdata1
-- /tmp/ibABwsCH (deleted)
-- /tmp/ibLWJRBw (deleted)
-- /tmp/ibVCthBl (deleted)
-- /tmp/ibogYHLa (deleted)
-- /var/lib/mysql/ib_logfile0
-- /var/lib/mysql/ib_logfile1
socket:[18993]: LA:0.0.0.0:3306 FA: 0.0.0.0:0
-- /tmp/ibgDa0v2 (deleted)
-- /var/lib/mysql/mysql/host.MYI
-- /var/lib/mysql/mysql/host.MYD
-- /var/lib/mysql/mysql/user.MYI
-- /var/lib/mysql/mysql/user.MYD
-- /var/lib/mysql/mysql/db.MYI
-- /var/lib/mysql/mysql/db.MYD
-- /var/lib/mysql/mysql/tables_priv.MYI
-- /var/lib/mysql/mysql/tables_priv.MYD
-- /var/lib/mysql/mysql/columns_priv.MYI
-- /var/lib/mysql/mysql/columns_priv.MYD
-- /var/lib/mysql/mysql/procs_priv.MYI
-- /var/lib/mysql/mysql/procs_priv.MYD
-- /var/lib/mysql/mysql/servers.MYI
-- /var/lib/mysql/mysql/servers.MYD
-- /var/lib/mysql/mysql/event.MYI
-- /var/lib/mysql/mysql/event.MYD
###后记
一篇简析进程-文件-网络三者在内核中的关系的文章,偏内核方向,如有感兴趣的小伙伴欢迎留言探讨。



浙公网安备 33010602011771号