Docker
Use containers to run applications in a reproducible and isolated environment
Last updated
Use containers to run applications in a reproducible and isolated environment
Last updated
Docker allows you to build and run containers that hold an application in an isolated environment, similar to a Virtual Machine. This is done with Linux namespaces, however, making it much more lightweight than VMs.
It should normally be impossible to escape to the host system from inside a container. While it may still be possible to reach into the internal network over regular network protocols, access to the host's filesystem and processes is restricted. There are, however, some misconfigurations that be exploited by attackers to get more access than expected, often targeting the host from inside the container.
Below are some more tricks that I've personally found useful.
In some cases, you may be able to access the docker.sock
socket or TCP ports 2375/2376 for the Docker API. This API does all the interaction with the host system. Through this, it is possible to start new containers with extra privileges and access through mounts.
If you find yourself as a low-privilege user on a machine with Docker installed, and you have the docker
group, you should be able to successfully run the following command. Check out Privilege Escalation to abuse this to get root
access.
The -H
option with the unix://
protocol allows you to connect to a mounted docker.sock
socket somewhere on the filesystem if it is available:
For remote Docker APIs, a host can be specified with -H
on your local docker
installation to run commands on another instance. Below is an example of an unencrypted connection to port 2375:
When TLS is required, just use port 2376 and --tls
:
As recommended, TLS servers may require a client certificate for authentication. If you have this, specify it with the --tlscert
and --tlskey
options:
Interactive from docker run
by mounting host:
Reverse shell using docker-compose
by mounting host:
Using the docker:dind
image, it is possible to run a nested Docker engine inside another Docker container. This allows applications that require starting docker containers to communicate with an isolated environment without requiring to talk with the host system directly.
A simple working setup of this can be seen below:
Making this work requires the --privileged
flag to be set for the dind
container, giving it more access to the host system than regular containers. We will abuse this, but first, we can use the techniques from Privilege Escalation to start a new container on the remote Docker API (DinD).
Note that we also provide --privileged
here to maintain the access:
When inside we should have access as if we are on the dind
container itself. Because it is privileged, we can mount disks like /dev/sda
to read and write to them. These disks come from the real host:
The above may generate some "Invalid argument" messages, but all possible disks should now be mounted in /mnt
. Look for the host system here and do anything with the newfound access to its files.
If you gain access to a container via some vulnerability, it might be hardened with some protections on the filesystem. A common one is "read-only file system" when writing anywhere.
Regular directories under /
will not be writable, but there is often one exception: /dev/shm
. This special directory is stored in RAM instead of disk and is thus always writable. While it sounds perfect, it is commonly protected with a noexec
flag disallowing any ELF binaries from executing inside this directory. Running ./pspy
, for example, won't work.
It is still possible to execute any bash code, however, and some clever people have abused this. By writing bash code that injects some ELF binary's logic into another process, it is possible to run a binary stored in /dev/shm
without actually executing it. The repository below implements this:
After uploading this shell script to the target together with your binary, run it with any arguments:
In an ever more restricted scenario, your container will not even have common shells like sh
or ash
. It might only have the programming language required to run the application installed. While a regular reverse shell is impossible here, it is often possible to use the programming language to load shellcode similarly to DDexec. By running binaries such as busybox
, many commands can be brought back to enumerate the system in this restricted environment.
Check out the following video for more information about exploiting this:
"DEF CON 31 - Exploring Linux Memory Manipulation for Stealth and Evasion - Polop, Gutierrez"