Hack.lu CTF Get the tank challenge 400 points
The challenge could be found on an ssh server. Logging in, we find a +s binary "tank" and a "masterkey" file in our home directory. The binary demands a password given via command line arguments. Analyzing the binary in IDA gives:
The binary writes 20 bytes from /dev/urandom to a file called ".sessionid", then it compares the contents of the masterkey-file to the given password. If they match, we get a funny message. If not, the failing will be logged with the session id to a file "log". To do this it again reads the contents of the file ".sessionid". This time it fetches 41bytes, but writes it to a buffer, which is only 20 bytes in size. If we can control the file ".sessionid", we can overflow the buffer, effectively controlling the saved eip of the current function frame. Time to check exploitability.
$ readelf -a tank| grep STACK GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RWE 0x4
The stack is executable, also we can see from the disassembly, that there are not stack cookies. Unfortunately ASLR is switched on and we need to find a reliable way to get to our shellcode. From the stack layout we know that, when our function returns esp will point above our shellcode. The other registers do not help us. Searching the binary for usable gadgets, we immediately find exactly what we are looking for
1 2 3 4 5 6
80493f0: 83 ec 28 sub $0x28,%esp 80493f3: 90 nop 80493f4: 90 nop 80493f5: 90 nop 80493f6: 90 nop 80493f7: c3 ret
Setting the eip to 0x080493f0 will adjust the value of esp, so that program control will continue at the address we provide in our buffer. We have been there before, but now esp points to our shellcode. We just need to jump to it using "ff e4", which the binary happily provides at 0x080e04c7. This gives us full control now. The next problem is, that 32 byte is not that much of space to provide shellcode. To solve this we will just push shellcode into an environment variable and do a relative jump.
e9 90 11 00 00 jmp 0x1195
The final payload for the sessionid-file looks like this:
[0x080e04c7]["\xe9\x90\x11\x00\x00"]["x"*27][0x080493f0] jmp esp jmp 640 garbage sub-gadget
Finally we need the shellcode that reads our file. I reused shellcode from the CSAW CTF 2012 Exploitation challenges, where a similar shellcode was needed. You can find it on this blog and I will not repeat it here. The final problem is the racing condition, which has to be won. There is a fflush(stdout), which can in theory be used to block the execution of the target binary at this point, but fortunately this was not necessary. Two while loops, one writing the payload to ".sessionid" and one executing the binary with an arbritrary password soon yielded the flag: DID_YOU_EAT_YOUR_FILE_DESCRIPTORS_TODAY?