# Challenges in Containers

Sometimes you get challenges provided with a `Dockerfile`. In most cases, it's best to use it, as you can be sure it acts the same locally and remotely.

Unfortunately, that can be rough. There are a few steps. In essence, we want to use `gdbserver` to set up a debug session, then connect to `gdbserver` from our host to leverage the full power of whatever we want to debug with. These steps work for debugging a binary hosted via `socat`.

## Quick Copy

Add:

<pre class="language-docker"><code class="lang-docker">RUN apt-get install -y gdb gdbserver
<strong> -- OR --
</strong>RUN apk add gdb

-p 9090:9090 --cap-add=SYS_PTRACE
</code></pre>

Run:

```bash
docker exec -it challenge /bin/bash
gdbserver :9090 --attach $(pidof challenge)
```

Connect:

```bash
r2 -d gdb://localhost:9090
```

OR

```bash
gdb challenge
target remote :9090
```

## Explanation

### Install

Add some installs to the Dockerfile:

```docker
RUN apt-get install -y gdb gdbserver
```

If the Dockerfile is an alpine image, instead use

```docker
RUN apk add gdb
```

`gdbserver` is automatically installed as part of the package.

## Change Run Command in build\_docker.sh

Add the&#x20;

```
-p 9090:9090 --cap-add=SYS_PTRACE
```

flags to the `docker run ...` command in `build_docker.sh`.

* `-p 9090:9090` binds the internal port `9090` to the external port `9090`, so we can connect to `localhost:9090` for the `gdbserver`
* `--cap-add=SYS_PTRACE` gives the container the capability to `ptrace` a process, which we need for debugging. The alternative is to run it in `--privileged` mode, which is far more unsafe

## Start the Executable and get the PID

Get a shell with `docker exec`:

```bash
docker exec -it challenge /bin/bash
```

Note that to get a binary started with `socat`, we have to connect to the service first in order to start a process. So, outside the container, connect with `nc`:

```bash
$ nc localhost 1337
<pwnable binary>
```

Don't end the process. Switch back to the Docker `root` shell:

```
root@096c4ec3bca6:/# pidof challenge
22
```

Grab the PID of the subprocess, in this case `22`.&#x20;

## Starting GDBserver

Now start a `gdbserver`:

```
gdbserver :9090 --attach 22
```

{% hint style="info" %}
You can combine this into one command:\
`gdbserver :9090 --attach $(pidof challenge)`
{% endhint %}

And on your host you can now connect to it with radare2 or GDB:

```bash
$ r2 -d gdb://localhost:9090
```

```
$ gdb challenge
(gdb) target remote :9090
Remote debugging using 172.17.0.2:9090
[...]
(gdb)
```

And boom.

Note the issue is that you have to restart gdbserver *every* time you connect again. Don't forget! Maybe there's a better way, but I don't know.

Did try and replace the shell commands with a single `docker exec`, but the `$()` is resolved before it is piped to the Docker:

```bash
$ docker exec -it challenge gdbserver :9090 --attach $(pidof challenge)
Cannot attach to process 7196: No such process (3)
Exiting
```

But when connecting via shell and running, it worked:

```bash
$ docker exec -it challenge /bin/bash
root@e2cd6b6e2e2c:/# gdbserver :9090 --attach $(pidof challenge)
Attached; pid = 201
Listening on port 9090
```

If anybody finds a fix, please let me know!


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ir0nstone.gitbook.io/notes/misc/challenges-in-containers.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
