前言
记录一下qemu逃逸的基础知识以及做题相关的技巧
例题是津门杯的qemu逃逸,个人觉得比较简单适合入门
分析
run.sh
#! /bin/sh
./qemu-system-x86_64 \
-initrd ./rootfs.cpio \
-kernel ./vmlinuz-4.8.0-52-generic \
-append 'console=ttyS0 root=/dev/ram oops=panic panic=1 quiet' \
-monitor /dev/null \
-m 64M --nographic \
-L pc-bios \
-device edu,id=vda
非预期
首先我们需要注意的-monitor这一句,因为如果有的题目没有加这一句则有可能导致非预期的产生,具体的做法可以参考:链接
步骤是首先ctrl+a 然后输入c回车之后即可进入monitor模式,然后就可以为所欲为了,可以用migrate来执行命令读取flag
migrate "exec:cat flag 1>&2"
正常分析
如果有monitor这一句的话那就接着分析
可以注意到-device edu,我们将所给的qemu-system-x86_64文件导进ida中,因为文件比较大,因此需要一段时间,导入成功后我们搜索edu相关函数,可以看到如下
通常漏洞是数组越界以及栈溢出,产生漏洞的函数常常集中在pmmio以及mmio或者timer函数,因此我们着重分析这些函数,当然也不排除特殊情况,具体还要看相关题目来做具体的分析,因为本题只有mmio函数,我们只要分析mmio函数即可
这里还有一个注意点,由于ida分析函数的顺序问题,可能会出现试别不出结构题的情况这时候我们只需要切换到汇编模式,查看相应的rdi对应的结构体的名称,然后在反汇编的页面将rdi按y修改类型即可例如
可以看到初始时没有试别结构体的,然后我们按y来修改类型
可以看到成功识别结构体
edu_mmio_write
void __fastcall edu_mmio_write(void *opaque, hwaddr addr, uint64_t val, unsigned int size)
{
__int64 v4; // rdi
__int64 v5; // rax
__int64 v6; // rdx
_BYTE v7[24]; // [rsp+0h] [rbp-28h]
unsigned __int64 v8; // [rsp+18h] [rbp-10h]
v8 = __readfsqword(0x28u);
if ( addr <= 0xFF && size == 4 )
{
cmd_buf[(unsigned int)addr] = val;
}
else if ( addr == 296 )
{
if ( buf_len > 0 )
{
v4 = (unsigned int)(buf_len - 1);
v5 = 0LL;
do
{
v7[v5] = cmd_buf[v5];
v6 = v5++;
}
while ( v4 != v6 );
}
if ( v7[4] == 3 )
buf_len = 291;
}
else if ( addr == 304 )
{
buf_len = val;
}
通过分析可以看到该函数主要实现了以下作用:
addr <= 0xff 将val赋值给cmd_buf[addr]处
addr = 0x130 将val赋值给buf_len
addr = 0x128 && buf_len>0 && v6!=v4将cmd_buf数组的内容逐字节赋值给v7数组
这里很容易发现有个栈溢出漏洞,可以溢出v7来达到栈溢出的目的
edu_mmio_read
uint64_t __fastcall edu_mmio_read(EduState *opaque, hwaddr addr, unsigned int size)
{
uint64_t result; // rax
char buf[16]; // [rsp+10h] [rbp-38h]
unsigned __int64 v5; // [rsp+28h] [rbp-20h]
v5 = __readfsqword(0x28u);
if ( addr <= 0x2FF && size == 4 )
return buf[(unsigned int)addr];
if ( addr <= 0x7F && size != 4 )
return buf_len + cmd_buf[addr];
if ( ((size - 4) & 0xFFFFFFFB) == 0 || (result = -1LL, addr <= 0x7F) )
{
if ( addr <= 0x24 )
__asm {
jmp rax }
if ( addr != 144 )
{
if ( addr <= 0x90 )
{
if ( addr == 128 )
return opaque->dma.src;
if ( addr == 136 )
return opaque->dma.dst;
}
else if ( addr == 152 )
{