在qemu上运行exp
在 qemu 上编写、构建和运行exp很麻烦,因为每次内核崩溃时,都必须重新开始。所以在本地编译好exp后再把它发送到 qemu会方便的多。
又由于每次都输入一大串命令很麻烦,所以把这些命令放在一个 shell 脚本transfer.sh里,每次执行这个脚本就好了。
#!/bin/sh
gcc exploit.c -o exploit # gcc编译exploit.c
mv exploit rootfs # 将编译结果exploit移动到rootfs(之前第一篇文章解压的那个目录)
cd rootfs; find . -print0 | cpio -o --null --format=newc --owner=root > ../debugfs.cpio
cd ../
qemu-system-x86_64 \
-m 64M \
-nographic \
-kernel bzImage \
-append "console=ttyS0 loglevel=3 oops=panic panic=-1 nopti nokaslr" \
-no-reboot \
-cpu qemu64 \
-gdb tcp::12345 \
-smp 1 \
-monitor /dev/null \
-initrd debugfs.cpio \
-net nic,model=virtio \
-net user
exploit.c
代码如下
#include <stdio.h>
int main() {
puts("Hello, World!");
return 0;
}
将这两个文件放在qemu目录下,如下所示:
lzx@ubuntu:~/LKPWN/pawnyable/LK01/qemu$ ls
bzImage exploit.c rootfs rootfs.cpio rootfs_updated.cpio run.sh transfer.sh
然后执行transfer.sh以启动qemu,最后在qemu中执行exploit,但是得到这样的错误:
[ Holstein v1 (LK01) - Pawnyable ]
/ # ./exploit
sh: ./exploit: not found
/ #
为什么?
因为这个镜像中使用的库为 uClibc ,而不是通常的 libc。而编译exploit的环境使用的是GCC,也就是libc,所以动态链接失败,exploit也不起作用。
因此,在 qemu 上运行 exploit 时,要注意静态链接它们。那么,修改脚本:
gcc exploit.c -o exploit -static
再次重新运行,那么程序应该可以正常工作:
[ Holstein v1 (LK01) - Pawnyable ]
/ # ./exploit
Hello, World!
/ #
小结:
- 将exp源文件和transfer.sh(视情况可能要做一定改变)放在qemu目录下
- 执行脚本transfer.sh
在远程机器上运行exp
本次分发的环境设置为允许网络连接,所以如果想远程执行,可以在qemu上使用wget命令传输exp。
但是在CTF等一些环境中,网络是不可用的。在这种情况下,有必要使用 busybox 中的命令远程传输二进制文件。一般使用base64,但是用GCC构建的文件有几百K到几十M,比如前面编译的exploit的大小就是826K,传输很费时间。文件大小的增加是由于外部库 (libc) 函数的静态链接。
lzx@ubuntu:~/LKPWN/pawnyable/LK01/qemu/rootfs$ ls -lh | grep exploit
-rwxrwxr-x 1 lzx lzx 826K Mar 11 00:26 exploit
如果想使用 GCC,并保持较小的大小,那么应该避免使用 libc 并使用系统调用(内联汇编)来自己定义读、写等,当然这是非常困难的。
所以许多 CTFer 使用名为 musl-gcc 的 C 编译器来进行内核利用。它可以从 https://www.musl-libc.org/ 下载源码,然后根据文档 https://git.musl-libc.org/cgit/musl/tree/INSTALL 进行构建并完成安装。
# 下载
lzx@ubuntu:~/tools$ wget https://musl.libc.org/releases/musl-1.2.3.tar.gz
--2023-03-11 00:59:06-- https://musl.libc.org/releases/musl-1.2.3.tar.gz
Resolving musl.libc.org (musl.libc.org)... 45.63.0.111, 2001:19f0:4009:4061:5400:ff:fe11:6da2
Connecting to musl.libc.org (musl.libc.org)|45.63.0.111|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 1058642 (1.0M) [application/gzip]
Saving to: ‘musl-1.2.3.tar.gz’
musl-1.2.3.tar.gz 100%[=============================================================================================================================>] 1.01M 881KB/s in 1.2s
2023-03-11 00:59:09 (881 KB/s) - ‘musl-1.2.3.tar.gz’ saved [1058642/1058642]
# 解压
lzx@ubuntu:~/tools$ tar -xzf musl-1.2.3.tar.gz
lzx@ubuntu:~/tools$ cd musl-1.2.3/
# 运行配置文件
lzx@ubuntu:~/tools/musl-1.2.3$ ./configure
......
# 编译
lzx@ubuntu:~/tools/musl-1.2.3$ make
......
# 安装
lzx@ubuntu:~/tools/musl-1.2.3$ sudo make install
......
./tools/install.sh -D obj/musl-gcc /usr/local/musl/bin/musl-gcc
安装完以后,就来使用了。使用musl-gcc编译exploit,然后移动到rootfs目录下(当然这一步可以省略,我只是为了保持统一):
lzx@ubuntu:~/LKPWN/pawnyable/LK01/qemu$ /usr/local/musl/bin/musl-gcc exploit.c -o exploit -static
lzx@ubuntu:~/LKPWN/pawnyable/LK01/qemu$ mv exploit rootfs
lzx@ubuntu:~/LKPWN/pawnyable/LK01/qemu$ ls -lh rootfs | grep exploit
-rwxrwxr-x 1 lzx lzx 11K Mar 11 01:16 exploit
可以看到exploit的大小由826K变成了11K。如果想让它更小,可以用 strip 等删除调试符号。
有些头文件(Linux内核类型)不在musl-gcc中,所以需要设置include路径或者用gcc编译。在这种情况下,先通过gcc汇编器构建
.S
文件,然后使用musl-gcc进行编译,就可以在使用 gcc 函数的同时,又减小文件大小。$ gcc -S sample.c -o sample.S $ musl-gcc sample.S -o sample.elf
最后编写一个脚本来使用 base64 远程传输(通过 nc)二进制文件。每次CTF都可能会用到这个上传器,所以建议大家自己制作一个模板。
from ptrlib import *
import time
import base64
import os
def run(cmd):
sock.sendlineafter("# ", cmd) # 这个需要根据情况改变,我这里的run.sh是以root启动qemu的,所以是#
sock.recvline()
with open("./rootfs/exploit", "rb") as f: # 同样,这个exploit的路径也是要根据情况改变
payload = bytes2str(base64.b64encode(f.read()))
#sock = Socket("HOST", PORT) # remote
sock = Process("./run.sh")
run('cd /tmp')
logger.info("Uploading...")
for i in range(0, len(payload), 512):
print(f"Uploading... {i:x} / {len(payload):x}")
run('echo "{}" >> b64exp'.format(payload[i:i+512]))
run('base64 -d b64exp > exploit')
run('rm b64exp')
run('chmod +x exploit')
sock.interactive()
然后执行这个脚本,要注意的一点是最好使用3.8及之后的python,不然 pip 安装完 ptrlib 之后,使用的时候仍可能报错。
lzx@ubuntu:~/LKPWN/pawnyable/LK01/qemu$ python -V
Python 3.9.16 (feeb267ead3e6771d3f2f49b83e1894839f64fb7, Dec 29 2022, 14:23:21)
[PyPy 7.3.11 with GCC 10.2.1 20210130 (Red Hat 10.2.1-11)]
lzx@ubuntu:~/LKPWN/pawnyable/LK01/qemu$ python upload_exp.py
[+] __init__: Successfully created new process (PID=83381)
[+] <module>: Uploading...
Uploading... 0 / 3780
Uploading... 200 / 3780
Uploading... 400 / 3780
Uploading... 600 / 3780
Uploading... 800 / 3780
Uploading... a00 / 3780
Uploading... c00 / 3780
Uploading... e00 / 3780
Uploading... 1000 / 3780
Uploading... 1200 / 3780
Uploading... 1400 / 3780
Uploading... 1600 / 3780
Uploading... 1800 / 3780
Uploading... 1a00 / 3780
Uploading... 1c00 / 3780
Uploading... 1e00 / 3780
Uploading... 2000 / 3780
Uploading... 2200 / 3780
Uploading... 2400 / 3780
Uploading... 2600 / 3780
Uploading... 2800 / 3780
Uploading... 2a00 / 3780
Uploading... 2c00 / 3780
Uploading... 2e00 / 3780
Uploading... 3000 / 3780
Uploading... 3200 / 3780
Uploading... 3400 / 3780
Uploading... 3600 / 3780
[ptrlib]$ /tmp # ls -lah
ls -lah
[ptrlib]$ total 44K
drwxrwxrwt 2 root root 100 Mar 10 18:28 .
drwxrwxr-x 17 root dhcpcd 420 Mar 10 18:28 ..
-rwxr-xr-x 1 root root 10.4K Mar 10 18:28 exploit
-rw-r--r-- 1 root root 27.9K Mar 10 18:28 messages
-rw-r--r-- 1 root root 149 Mar 10 18:28 resolv.conf
/tmp # ./exploit
.[ptrlib]$ /exploit
Hello, World!
/tmp #
最后小结一下:
- 在本地用musl编译好exp(如果有需要,将编译好的文件移动到某个目录下)
/usr/local/musl/bin/musl-gcc exploit.c -o exploit -static
- 根据实际情况,稍微修改上传脚本,然后执行脚本,将exp发送到qemu中:
python upload_exp.py