【Pwn 笔记】Linux Kernel 调试文件总结

用于上传文件的脚本就放到最后啦

baby.ko

漏洞模块,要拖到 IDA 看的,要打的题就是它

bzImage

概述

vmlinux

vmlinux 是 ELF 文件,未压缩的内核,即编译出来的最原始的文件

vmlinux 用于 kernel-debug,产生 system.map 符号表,不能用于直接加载,不可以作为启动内核,只是启动过程中的中间媒体

vmlinuz

vmlinuz 是可引导的、压缩的内核,vm 代表 Virtual Memory

Linux 支持虚拟内存,不像老的操作系统比如 DOS 有 640KB 内存的限制,因为 Linux 能够使用硬盘空间作为虚拟内存,所以得名 vm

vmlinuz 是可执行的 Linux 内核,位于/boot/vmlinuz。它一般是一个软链接,但是已经丢失了调试信息等数据,不可用于调试

这就是为什么 perf 和 systemtap 等内核级别的调试软件安装的时候,需要重新编译内核的原因

同理,解压缩 vmlinuz 是不能得到 vmlinux 的,相对于 vmlinux,它增加了解压缩和 boot 的部分

zImage

zImage 是 vmlinuz 经过 gzip 压缩后的文件,适用于小内核(512KB 以内),加载到内存的开始 640KB 处

bzImage

bzImage 是 vmlinuz 经过 gzip 压缩后的文件,适用于大内核,为什么会发明 bzImage 这种内核镜像呢?

随着 Linux 内核的成熟,Linux 内核的大小逐渐增大,超过了一些体系结构的限制,导致存储压缩内核的空间受到限制

bzImage 这种格式就是为了克服这种限制,它通过把 kernel 分解到不相邻的内存区域来达到这一个目的

bzImage 包含以下目标文件:bootsect.o + setup.o + misc.o + piggy.o

bzImage 的解剖图:

Image

做题要点

extract-vmlinux

主要是在题目没有提供 vmlinux 用以调试内核及查看 rop 的时候,利用 extract-vmlinux 命令可以从 bzImage 中提取 vmlinux

extract-vmlinux 存在于在搭建 Kernel 环境时编译 linux 内核的文件夹里,我的路径是/linux-4.20/scripts/extract-vmlinux

ropper

ropper 提取 rop 的速度比 ROPgadget 要快很多,但是安装属实困难,最主要的问题出在安装 filebytes 上面

安装这个库的时候包名都变成了 UNKNOWN,之后了解到是因为没更新 setuptools,用命令更新一下:

1
sudo pip install setuptools --upgrade

然后抛错

1
ERROR: launchpadlib 1.10.3 requires testresources, which is not installed.

再安装即可

1
2
sudo pip install launchpadlib
sudo pip install filebytes

之后按照 github 上面写的安装 ropper 的步骤来就完事了,提取 rop 的方法如下:

1
ropper -f vmlinux --nocolor > gadget.txt

initramfs.cpio

cpio 文件的压缩和解包

压缩

这个一定要在解压出来的文件目录内运行,不然最后出来的镜像文件是不完整的

1
find . | cpio -o --format=newc > initramfs.cpio

解压

将 cpio 文件内的文件全部解压到当前目录,最好一开始建个文件夹,将这些文件都存在单独的文件夹里

1
sudo cpio -idmv < initramfs.cpio

这个右键归档管理器貌似也能解压,可能是因为我装了 7z

rcS

这个文件一般都在解包后文件夹的/etc/init.d里,记载着内核启动时的参数,一般 rcS 文件内会写有如下参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/sh
mount -t devtmpfs none /dev
mount -t proc proc /proc

insmod /home/pwn/baby.ko
chmod 644 /dev/baby
echo 1 > /proc/sys/kernel/dmesg_restrict
echo 1 > /proc/sys/kernel/kptr_restrict

cd /home/pwn
setsid cttyhack setuidgid 1000 sh

umount /proc
poweroff -f

这里调试的时候需要把 1000 改成 0000 来获得 root 权限,改成 0 会崩,一定要 4 个 0

下面就简单讲解一下这些参数:

mount -t devtmpfs none /dev

挂载 devtmpfs 类型的文件系统,设备名设置为 none,挂载目录为 /dev

devtmpfs 的功用是在 Linux 核心启动早期建立一个初步的 /dev,令一般启动程序不用等待 udev,缩短 GNU/Linux 的开机时间。

mount -t proc proc /proc

挂载 proc 类型的文件系统,设备名设置为 proc,挂载目录为 /proc

insmod /home/pwn/baby.ko

加载存在漏洞的题目模块到内核中

chmod 644 /dev/baby

这块还不懂,但是不设置内核会崩,改的是一个字符设备文件的权限

echo 1 > /proc/sys/kernel/dmesg_restrict

这个参数是不让非 root 用户读取 dmesg 的输出信息的

设置为 0 就可以输出 dmesg 的信息了,但是没必要,改成 root 用户就好了

echo 1 > /proc/sys/kernel/kptr_restrict

有 0、1、2 三个值可以选择,这里的 1 具体我也不懂,不过 1 和 0 都是能打印内核符号表的

如果是 2 的话,打印的符号表地址就都是 0,相当于不让你读取了,一般读取方法如下:

grep prepare_kernel_cred /proc/kallsyms

cd /home/pwn

漏洞模块在这,没啥好说的

setsid cttyhack setuidgid 1000 sh

创建一个子进程,并使子进程成为新会话的首进程,成为新进程组的组长进程

用户组设置为 1000,登录 shell 设置为 sh

这个 cttyhack 我不知道啥意思,不过写上就完了

umount /proc

卸除挂载的 /proc 文件夹

poweroff -f

不写起不了程序,暂且不知道是退出啥终端

startvm.sh

起程序的脚本,一般大致如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/bash

stty intr ^]
cd `dirname $0`
timeout --foreground 600 qemu-system-x86_64\
-m 64M \
-nographic \
-kernel bzImage \
-append 'console=ttyS0 loglevel=3 oops=panic panic=1 nokaslr' \
-monitor /dev/null \
-initrd initramfs.cpio \
-smp cores=1,threads=1 \
-cpu qemu64 2>/dev/null

调试的时候需要在后面加一个 -s 用来开放本地的 1234 号端口,用 gdb-multiarch 监听 1234 端口即可

如果 1234 号端口用不了,也可以换成 -gdb tcp::端口号,改完大致如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/bash

stty intr ^]
cd `dirname $0`
timeout --foreground 600 qemu-system-x86_64\
-m 64M \
-nographic \
-kernel bzImage \
-append 'console=ttyS0 loglevel=3 oops=panic panic=1 nokaslr' \
-monitor /dev/null \
-initrd initramfs.cpio \
-smp cores=1,threads=1 \
-cpu qemu64 2>/dev/null \
-gdb tcp::2134

exp 上传脚本

这里用的是 sixstars 战队中一位师傅的脚本,采用 base64 来进行文件编码传输

我改了改脚本,写 exp 的时候需要在当前目录下新建一个 poc 文件夹,把 c 文件和 c 程序都放在那里

这样看起来不乱,程序的名字设置成 exp 就好

普通用户

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *
import os

# context.log_level = 'debug'
cmd = '$ '


def exploit(r):
r.sendlineafter(cmd, 'stty -echo')
os.system('musl-gcc -static -O2 ./poc/exp.c -o ./poc/exp')
os.system('gzip -c ./poc/exp > ./poc/exp.gz')
r.sendlineafter(cmd, 'cat <<EOF > exp.gz.b64')
r.sendline((read('./poc/exp.gz')).encode('base64'))
r.sendline('EOF')
r.sendlineafter(cmd, 'base64 -d exp.gz.b64 > exp.gz')
r.sendlineafter(cmd, 'gunzip ./exp.gz')
r.sendlineafter(cmd, 'chmod +x ./exp')
r.sendlineafter(cmd, './exp')
r.interactive()


p = process('./startvm.sh', shell=True)
# p = remote('', )

exploit(p)

root 用户

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *
import os

# context.log_level = 'debug'
cmd = '# '


def exploit(r):
r.sendlineafter(cmd, 'stty -echo')
os.system('musl-gcc -static -O2 ./poc/exp.c -o ./poc/exp')
os.system('gzip -c ./poc/exp > ./poc/exp.gz')
r.sendlineafter(cmd, 'cat <<EOF > exp.gz.b64')
r.sendline((read('./poc/exp.gz')).encode('base64'))
r.sendline('EOF')
r.sendlineafter(cmd, 'base64 -d exp.gz.b64 > exp.gz')
r.sendlineafter(cmd, 'gunzip ./exp.gz')
r.sendlineafter(cmd, 'chmod +x ./exp')
r.sendlineafter(cmd, './exp')
r.interactive()


p = process('./startvm.sh', shell=True)
# p = remote('', )

exploit(p)

参考链接

1
2
https://www.cnblogs.com/javawebsoa/archive/2013/07/24/3212564.html
https://blog.csdn.net/tiantao2012/article/details/78864757
文章目录
  1. 1. baby.ko
  2. 2. bzImage
    1. 2.1. 概述
      1. 2.1.1. vmlinux
      2. 2.1.2. vmlinuz
      3. 2.1.3. zImage
      4. 2.1.4. bzImage
    2. 2.2. 做题要点
      1. 2.2.1. extract-vmlinux
      2. 2.2.2. ropper
  3. 3. initramfs.cpio
    1. 3.1. cpio 文件的压缩和解包
      1. 3.1.1. 压缩
      2. 3.1.2. 解压
    2. 3.2. rcS
      1. 3.2.1. mount -t devtmpfs none /dev
      2. 3.2.2. mount -t proc proc /proc
      3. 3.2.3. insmod /home/pwn/baby.ko
      4. 3.2.4. chmod 644 /dev/baby
      5. 3.2.5. echo 1 > /proc/sys/kernel/dmesg_restrict
      6. 3.2.6. echo 1 > /proc/sys/kernel/kptr_restrict
      7. 3.2.7. cd /home/pwn
      8. 3.2.8. setsid cttyhack setuidgid 1000 sh
      9. 3.2.9. umount /proc
      10. 3.2.10. poweroff -f
  4. 4. startvm.sh
  5. 5. exp 上传脚本
    1. 5.1. 普通用户
    2. 5.2. root 用户
  6. 6. 参考链接
|