Skip to content

Instantly share code, notes, and snippets.

@turekt
Last active January 16, 2024 06:43
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save turekt/71f6950bc9f048daaeb69479845b672b to your computer and use it in GitHub Desktop.
Save turekt/71f6950bc9f048daaeb69479845b672b to your computer and use it in GitHub Desktop.
Running pwntools gdb debug feature inside Docker containers

Running pwnlib gdb (pwntools) feature inside Docker

Intro

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.

pwngdb-host

Problem

If you replicate the same example inside a docker container, your pwntools script will fail.

pwngdb-docker

Analysis

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.

Solution #1 (quick and easy with tmux)

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.

pwngdb-docker-tmux

Solution #2 (utilizing X11)

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.

pwngdb-docker-x11

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.

Appendix

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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment