Hfs-vm1
Points: 287
Solves: 42
Write a program in my crappy VM language.

By the name and description of the challenge its pretty clear that we are dealing with a VM. Taking a look at the main function, it uses socketpair to create connected sockets and allocates some memory. The process then forks, the parent process acts as the kernel component and the child process acts as the usermode component. The child component implements a VM which has ability to communicate with the kernel component and make syscalls.

There are 5 syscalls supported by the kernel:

0 - ls
1 - write
2 - getuid
3 - read_flag1
4 - get_random_bytes

For the first part of the challenge the only syscall we are interested in is 3 (read_flag1).

The child component takes the program to execute as input. After this a structure which looks like it tracks the vmstate is initialized. Analyzing this structure and the 0xA instruction (prints registers and stack) in the VM, we can define the structure and make our analysis easy.

vm_state

So there are total of 16 registers all of which are 2 types, the 15th register is SP and last one is IP. Size of the stack is 32 Words. Size of each instruction is 32 bits, out of which last 5 bits decide which instruction will be executed and rest are arguments. The following are the instructions supported by the VM:

0x0 - mov
0x1 - add
0x2 - sub
0x3 - swap_regs
0x4 - xor
0x5 - push
0x6 - pop
0x7 - mov_to_stack
0x8 - mov_to_reg_from_stack
0x9 - syscall
0xa - print_regs_stack

Analysing the syscall instruction and the kernel, we see the syscall executed is decided by register 1 and the result of the syscall is copied to the stack. Here is the program i wrote to read flag1.

from pwn import *

r = remote("hfs-vm-01.play.midnightsunctf.se", 4096)

bytecode = p32(0x032020) 		# move 3 to register 1
bytecode += p32(0x12005) * 31	# allocate space on stack for flag
bytecode += p32(0x9)			# make read_flag syscall
bytecode += p32(0xa)			# print regs and stack

r.recvuntil("length: ")
r.sendline(str(len(bytecode)))
r.recvuntil("code: ")
r.sendline(bytecode)
r.interactive()

We can see the flag on the stack and decoding it we get the flag midnight{m3_h4bl0_vm}

Categories: CTFs