0
回答
[技术分享] NSRC技术分享——自制Linux Rootkit检测工具
华为云实践训练营,热门技术免费实践!>>>   

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

 

###后记

本文转自i春秋论坛网易src的分享~

<无标签>
举报
i春秋学院
发帖于4个月前 0回/132阅
顶部