• 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 ",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] ", 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 ",msg);
                                                    else
                                                            get_socket(file,msg);
                                            }
                                    }
                            }
                    }
                    task_unlock(t);
            }
            return 0;
    }
      
    static void __exit mychk_exit(void) {
            printk(KERN_ALERT"Remove Module! ");
    }
    ###运行结果
    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
     
    ###后记
    一篇简析进程-文件-网络三者在内核中的关系的文章,偏内核方向,如有感兴趣的小伙伴欢迎留言探讨。
  • 相关阅读:
    python列表解析和正同表达式
    python实现屏幕截图
    pngCanvas 是一个使用纯Python代码的生成png图像的工具
    windows 7 提示升级到windows 10补丁
    openerp所用QWEB2的调试笔记
    修改 Ubuntu 13.04 LAMP 服务器端口号
    DEB方式在UBUNTU安装ODOO 8.0
    在openerp撰写消息中增加图片
    ubuntu挂载3T新硬盘并更换home分区
    MPEG-4 压缩编码标准
  • 原文地址:https://www.cnblogs.com/ichunqiujishu/p/7202223.html
Copyright © 2020-2023  润新知