When conducting exploit development with pwntools you will often want to utilize the pwnlib gdb feature which will ease the usage of gdb and gdb scripts. Let's look into a simple example.
Assume that you have the following code you are analyzing:
// Compile: gcc -o /tmp/example -no-pie -fno-stack-protector example.c && chmod +x /tmp/example
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void submit() {
char data[8];
printf("submit something: ");
read(0, &data, 200);
}
int main() {
setbuf(stdout, NULL);
setbuf(stdin, NULL);
puts("program is starting ...");
submit();
puts("thanks\nprogram exiting ...");
}
You are analyzing the code on your PC and you wrote the following pwntools script:
from pwn import *
p = gdb.debug('/tmp/example', '''
break read
continue
''')
print(p.recvuntil('submit something: '))
p.sendline('A' * 40)
p.interactive()
After executing python exploit.py
, the script will open a new terminal with a gdb prompt so you can continue debugging.
If you replicate the same example inside a docker container, your pwntools script will fail.
The issue in running gdb.debug
inside docker is because the terminal is not set inside the pwnlib context. A quick sneak peek into source code documentation reveals the following:
>>> from pwn import *
>>> help(context)
...
| terminal
| Default terminal used by :meth:`pwnlib.util.misc.run_in_new_terminal`.
| Can be a string or an iterable of strings. In the latter case the first
| entry is the terminal and the rest are default arguments.
...
>>> help(pwnlib.util.misc.run_in_new_terminal)
...
When ``terminal`` is not set:
- If ``context.terminal`` is set it will be used.
If it is an iterable then ``context.terminal[1:]`` are default arguments.
- If a ``pwntools-terminal`` command exists in ``$PATH``, it is used
- If ``$TERM_PROGRAM`` is set, that is used.
- If X11 is detected (by the presence of the ``$DISPLAY`` environment
variable), ``x-terminal-emulator`` is used.
- If tmux is detected (by the presence of the ``$TMUX`` environment
variable), a new pane will be opened.
- If GNU Screen is detected (by the presence of the ``$STY`` environment
variable), a new screen will be opened.
...
Inside docker, none of the conditions are true, therefore we are receiving the error message.
In order to overcome this issue quickly, we can install tmux into docker container. After this is set up, change the pwntools script by adding the terminal context:
from pwn import *
# you can use any of:
# ['tmux', 'split-window', '-h'] -> will run gdb in a new pane, horizontal split
# ['tmux', 'split-window', '-v'] -> will run gdb in a new pane, vertical split
# ['tmux', 'new-window'] -> will run gdb in a new window
context(terminal=['tmux', 'split-window', '-h'])
p = gdb.debug('/tmp/example', '''
break read
continue
''')
print(p.recvuntil('submit something: '))
p.sendline('A' * 40)
p.interactive()
Run tmux
inside your docker container and execute python exploit.py
, you should now get two panes (or windows) inside your tmux session.
There are a ton of resources on how to setup GUI apps with docker, which is essentially what we require to overcome this problem since we want to issue a new x-terminal-emulator
. IMO, this approach is not ideal since it is specific and might require tweaking in order for it to work on your device. So, I'm going to write down how I have successfully spawned new x-terminal-emulator
and give additional resources which might be needed for additional setup and/or tweaking.
If this approach is used, terminal context does not need to be set at all, the pwntools script can be used as is. Only thing that needs to be done is to execute a xhost +
command in your terminal in order to loosen X access control. Afterwards run your docker container with:
sudo docker run -it -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=$DISPLAY gdb-test
After executing python exploit.py
inside the container, new terminal will open. In order to re-establish protections, run xhost -
inside your shell.
Keep in mind that this approach is far from perfect. You are using X that is running on the host machine and removing Xauthority protections. Consult links below to tailor your own setup.
- Docker containers on the desktop, GUI section
- how to use -e DISPLAY flag on osx?
- Running Chromium inside Docker
- Can you run GUI applications in a Docker container?
Dockerfile gdb-test:
FROM ubuntu:16.04
RUN apt-get update -y && \
apt-get upgrade -y
RUN apt-get install -y python-pip gdb wget curl python2.7 python-pip python-dev git libssl-dev libffi-dev build-essential tmux xterm
RUN pip install --upgrade pip && \
pip install --upgrade pwntools
RUN apt-get install -y vim
COPY ./example.c /example.c
COPY ./exploit.py /exploit.py
RUN gcc -o /tmp/example -no-pie -fno-stack-protector example.c && chmod +x /tmp/example