Linux Kernel Rootkit 1

IoT 3年前 (2021) admin
1,130 0 0

本篇文章由ChaMd5安全团逆向样本小组投稿
本系列文章将记录我关于Linux Kernel Rootkit的学习与思考,重点部分是关于难度比较高的LKM Rootkit部分。

概述

rootkit目的:

  • 1.隐藏文件
  • 2.隐藏进程
  • 3.内核提权
  • 4.隐藏端口
  • 5.永久驻留
  • 6.隐藏自身

Linux rootkit 可以通过两种方式破坏内核执行恶意操作:

  • 加载内核模块

    Linux 内核(和许多其他操作系统)可以在运行时加载内核模块(例如设备驱动程序)。这允许入侵者插入一个覆盖内核系统调用的模块以返回不正确的值(例如不列出某些文件),或提供对入侵者有用的新功能(例如为某些进程提供 root 权限)。

    防护措施:编译一个禁用可加载内核模块接口的内核。

  • 写入 /DEV/KMEM

    /dev/kmem是一个特殊设备,可以访问正在运行的内核占用的内存区域。通过写入 /dev/kmem,可以在运行时覆盖内核,从而执行任意修改。如果你想覆盖内核的某个特定部分,唯一的问题是在/dev/kmem 中找到正确的位置。

    对/dev/kmem的访问只能通过修补内核来拒绝。一个使/dev/kmem不可写的补丁已经发表在Phrack issue 58, article 0x07 ("Linux on-the-fly kernel patching without LKM", by sd & devik)。正如Guillaume Pellat在bugtraq帖子中指出的,这个补丁仍然允许通过使用mmap()而不是直接的文件I/O写入/dev/kmem。

当应用程序进行系统调用(例如 open() 打开文件)时,控制流如下所示:

  • 触发中断,并在为该中断定义的中断处理程序处继续执行。在 Linux 上,使用中断 80。

    rootkit 可以用自己的函数替换内核中断处理程序。这需要修改中断描述符表 (IDT)。关于此方法的讨论以及概念验证代码发表在 Phrack issue 58, article 0x07 ("Linux on-the-fly kernel patching without LKM", by sd & devik)中。本文提供了一个程序,可用于列出 IDT 并保存当前状态。

  • 中断处理程序(在 Linux 上名为 system_call())在系统调用表中查找所请求系统调用的地址,并执行跳转到相应地址。

    rootkit 可以

    (a) 修改中断处理程序来使用rootkit 提供的系统调用表;或

    (b) 修改系统调用表中的条目以指向 rootkit 替换的函数。

    方法 (a) 目前仅被一个 rootkit 使用,SucKIT rootkit ,在 Phrack issue 58, article 0x07 ("Linux on-the-fly kernel patching without LKM", by sd & devik)。这是一个完整的 rootkit,通过/dev/kmem 加载 (即它不需要支持可加载内核模块的内核。它提供了一个受密码保护的远程访问shell,由欺骗数据包启动(绕过大部分防火墙配置),并且可以隐藏进程、文件和连接。

    方法(b) 被大量rootkit 使用,因为它很容易编码。

  • 系统调用函数被执行,控制权返回给应用程序。

    rootkit 可能会覆盖 syscall 函数,以在 syscall 函数的开头放置一个跳转到它自己的替换函数。目前没有已知的 rootkit 使用这种方法。

rootkit是允许某人控制操作系统的特定方面而不暴露他或她的踪迹的一组代码。从根本上说来,用户无法察觉这种特性构成了rootkit。rootkit会想尽办法去隐藏自己的网络、进程、I/O等信息(注意,这里所谓的隐藏,只是针对ring3的ui隐藏,内核层的功能不能隐藏,否则rootkit自己也无法使用功能了),所以,rootkit的攻防问题很大程度上是一个ring0争夺战的问题,监控程序必须直接深入到系统的底层去获取最原始的数据,才能避免因为rootkit的ring3隐藏导致的误判。

Linux Kernel Rootkits 分类

1. 应用级rootkit
通过替换login、ps、ls、netstat等系统工具,或修改.rhosts等系统配置文件等实现隐藏及后门

2. 内核级rootkit
    2.1 挂钩hook技术
        1) 系统调用hook
        2) 函数api hook
    2.2 直接内核对象操作
    主要是指在系统不支持lkm机制时修改内核的一种方法,主要通过/dev/mem、/dev/kmem设备直接操作内存,从而对内核进行修改

3. 硬件级rootkit
主要指bios rootkit,可以在系统加载前获得控制权,通过向磁盘中写入文件,再由引导程序加载该文件重新获得控制权,也可以采用虚拟机技术,使整个操作系统运行在rootkit掌握之中
http://www.rootkitanalytics.com/firmware/hypervisor.php
http://www.rootkitanalytics.com/kernelland/linux-kernel-rootkit.php

通过/dev/kmem加载的rootkits

SucKIT rootkit 是一个完整的 rootkit,通过/dev/kmem 加载,即它不需要支持可加载内核模块的内核。它提供了一个受密码保护的远程访问shell,由欺骗数据包启动(绕过大部分防火墙配置),并且可以隐藏进程、文件和连接。Phrack issue 58, article 0x07 ("Linux on-the-fly kernel patching without LKM", by sd & devik)

Loadable Kernel Modules Rootkit

除SucKIT rootkit外,大部分的rootkit都是LKM rootkit,并使用修改syscall表的方法。Linux就是通常所说的单内核(monolithic kernel),它与微型内核(windows系统中常见)不同

1. Linux中的单内核
操作系统的大部分功能都被称为内核,并在特权模式下运行。同时,linux也提供动态扩充系统功能的机制(可以将新的功能加载到内核、从内核去除某个功能),通过Linux内核模块(LKM)可以在运行时动态地更改Linux的内核,以达到
动态扩充和裁剪的目的,这样可以最小化内核的内存占用

2. 微型内核
只把基本的功能(进程间通信[IPC]、调度、基本的输入/输出[I/O]和内存管理)当作内核运行,而把其他功能(驱动程序、网络堆栈和文件系统)排除在特权空间之外

LKM与直接编译到内核或典型程序的元素有根本区别

1. 典型的程序有一个main函数
2. LKM包含entry和exit函数(这里所谓的entry、exit只是一个称号,我们可以任意命名这些函数,只要通过module_init、module_exit宏进行明确声明)。当向内核插入模块时,调用module_init声明的函数,从内核删除模块时
则调用module_exit声明的函数。LKM还包含一组必要的宏和一组可选的宏,用于定义模块的许可证、模块的作者、模块的描述等等
Linux Kernel Rootkit 1

2.6及以上的本的Linux内核提供了更简单的bash命令用于构建LKM

  • 1.insmod: 安装LKM
  • 2.rmmod: 删除LKM
  • 3.modprobe: insmod和rmmod的包装器
  • 4.depmod: 用于创建模块依赖项
  • 5.modinfo: 用于为模块宏查找值

检测内核 Rootkit

要获取内核模块列表,可以使用两种标准方法:

parallels@ubuntu20:/$ sudo lsmod 
Module                  Size  Used by
binfmt_misc            24576  1
usblp                  32768  0
prl_fs_freeze          20480  0
prl_fs                 45056  4
nls_iso8859_1          16384  1
snd_hda_codec_generic    94208  1
ledtrig_audio          16384  1 snd_hda_codec_generic
snd_hda_intel          53248  4
snd_intel_dspcfg       20480  1 snd_hda_intel
snd_hda_codec         172032  2 snd_hda_codec_generic,snd_hda_intel
snd_hda_core          114688  3 snd_hda_codec_generic,snd_hda_intel,snd_hda_codec
snd_hwdep              28672  1 snd_hda_codec
snd_pcm               143360  4 snd_hda_intel,snd_hda_codec,snd_hda_core
snd_seq_midi           20480  0
snd_seq_midi_event     20480  1 snd_seq_midi
snd_rawmidi            57344  1 snd_seq_midi
aes_ce_blk             32768  0
snd_seq               110592  2 snd_seq_midi,snd_seq_midi_event
input_leds             16384  0
crypto_simd            20480  1 aes_ce_blk
parallels@ubuntu20:/$ sudo cat /proc/modules
binfmt_misc 24576 1 - Live 0xffff8000091d9000
usblp 32768 0 - Live 0xffff8000091d0000
prl_fs_freeze 20480 0 - Live 0xffff800009163000 (POE)
prl_fs 45056 4 - Live 0xffff80000919a000 (POE)
nls_iso8859_1 16384 1 - Live 0xffff800009133000
snd_hda_codec_generic 94208 1 - Live 0xffff8000091b8000
ledtrig_audio 16384 1 snd_hda_codec_generic, Live 0xffff8000090a3000
snd_hda_intel 53248 2 - Live 0xffff8000091aa000
snd_intel_dspcfg 20480 1 snd_hda_intel, Live 0xffff8000090ef000
snd_hda_codec 172032 2 snd_hda_codec_generic,snd_hda_intel, Live 0xffff80000916f000
snd_hda_core 114688 3 snd_hda_codec_generic,snd_hda_intel,snd_hda_codec, Live 0xffff800009146000
snd_hwdep 28672 1 snd_hda_codec, Live 0xffff80000913e000
snd_pcm 143360 3 snd_hda_intel,snd_hda_codec,snd_hda_core, Live 0xffff80000910f000
snd_seq_midi 20480 0 - Live 0xffff800009050000
snd_seq_midi_event 20480 1 snd_seq_midi, Live 0xffff80000904a000
snd_rawmidi 57344 1 snd_seq_midi, Live 0xffff800009100000
aes_ce_blk 32768 0 - Live 0xffff8000090f7000
snd_seq 110592 2 snd_seq_midi,snd_seq_midi_event, Live 0xffff8000090d3000
input_leds 16384 0 - Live 0xffff8000090a8000
crypto_simd 20480 1 aes_ce_blk, Live 0xffff800009057000
cryptd 24576 1 crypto_simd, Live 0xffff80000907b000
snd_seq_device 20480 3 snd_seq_midi,snd_rawmidi,snd_seq, Live 0xffff8000090cd000
snd_timer 49152 2 snd_pcm,snd_seq, Live 0xffff8000090c0000

另外,可以查看模块导出的符号列表(/proc/kallsyms),其中方括号中会列出对应模块的名称

sudo cat /proc/kallsyms
ffff800008e38808 t failover_unregister [failover]
ffff800008e3b080 d __this_module [failover]
ffff800008e38228 t failover_slave_unregister [failover]
ffff800008e38924 t cleanup_module [failover]
ffff800008e385e8 t failover_register [failover]
ffff800008e32240 d $d [ahci_platform]
ffff800008e31024 r $d [ahci_platform]
ffff800008e31024 r _note_6 [ahci_platform]
ffff800008e31040 r $d [ahci_platform]
ffff800008e30000 t $x [ahci_platform]
ffff800008e30000 t ahci_probe [ahci_platform]
ffff800008e300e8 t $x [ahci_platform]
ffff800008e300e8 t ahci_driver_exit [ahci_platform]
ffff800008e310b0 r ahci_acpi_match [ahci_platform]
ffff800008e31110 r ahci_of_match [ahci_platform]
ffff800008e31078 r $d [ahci_platform]

不幸的是,作为内核模块,LKM Rootkit 可以通过多种方法轻松躲避这些方法。这里有一种更好的方法来检测 LKM Rootkit:

为了用自己的代码替换内核系统调用,LKM Rootkit 修改了保存这些系统调用地址的表,指向模块的替换函数而不是原始内核函数。现在,无论何时编译内核,都会生成内核符号 及其各自在内核中的地址的 映射。该映射称为 System.map (有时附加内核版本),通常安装在与内核相同的位置(例如/boot)。因此,检测被劫持的内核系统调用的一种直接方法是将此映射与所有系统调用的实际地址进行比较,这将显示地址与映射中列出的原始地址不同的所有系统调用。

这里举例一个程序kern_check.c用于检测LKM Rootkit,它将System.map 与内核系统调用表进行比较,并警告任何不一致

bash$ gpg --verify kern_check.c.asc kern_check.c
bash$ gcc -O2 -Wall -o kern_check kern_check.c
bash$ su
bash$ kern_check /path/to/System.map

参考文献

https://www.cnblogs.com/LittleHann/p/3870974.html


end


招新小广告

ChaMd5 Venom 招收大佬入圈

新成立组IOT+工控+样本分析+AI 长期招新

欢迎联系[email protected]



Linux Kernel Rootkit 1

原文始发于微信公众号(ChaMd5安全团队):Linux Kernel Rootkit 1

版权声明:admin 发表于 2021年10月30日 上午12:00。
转载请注明:Linux Kernel Rootkit 1 | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...