Tubes are effectively I/O wrappers for most types of I/O you'll need to perform:
- Local processes
- Remote TCP or UDP connections
- Processes running on a remote server over SSH
- Serial port I/O
This introduction provides a few examples of the functionality provided, but more complex combinations are possible. See the full documentation for more information on how to perform regular expression matching, and connecting tubes together.
The basic functions that you'll probably want out of your IO are:
recv(n)
- Receive any number of available bytesrecvline()
- Receive data until a newline is encounteredrecvuntil(delim)
- Receive data until a delimiter is foundrecvregex(pattern)
- Receive data until a regex pattern is satisfiedrecvrepeat(timeout)
- Keep receiving data until a timeout occursclean()
- Discard all buffered data
send(data)
- Sends datasendline(line)
- Sends data plus a newline
pack(int)
- Sends a word-size packed integerunpack()
- Receives and unpacks a word-size integer
In order to create a tube to talk to a process, you just create a process
object and give it the name of the target binary.
from pwn import *
io = process('sh')
io.sendline('echo Hello, world')
io.recvline()
# 'Hello, world\n'
If you need to provide command-line arguments, or set the environment, additional options are available. See the full documentation for more information;
from pwn import *
io = process(['sh', '-c', 'echo $MYENV'], env={'MYENV': 'MYVAL'})
io.recvline()
# 'MYVAL\n'
Reading binary data isn't a problem either. You can receive up-to a number of bytes with recv
, or block for an exact count with recvn
.
from pwn import *
io = process(['sh', '-c', 'echo A; sleep 1; echo B; sleep 1; echo C; sleep 1; echo DDD'])
io.recv()
# 'A\n'
io.recvn(4)
# 'B\nC\n'
hex(io.unpack())
# 0xa444444
Did you land a shell on the game server? Hurray! It's pretty easy to use it interactively.
from pwn import *
# Let's pretend we're uber 1337 and landed a shell.
io = process('sh')
# <exploit goes here>
io.interactive()
Creating a network connection is also easy, and has the exact same interface. A remote
object connects to somewhere else, while a listen
object waits for a connection.
from pwn import *
io = remote('google.com', 80)
io.send('GET /\r\n\r\n')
io.recvline()
# 'HTTP/1.0 200 OK\r\n'
If you need to specify protocol information, it's also pretty straightforward.
from pwn import *
dns = remote('8.8.8.8', 53, typ='udp')
tcp6 = remote('google.com', 80, fam='ipv6')
Listening for connections isn't much more complex. Note that this listens for exactly one connection, then stops listening.
from pwn import *
client = listen(8080).wait_for_connection()
SSH connectivity is similarly simple. Compare the code below with that in "Hello Process" above.
You can also do more complex things with SSH, such as port forwarding and file upload / download. See the SSH tutorial for more information.
from pwn import *
session = ssh('bandit0', 'bandit.labs.overthewire.org', 2220, password='bandit0')
io = session.process('/bin/sh', env={"PS1":""})
io.sendline('echo Hello, world!')
io.recvline()
# 'Hello, world!\n'
In the event you need to get some local hacking done, there's also a serial tube. As always, there is more information in the full online documentation.
from pwn import *
io = serialtube('/dev/ttyUSB0', baudrate=115200)