Docker image recon
Tags: redteam, docker, recon
Published: 2023-03-02 19:55:53

## Why?

You want to find weaknesses to exploit in an third party docker image.

## When?

You have access to a target docker image ahead of exploitation.

## How?

### Be wary of your local docker setup

Assuming you already have the docker image locally you want to be able to passively inspect it first. This is because default docker installations are not inherently secure. There's lots of good documentation on this from Docker themselves (see [Docker Security](https://docs.docker.com/engine/security/), especially [Rootless mode](https://docs.docker.com/engine/security/rootless/)). If in doubt it always pays to see what precautions a forensics or incident response team would take with an untrusted docker image (google is your friend here).

### Passively inspect layers

A good starting point is inspecting layers. Software engineers optimize their build processes around the semantic and performance benefits of docker layers, so the layer that changes the most will likely be the last, smallest, and the most juicy (i.e. configuration and code that's specific to the third party). Even better, is that likely the second to last layer will be a neat presentation of the code's third-party dependencies. You can inspect the layers with an open source tool, called [dive](https://github.com/wagoodman/dive). If you have a more command-line friendly way you do this, please comment below. I'd love to hear about it.

This is as straight-forward as:
```bash
dive IMAGE
```

Once you find something juicy you can selectively extract files from the container like so:
```bash
export ID=$(docker create IMAGE)
docker cp $ID:/PATH_WITHIN_IMAGE LOCAL_PATH
```

### Run within the image

If it's worth risking running the image locally there are things you can do to limit your exposure. The first is you don't actively want to undo the security benefits docker does provide you. Your image may be expecting to run with `--cap-add=SYS_ADMIN` but that doesn't mean you should! Here's an example of parameters that directly increase the risk of container escape: [container escapes](https://cloud.redhat.com/blog/docker-forensics-for-containers-how-to-conduct-investigations#container-escape).

#### Override the entrypoint

You'll want to override the default behavior of the image. A Dockerfile like this that overrides the `ENTRYPOINT` may get you going in the right direction (assuming that you are heading in the direction of adding your own `COPY` directives to launch your own code):

```
FROM <IMAGE>

EXPOSE 8080/tcp
ENTRYPOINT ["python3", "-m", "http.server"] 
CMD ["8080"]
```

#### Lock down egress to the internet

Before you run this, you may want to lock down egress in case the image calls home in some way. I didn't find a very satisfactory answer for this without going the route of opaque plugins to handle the task for you. Cribbing from the [docker network documentation](https://docs.docker.com/network/bridge/), we can at least create our own internal network bridge (i.e. with no egress gateway to the internet at large). This isn't ideal as it's still exposing your host:

```bash
docker network create --internal egress-restricted-net
```

From here we specify `--network egress-restricted-net` when running our image as a container. You can verify this behavior for yourself with:

```
FROM ubuntu:latest

RUN apt update && apt install -y iputils-ping iproute2
```

```bash
docker run --network egress-restricted-net --rm -it \
  $(docker build -q -f Dockerfile.egresstest .) /bin/bash -i
```

#### Remove networking entirely

Alternatively, if you can turn off networking entirely with `--network none` if you're willing to control the container entirely via stdin/stdout and `docker run -it`.