Skip to content

pwntools – Getting started with Tubes

What is pwntools.

The python module pwntools is a collection of tools developed to be used for CTF challenges. According to the website pwntools is a “Toolbox optimized for CTFs” In this short write-up I introduce to the functionality around tubes. I will only focus on “pwn” the python module for CTF Challenges. There is an binary that is installed along with it but I prefer to only use the python module as it reinforces my python knowledge.

Set-up pwntools

For this I will be using my BlackArch system that I built and documented in a previous blog post. You can use any modern Linux flavor but my focus is on Arch commands.

So let’s get started. First of all pwntools has to be installed. This can be done by running the command.

sudo pip install pwntools

Hello World in tubes

pwntools uses tubes to communicate to system process. Lets start with a simple ‘Hello World” script.

import pwn

p = pwn.process('/bin/bash')
p.sendline('echo Hello World')

Let’s run it.

If you look closely at the gif there is a “BytesWarning” that this module is expecting data to be inputted in “byte” format. So lets change it up a bit to allow for that.

import pwn

p = pwn.process('/bin/bash')
p.sendline(b'echo Hello World')

Now lets run this.

Looking much better, no errors this time. Also note that the output is also in bytes. If you need to print it you need to decode it into utf8 ASCII format.

import pwn

p = pwn.process('/bin/bash')
p.sendline(b'echo Hello World')
data = p.readline()

Tubes Arguments

What happens if we need to give some arguments to our commands. Well this is done by way of array arguments.

import pwn
p = pwn.process(['uname', '-r'])

Couple of new things here. First of all we have “p = pwn.process([‘uname’, ‘-r’])“. Here we see that the command ‘uname -r’ is run but the command and its arguments are wrapped up inside an array. This is how it works for all commands.

Also new we see “p.close()”. This tells python to close off and kill the process. We need to do this to clean up so we don’t leave any processes running after the script is completed.

Networking with Tubes

I know we have “netcat” but isn’t fun to create a listener with python.

import pwn
port = 9999
p = pwn.listen(port).wait_for_connection()

pwntools tubes and FTP Server

One of the thing I love about docker is being able to spin up services quickly to test something. In this case i will spin up a temporary ftp server so we can play some more with pwntools.

docker run -it -d --rm \
--name ftp -p 21:21 \
-e USERS="anonymous|" \
-p 21000-21010:21000-21010 \
import pwn
server = ''
port = '21'
c = pown.remote(server,port)
c.send(b'USER anonymous\r\n')
c.send(b'PASS \r\n')

Although an interesting experiment and clearly documented in pwntools library, I do not recommend using pwntools to interact with ftp. It’s not very reliable or worth the effort.

SSH and pwntools

There is also a ssh module for pwntools that allows for remote execution.

s = pwn.ssh('tkraz', 'localhost', password='letmein', port=22)
[x] Connecting to localhost on port 22
[+] Connecting to localhost on port 22: Done
>>> print(s['date'].decode('utf8'))
[x] Opening new channel: 'date'
[+] Opening new channel: 'date': Done
[x] Receiving all data
[x] Receiving all data: 0B
[x] Receiving all data: 29B
[+] Receiving all data: Done (29B)
[*] Closed SSH channel with localhost
Thu Mar  3 21:58:05 GMT 2022


pwntools by default has log level of info. When running the command it spew a lot of usless information to the screen. in order to get rid of it, at the top of your script put in,

pwn.context.log_leve = "error"


For CTF challenges pwntools is a very useful tool. It has a lot going for it and a lot of different tools under its belt. However it is a “Jack of all Trades and Master of None”. There are much better python modules out there for the jobs it does. The whole pint of pwntools is you only need to learn one module instead of many and in this case its a winner.

Published inIT & Security