Pwntools Cheatsheet
This is a very brief cheatsheet and introduction to pwntools
for CTFs. I am writing this specifically for Sieberrsec CTF 5.0, but it can be applied for all CTFs.
Install and Import
pip install pwntools
: to install pwntools, use this command in the terminal
from pwn import *
: put this at the top of your python file to import pwntools.
Making connections
r = remote(HOST, PORT)
: connects to a remote connection, with the relevant host and port
- Eg if the CTF tells you to connect to the instance via
nc 1.1.1.1 2000
,1.1.1.1
is the host, and2000
is the port - This command is in effect the same as
nc
r.interactive()
: allows you to interact with the process yourself
- We usually use this at the very end after we have obtained the shell or when the flag is printed out
ELF manipulation
CTF challenges usually provide an ELF file for you to run. An ELF file is essentially the linux version of an .exe
file.
elf = ELF('./NAME')
: this allows you to get information about an ELF file of the specified name
r = elf.process(stdin=PTY)
: this executes the ELF file
- Usually we use this to test the challenge locally
- Then switch to
remote(HOST,PORT)
to connect to the remote instance
elf.symbols['FUNCTION']
: gets the address of the specified function
- Eg
elf.symbols['main']
gives the address of main()
Reading data and providing input
conn.recvline()
: reads one line of data
conn.recvlines(N)
: reads N lines of data
conn.recvuntil(VALUE)
: reads data until VALUE
conn.sendline(VALUE)
: sends an input of VALUE
Further readings
These commands are left as an exercise to the reader to learn more about. For more commands, refer to their documentation.
p64(NUMBER)
and p32(NUMBER)
: struct unpacking
elf.got['write']
,elf.plt['write']
: get the GOT and PLT addresses
Sample
Imagine that you are provided with a file which does this:
int main() {
int n1 = rand();
int input;
// prints "n1: xx" where xx is the number randomly generated
printf("n1: %d\n",n1);
puts("What is the value of n1?");
// gets an integer input
scanf("d",&input);
// get the flag if input is equal to n1
if (input == n1) {
print_flag();
}
}
So, the file will print the value of n1, and then you will need to input n1 back.
This is how you can use pwntools to solve the challenge:
from pwn import *
elf = context.binary = ELF("./challenge")
local = False
if local:
# execute the local file
r = elf.process()
else:
# connect to the remote instance
r = remote("challs.sieberr.live", 1337)
# get the value of n1
r.recvuntil(b'n1: ')
n1 = int(r.recvline())
# input n1
r.sendline(str(n1))
# interact with the process yourself, so you can see the value of the flag
r.interactive()