Docker exploitation and Docker vulnerabilities
Last updated
Last updated
This page is in web pentest but Docker can be found in other type of pentests such as network pentest for instance. It can also be used for privesc on linux among other things. This documentation has been made using the room The Docker Rodeo on TryHackMe and of course notes from my practice
We can launch an nmap scan to check on which port a Docker registry is running nmap -sV -p- 10.10.137.64
The Docker Registry is a JSON endpoint, so we cannot just simply interact with it like we would a normal website - we will have to query it. Whilst this can be done via the terminal or browser, dedicated tools such as Postman or Insomnia are much better suited for the job. We can also use Burp and forge requests with the repeater for example. In the room Cnmatic uses Postman but I am going to use Burp.
We can send a GET
request to http://target:5000/v2/_catalog
to list all the repositories.
To query all published tags of a repository we can send a GET
request to http://target:5000/v2/repository/name/tags/list
To get a manifest file to the repository we found we can send a GET
request to http://target:5000/v2/repository/name/manifests/tag
Abusing the Registry on port 7000
List the repos
List the published tags
Grab data
We can pull the image locally and reverse engineer it with Dive.
Install on Ubuntu
We can pull the image docker pull target:5000/dive/example
docker images
to get the image ID
dive image-id
Navigate the data within the current window using the "Up" and "Down" Arrow-keys.
You can swap between the Windows using the "Tab" key.
Without proper authentication, we can upload our own image to the target's registry. That way, the next time the owner runs a docker pull
or docker run
command, their host will download and execute our malicious image as it will be a new version for Docker.
Dockerfile that will connect to our machine with netcat
We compile this into an image with docker build . Once compiled and added to the vulnerable registry, we set up a listener on our attacker machine and wait for the new image to be executed by the target.
rlwrap nc -lvnp 8080
This way we will get access as root to the container. The next step will be to try to escape the container or privesc one way or another.
Sometimes Docker can be set up to be used remotely, this way when enumerating a target with nmap we might find docker running on a target.
curl http://TARGET-IP:2375/version
Check if we can interact with the Docker Daemon. If it works we get a result looking like this.
docker -H tcp://TARGET-IP:2375 ps
list the currently running container the H flag allows us to specify the IP of our remote target.
Once we have a foothold we can try to escape Docker
Look for exposed docker socket
docker run -v /:/mnt --rm -it alpine chroot /mnt sh
mount the host directory to a new container and then connect to that to reveal all the data on the host OS
Note: If you do not receive any output after 30 seconds you will need to cancel the command by "Ctrl + C" and attempt to run it again.
We can confirm that the container we're connected to in namespaces of the host by using ps aux
.
To escape the Docker, we can use the following exploit: nsenter --target 1 --mount sh
which does the following:
We use the --target
switch with the value of "1" to execute our shell command that we later provide to execute in the namespace of the special system process ID, to get ultimate root!
Specifying --mount
this is where we provide the mount namespace of the process that we are targeting. "If no file is specified, enter the mount namespace of the target process." (Man.org., 2013)
As we are targeting the "/sbin/init" process #1 (although it's actually a symbolic link to "lib/systemd/systemd" for backwards-compatibility), we are using the namespace and permissions of the systemd daemon for our new process (the shell)
Here's where our process that will be executed into this privileged namespace: sh
or a shell. This will execute in the same namespace (and therefore privileges of) the kernel.
Docker containers can run in two modes:
User mode
Privileged mode
If a container is running with privileged access to the operating system, we can effectively execute commands as root.
We can use a system package such as "libcap2-bin"'s capsh
to list the capabilities our container has: capsh --print
.
capsh --print | grep sys_admin
Summary of the exploit:
We need to create a group to use the Linux kernel to write and execute our exploit. The kernel uses "cgroups" to manage processes on the operating system since we have capabilities to manage "cgroups" as root on the host, we'll mount this to "/tmp/cgrp" on the container.
For our exploit to execute, we'll need to tell Kernel to run our code. By adding "1" to "/tmp/cgrp/x/notify_on_release", we're telling the kernel to execute something once the "cgroup" finishes. (Paul Menage., 2004)
We find out where the containers files are stored on the host and store it as a variable
Where we then echo the location of the containers files into our "/exploit" and then ultimately to the "release_agent" which is what will be executed by the "cgroup" once it is released.
Let's turn our exploit into a shell on the host
Execute a command to echo the host flag into a file named "flag.txt" in the container, once "/exploit" is executed
Make our exploit executable!
We create a process and store that into "/tmp/cgrp/x/cgroup.procs"
Run ps aux
(if there are not many process it could be a container)
Look for dockerenv cd / && ls -lah
Look for cgroups cd /proc/1
and cat cgroup
(should contain the word docker)
Not to edit the targe in burp repeater you need to click here and edit the window according to your needs