from pwn import *
context(arch = 'i386', os = 'linux')
r = remote('exploitme.example.com', 31337)
# EXPLOIT CODE GOES HERE
r.send(asm(shellcraft.sh()))
r.interactive()
Basics: from pwn import * - This imports a lot of functionality into the global namespace. You can now assemble, disassemble, pack, unpack, and many other things with a single function.
ALL FUNCTIONS:
Making Connections
You need to talk to the challenge binary in order to pwn it, right? pwntools makes this stupid simple with its pwnlib.tubes module.
This exposes a standard interface to talk to processes, sockets, serial ports, and all manner of things, along with some nifty helpers for common tasks. For example, remote connections via pwnlib.tubes.remote
Not only can you interact with processes programmatically, but you can actually interact with processes.
>>> sh.interactive() # doctest: +SKIP
$ whoami
user
There’s even an SSH module for when you’ve got to SSH into a box to perform a local/setuid exploit with pwnlib.tubes.ssh. You can quickly spawn processes and grab the output, or spawn a process and interact with it like a process tube.
A common task for exploit-writing is converting between integers as Python sees them, and their representation as a sequence of bytes. Usually, folks resort to the built-in struct module.
pwntools makes this easier with pwnlib.util.packing. No more remembering unpacking codes, and littering your code with helper routines.
The packing/unpacking operations are defined for many common bit-widths.
>>> u8(b'A') == 0x41
True
Misc Tools
Never write another hexdump, thanks to pwnlib.util.fiddling.
Find offsets in your buffer that cause a crash, thanks to pwnlib.cyclic.
>>> print(cyclic(20).decode())
aaaabaaacaaadaaaeaaa
>>> # Assume EIP = 0x62616166 (b'faab' which is pack(0x62616166)) at crash time
>>> print(cyclic_find(b'faab'))
120