Linux Loader 机制与内核模块修复

文章目录

[隐藏]

  • 0x0 前言
  • 0x1 Linux 启动与内核加载
    • 1.1 bootloader
    • 1.2 内核文件
    • 1.3 解剖 initramfs
    • 1.4 bootloader 配置
  • 0x2 内核模块依赖重建
    • 2.1 内核模块
    • 2.2 问题重现
    • 2.3 修复内核模块
  • 0x4 总结
0x0 前言

在吃着月饼喝着茶的闲暇时间里,突然接到某单位的应急通知。赶往现场进行初步勘察后,发现攻击者手段非常暴力,直接删除系统相关关键模块(包括 PAM 模块、基础内核驱动模块等),导致后续用户无法登录操作系统。

在尝试恢复 PAM 模块后,正常登录系统,但由于缺少基础的核心模块,网络、USB 挂载等仍无法正常使用。在下载部分二进制驱动包进行安装后,重启开始出现问题(截图为后期复现):

确认 /lib/modules/ 下确实存在此文件,但重启依然出现此问题。

而由于对 Linux Loader 机制的不熟悉,现场并未能解决此问题(菜。同时在不确定攻击者是否也删除了正常业务程序组件的情况下,恢复的成本较大,于是备份关键数据,提取相关样本与日志后,对系统进行重装,恢复正常业务。

0x1 Linux 启动与内核加载

1.1 bootloader

首先,还是从我们的老朋友 BIOS 进行加电自检(POST,Power-On Self-Test)后,开始读取 MBR 记录。MBR 为 512 字节大小的扇区,其中前 446 字节硬编码着 bootloader 程序。BIOS 从 MBR 记录读取 bootloader 程序,将其加载到内存,并运行该程序。

对于不同的操作系统,有不同的 bootloader 程序,一般在安装操作系统时,安装程序会向 MBR 写入 bootloader 程序。如 Windows 操作系统,使用自带的 bootloader 程序。对于 Linux 发行版,一般使用新版的 GRUB2 来生成并写入 bootloader。

bootloader 的工作便是载入内核文件,使操作系统正常运行。

1.2 内核文件

在 Linux 中,由 bootloader 载入的内核文件位于 /boot 节点下:

[root@centos boot]# ls --format=single-column /boot  config-2.6.32-696.el6.x86_64 # 内核编译时启用的配置信息与模块设定  efi # EFI 引导程序  grub # GRUB 引导程序支持  initramfs-2.6.32-696.el6.x86_64.img # 虚拟文件系统,主角 ;-)  symvers-2.6.32-696.el6.x86_64.gz # 驱动模块符号表  System.map-2.6.32-696.el6.x86_64 # 内核符号表  vmlinuz-2.6.32-696.el6.x86_64 # 内核文件  

如上,vmlinuz 便是 bootloader 载入的 Linux 内核文件,内核文件主要负责检测基础的硬件设施,并载入相关驱动,这些驱动一般位于 /lib/modules/<内核版本>/ 目录下。

那么 initramfs 是干嘛的?当内核启动时,需要往 /lib/modudles 下读取驱动文件,以支持 SATA、USB 等接口的设备,但是明显 /lib/modules 是存储于 SATA 磁盘中,没有 SATA 驱动的情况下也无法读取挂载,这里就出现了先有鸡还是先有蛋的问题。

而 initramfs 便是来解决这个问题,initramfs 事实上是一个具有根目录结构的文件,其中包含基础的应用程序,以及核心的内核模块,例如 SCSI、SATA、USB 等,用于支持最基础的外部设备。

1.3 解剖 initramfs

新建目录,将 initramfs 拷贝到目标目录下:

[root@centos ~]# mkdir /tmp/initramfs  [root@centos ~]# cp /boot/initramfs-2.6.32-696.el6.x86_64.img /tmp/initramfs/initramfs.img  

initramfs 使用 gzip 进行压缩,将其解压:

[root@centos ~]# cd /tmp/initramfs/  [root@centos initramfs]# file initramfs.img  initramfs.img: gzip compressed data, from Unix, last modified: Wed Oct  4 17:17:17 2017, max compression  [root@centos initramfs]# mv initramfs.img initramfs.gz  [root@centos initramfs]# gzip -d initramfs.gz  

在解压完成后,实际上文件使用 cpio 进行归档,最后我们使用 cpio 将其解压出来:

[root@centos initramfs]# file initramfs  initramfs: ASCII cpio archive (SVR4 with no CRC)    # -i 解压文件  # -d 必要时创建目录  # -H newc 指定类型为 SVR4 的归档文件  # --no-absolute-filenames 不要将文件解压覆盖到绝对路径  [root@centos initramfs]# cpio -i -d -H newc --no-absolute-filenames < initramfs  108638 blocks  

从最后的目录结构可以看到 initramfs 的真实内容:

[root@centos initramfs]# ll  total 54432  drwxr-xr-x. 2 root root     4096 Oct  5 22:50 bin  drwxr-xr-x. 2 root root     4096 Oct  5 22:50 cmdline  drwxr-xr-x. 3 root root     4096 Oct  5 22:50 dev  -rw-r--r--. 1 root root       23 Oct  5 22:50 dracut-004-409.el6_8.2  drwxr-xr-x. 2 root root     4096 Oct  5 22:50 emergency  drwxr-xr-x. 7 root root     4096 Oct  5 22:50 etc  -rwxr-xr-x. 1 root root     8989 Oct  5 22:50 init  drwxr-xr-x. 2 root root     4096 Oct  5 22:50 initqueue  drwxr-xr-x. 2 root root     4096 Oct  5 22:50 initqueue-finished  drwxr-xr-x. 2 root root     4096 Oct  5 22:50 initqueue-settled  drwxr-xr-x. 2 root root     4096 Oct  5 22:50 initqueue-timeout  drwxr-xr-x. 7 root root     4096 Oct  5 22:50 lib  drwxr-xr-x. 3 root root     4096 Oct  5 22:50 lib64  drwxr-xr-x. 2 root root     4096 Oct  5 22:50 mount  drwxr-xr-x. 2 root root     4096 Oct  5 22:50 netroot  drwxr-xr-x. 2 root root     4096 Oct  5 22:50 pre-mount  drwxr-xr-x. 2 root root     4096 Oct  5 22:50 pre-pivot  drwxr-xr-x. 2 root root     4096 Oct  5 22:50 pre-trigger  drwxr-xr-x. 2 root root     4096 Oct  5 22:50 pre-udev  drwxr-xr-x. 2 root root     4096 Oct  5 22:50 proc  drwxr-xr-x. 2 root root     4096 Oct  5 22:50 sbin  drwxr-xr-x. 2 root root     4096 Oct  5 22:50 sys  drwxr-xr-x. 2 root root     4096 Oct  5 22:50 sysroot  drwxrwxrwt. 2 root root     4096 Oct  5 22:50 tmp  drwxr-xr-x. 7 root root     4096 Oct  5 22:50 usr  drwxr-xr-x. 4 root root     4096 Oct  5 22:50 var  

列一下 lib/modules/<内核版本>/kernel/drivers 下的驱动文件:

[root@centos initramfs]# ls lib/modules/2.6.32-696.el6.x86_64/kernel/drivers/  acpi  ata  atm  auxdisplay  bcma  block  bluetooth  cdrom  <...snippets...>  

initramfs 中包含最核心的驱动程序,bootloader 在启动时,将 initramfs 临时挂载到根目录,在内核文件正常加载驱动后,对其进行卸载,并挂载真正的根目录节点。

最后,内核程序启动 init / systemd 对系统服务进行加载。

1.4 bootloader 配置

在 Linux 发行版下,bootloader 通常由 GRUB 程序进行管理,而 bootloader 又负责加载内核文件,较新的发行版一般使用新的 GRUB2 进行引导。

由于笔者使用的是 CentOS 6.X,所以此时默认还是旧版的 GRUB 引导管理程序,但不同版本配置上大同小异,所以以旧版为例。

默认情况下,/boot/grub 下(新版为/boot/grub2)存放 GRUB 的配置文件:

[root@centos ~]# ls /boot/grub  grub.conf # GRUB 的引导菜单配置文件  stage1  stage2  <...snippets...>  

可以注意到目录下有 stage1 和 stage2 文件,这个其实便是 bootloader 程序。由于 MBR 区域只有可怜的 512 字节,而 bootloader 程序相对都会比较大,所以 GRUB 将启动分为两个阶段,真正存在于 MBR 处的代码便是 stage1 程序,再由此加载真正的 bootloader 程序 stage2。

再看看主配置文件 /boot/grub/grub.conf 的内容:

# grub.conf generated by anaconda    default=0  timeout=5    title CentOS 6 (2.6.32-696.el6.x86_64)      root (hd0,0)      kernel /vmlinuz-2.6.32-696.el6.x86_64 ro root=/dev/mapper/vg_centos-lv_root nomodeset rd_NO_LUKS https://www.centos.bz/wp-content/uploads/2017/10/2-11.png" alt=""    />

再次重启后,正常进入系统,基本模块修复:

0x4 总结
  • 内核通过 initramfs 载入核心驱动为基础的外部设备提供支持
  • 内核模块位于 /lib/modules/<内核版本> 下,modules.dep 记录模块索引,使用 depmod -a 可以自动建立依赖信息
  • 使用 dracut 可以对 initramfs 进行重建,将 /lib/modules/ 下的核心模块打包到虚拟文件系统当中
  • 在 SELinux 的上下文下,需要建立 /.autorelabel 通知 SELinux 重新建立策略

总体而言都是在干运维的活,但是 Loader 的加载机制还是十分有趣。

原文出处:threathunter -> https://threathunter.org/topic/59d60bebec721b1f1966ec64https://threathunter.org/topic/59d60bebec721b1f1966ec64

本站所发布的一切资源仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。如果侵犯你的利益,请发送邮箱到 [email protected],我们会很快的为您处理。