Attaching to gdb with pwntools
Table of Contents
0x00. Introduction
When solving pwnable challenges, I primarily use pwntools for scripting and gdb for debugging. Usually, you’d spawn a process and attach gdb from another terminal - but with pwntools and tmux, we can automate all of this within the script itself.
0x01. Debugging with pwntools
Spawning Process
=
=
# for remote
=
# for local
=
Use remote for remote, and process for local to run and connect to processes. Especially, remote is used not only when connecting to actual servers but also when connecting to locally running docker.
Open Debugger
The attach function from pwntools’ gdb module lets you attach a debugger to a running process:
=
= f
The second argument takes a gdb script, so you can automate setting breakpoints and continuing code flow.
Also, you can attach debugger to a process inside of docker with pid, using the following script:
=
=
With this script, it is possible to minimize the difference between local and remote environment. However, errors can occasionally occur when inside and outside of container has permissions that don’t match (see Permission Error).
Set Terminal
You need to configure where the attached debugger shows up. Simple enough with the context module’s terminal variable - just pick your preferred layout:
= # split current window horizontally
= # split current window vertically
= # split entire window horizontally
= # split entire window vertically
I know it’s pretty old-fashioned, but I’ve been using tmux since it’s pretty clean. You should also note that you’re actually running inside a tmux session before executing the script (see Tmux Session Error).
0x02. Conclusion
Here’s the final script I use as my exploit.py template:
=
=
=
= 0x555555554000
=
= f
=
=
=
=
=
=
=
=
The main function takes three arguments. If -p or --port is provided, it connects remotely. Otherwise, it runs locally for debugging:
When you’re done debugging, pass 0 to -d or --debug to run without a debugger:
Finally, to hit the actual server, pass the domain or IP to -s or --server - and definitely disable debugging:
Side note: I’m already doing from pwn import *, but I explicitly import the packing functions again on line 2 because vscode doesn’t seem to find them. Otherwise it shows annoying underlines.
0x03. Troubleshooting
Permission Error
When debugging a process inside of docker, the error above might occurs sometimes. If we take a closer look at the error, it’s something to do with permission. Printing out the current process list is as follows:
|
The debugger opened via python script is executed with user permission, whereas the target process challenge is executed with root permission. In this case attaching to the process fails, so the following lines should be added to Dockerfile.
RUN /usr/sbin/useradd -u 1000 ctf
USER ctf
You should note that the uid above should be identical with the user’s, who is running the python script. In the case of Ubuntu 24.04, for example, the user ubuntu is preempting uid 1000, possibly causing error because a new user will have uid 1001.
Tmux Session Error
This is what greeted me when I first ran the script:
)
)
)
)
)
)
The error hit at gdb.attach(s, gs) with a type issue, so I spent way too long thinking it was a pid datatype mismatch. Turns out it was something completely different.
The script tries to create a terminal in a tmux session - but there was no active tmux session to attach to. I naively assumed it would just create one automatically…