One of the myths of the DevOps universe is that Docker and its environment guarantee a higher level of security than a virtualised architecture: its separation of applications provides better security. But is this really the case? Unfortunately, it is not. In this article, we will demonstrate that it is relatively simple to effectively jeopardise a container, attack a host or Docker’s own assets.
Virtualisation Vs. Containerisation
These two components are diametrically opposed, which is why there is no real opposition between them. They have their own strengths, their own weaknesses, but it is above all their usage that is totally different. So why address this issue?
Quite simply because the subject is recurrent during exchanges with certain clients. It was therefore appropriate to provide a comparison between these two methods. It is important to know that in a classic Docker environment, and with a containerisation system, the separation of resources between host and container is a fine line. Virtualisation, on the other hand, requires additional overlay to ensure that resources are sealed between the hypervisor and Guest systems. This results in a lack of flexibility and scalability (the ability of a product to maintain its functionality in the event of an increase in demand), as opposed to a containerisation system.
But this thinness between the different layers also brings its share of safety issues. To identify them, here is a summary diagram of the possible attack vectors on a containerised system:
This illustration allows us to see that the security appears to be quite permeable. However, other assets such as Registry services, orchestration or container management such as Portainer are not included in this graph.
We are now going to see what risks and attacks you may be exposed to if you use a poorly configured or insufficiently secure containerised environment.
Remote compromise of a container or host
It is possible to easily compromise a host server when port 2375 (or 2376 via TLS (Transport Layer Security)) of the daemon Docker is exposed without authentication. This is a critical vulnerability because this process requires high-level access rights when they are not root types.
Let’s take a look at an example. Let’s do a search on port 2375 on Shodan, presenting a JSON HTTP header:
We see that 4’700 results are available via the attached filter. Let’s imagine for a moment that 10% of these results are effectively exploitable: that’s a nice potential attack vector for a malicious party.
This situation is worrisome, since the daemon Docker exposes an API that allows for a large number of operations to be performed, such as listing containers, launching one, interacting with another, modifying its execution, and so on.
This is why one of the most likely scenarios would be for an attacker to create a container on the target. The hacker would execute a specific command to obtain a reverse shell and then proceed to circumvent the container via the privileged mode previously activated (a technique that we will discuss later in the article). This method allows the attacker to take control of the host in a simple, fast and efficient way.
Be aware that it is also possible to escape directly from a container using this technique.
To endanger a container, there are as many possibilities as there are different technologies. The latter uses services and libraries that may be vulnerable. To compromise a container, it is therefore necessary to attack these third-party services (web, SQL, cache, proxy…).
All the more so since in a micro-service architecture that is commonly based on Docker (or a containerisation system), bounces are quite possible between containers. Especially when inadequate security configurations exist (presence of a password on a container allowing it to be accessed).
All the more so since in a micro-service architecture that is commonly based on Docker, bouncing between containers is quite possible. Especially when inadequate security configurations are executed (presence of a password on a container allowing it to connect to another…).
Container Escape in a Docker System
It is very difficult to escape from a container in a fully updated Docker system. However, experience has shown us that it is not uncommon to find obsolete elements.
So let’s assume that a kernel, or operating system kernel, is not up to date. As a reminder, the containers and the host share the kernel. If this particular kernel presents a vulnerability, such as “privilege escalation” for example, then an attacker can take advantage of this in a compromised container. This will allow them to obtain the highest rights. Not on the container, but directly on the host.
Excessive Privilege Kills Privilege
As an auditor you may be faced with other problems. Especially those related to the configuration, for example with rights granted to containers and their resources that are too high-level. When a container launches in privileged mode, an attacker can then access certain host resources.
Thus, he/she may have the ability to modify the files on the disk. This gives them access to the machine and the ability to compromise its functionality.
Are you capable?
In the same manner, the container may have certain capabilities for various reasons (debug or maintenance). These can be used and diverted to escape from the container. This is why we have identified the greatest risks below:
- SYS_ADMIN: similar to the privileged mode
- SYS_PTRACE : allows processes to be debugged
- SYS_MODULE: inserting modules in the kernel
- DAC_READ_SEARCH: allows reading of shared resources
- DAC_OVERRIDE: allows writing of shared resources
The SYS_ADMIN capability allows, in privileged mode, to create resources such as host partitions. This means that an attacker can modify critical files to gain access to the host and jeopardise data security.
If the SYS_PTRACE capability is active and the PID namespace is shared between several containers (or directly with the host), then an attacker can take advantage of it to escape. The attaker can inject himself/herself into one of the processes, redirect to the asset with which it is shared and thus execute commands with the same level of privileges as the process.
This capability allows the container, if necessary, to integrate a module into the kernel. It is then possible to create a malicious module that will be inserted into it. As a reminder, the kernel is shared between the host and the containers, i.e. by inserting this malicious module, it will therefore be executed by the host carrying the kernel. The attacker can therefore obtain priority access to it.
The DAC_READ_SEARCH capability maps certain files from the host to the Container. Using a known exploitation called Shocker, it is then possible to map and read other files that are normally inaccessible from the container. These are host files such as /etc/shadow, which contain system passwords. This capability does not directly allow for escape, but it can be very helpful.
DAC _OVERRIDE Capablility
DAC _OVERRIDE capability is necessary for the operation of a container, even if by itself it is of little use to a malicious actor. However, combined with the above-mentioned capability (DAC_READ_SEARCH), it allows total escape from the container. An attacker will therefore be able to use the same process to map host files which are normally inaccessible. The worst thing is that they will then be able to modify them. The attacker can change the user password on the host directly in the /etc/shadow file and thus access the machine via SSH.
To reassure you after all these disaster scenarios, it is necessary to know that most of the capacities require root access on the container. This adds an extra step for the attacker. But it can be worth the effort…
Registries as a Vector of Contamination
A system that stores images based on containers is called the “Registry”. Registries therefore allow DevOps to make ready-made images available to systems, the goal being not to have to recreate them each time.
However, Public Registries such as the one proposed by Docker do exist.
Normally, Registries internalise for private infrastructures and in some cases, protection is not sufficient in the face of the risks that may exist.
Indeed, reaching a Registry would allow an attacker to extract the images it contains. The latter could contain sensitive information, such as passwords, authentication keys or certificates. In the same way, it is possible to imagine an attacker pushing or rewriting an image containing a backdoor to the information system.
Regardless of the Registry system, they function more or less in the same way and therefore rely on the same API. This makes it relatively simple for an attacker from the moment they are able to communicate with the famous Registry.
And how can you defend yourself?
It is important to understand that these vulnerabilities target configuration issues leading to security problems. Be aware that it is possible to carry out an audit in order to verify if there are configuration errors or an oversight.
There are tools to analyse the security of images before deployment, or to analyse the behaviour of containers in runtime. These are relatively effective and simple to implement.
For Docker image security analysis, Clair and Trivy are the most commonly used. With respect to real-time execution, Falco provides the ability to give alerts on suspicious activities. As these take place both on the host and on the containers, it is then ideal to couple it with a SIEM-type tool.
AppArmor, SELinux or Seccomp can reduce the risk of compromise by limiting the execution of certain actions through the creation of security profiles.
For more details on these protection systems, a follow-up article should be available in the coming weeks.
Docker and Security: Conclusion
This article is not exhaustive. There are other compromises and evasion techniques such as the exploitation of vulnerabilities inherent in Docker. It is a myth that Docker is more secure than other architectures. They are all pretty much on the same level.
Unfortunately, we find that vulnerabilities are most often introduced due to an error in configuration, or lack of updates. So don’t forget that with Docker, a port-opening or poorly-enabled capability can compromise the entire architecture.