Welcome to our Pentest Files blog series.
Each blog post will present an interesting or dangerous finding one of our testers has identified in an actual recent pen-test, so you can see the kinds of cool things our pen-testers get up to, and also to help you take steps to prevent similar vulnerabilities in your own assets.
These findings are taken from real reports, anonymised, and published with kind permission from our clients.
Tester: Cale Anderson
Vertical: Artificial Intelligence
Impact: Compromise of AWS instance and all user data on the instance
Cale was able to bypass the security boundaries of a shared environment he was testing. This allowed him to break out of a restricted container environment and read and modify the files of and authenticate as other users of the application.
The target of the engagement was an artificial intelligence platform that provides users with their own hosted data analytics environment. One of the application’s features was to provide the user with their own bash terminal so they could run various commands within their own sandbox to help them effectively analyse their own data.
Under the hood, each terminal was implemented through the use of a Docker container. In theory this should have provided each user of the platform access to their own dedicated and isolated computing instance with access to only their own files and directories. This would have allowed multiple users to share the same physical machine securely, without risk of data being exposed unintentionally between users.
However, Cale found that the host systems Docker socket was mounted within the container.
The Docker socket is a special endpoint located on the filesystem at /var/run/docker.sock. This socket is how user-facing Docker tools such as the docker command line client interact with the Docker daemon, the core component of Docker which handles starting, stopping and managing the various containers on a system.
It is important that access to this socket be heavily restricted, as were a malicious user be able to access and interact with this socket, they could potentially issue various docker commands such as starting new containers or executing new commands within currently running containers.
Docker also supports a feature called volumes. This allows exposing certain directories on the host filesystem to a docker container. For example if an application needs to read a certain configuration file, this file or the directory it resides in might be attached to the container as a volume.
Given these two pieces of information, Cale realised that it would be possible to bypass the ordinary restrictions of the system by creating a container with the entire host filesystem mounted as a volume.
He proceeded to download the Docker command line binary within his container and then used this access to the docker socket to launch a new container with the entire host operating system filesystem mounted. From there he was able to traverse the host filesystem, giving him access to all data on the root filesystem of the host computer.
docker run -it -v /:/host/ ubuntu:18.04 chroot /host/ bash
Cale could now access the files and information of all users of the application that shared the same host machine as him.
While traversing the filesystem to discover the potential impact this issue might have, he noticed that he could access the session tokens for logged in users, allowing him to authenticate to the platform as other users. This included access to what appeared to be an administrative user account.
Cale promptly notified the client who fully remediated the issue, as well as implementing further security restrictions to protect against both this particular attack vector and similar attacks.
This is actually quite a common security misconfiguration when utilising Docker within applications, and luckily there’s a fix.
To protect against this kind of attack simply do not mount the host system Docker socket inside containers as this can introduce a significant risk when giving untrusted users access to the container, such as on shared computing environments.
It is also worthwhile to note that the use of containerisation should never be relied on as a lone security boundary. Like all technologies, it is possible to mis-configure Docker in a manner that may allow an attacker to completely bypass or escape the limitations of their containerised environment. For example one weakness of a containerised system is that containers share the same operating system kernel. Were an attacker able to exploit a vulnerability in the kernel, it might be possible for them to escape the container environment or access other running containers.
Therefore when utilising containerisation there are other remedial steps worth considering that could also help to further protect against this kind of attack. Some suggestions are provided below that would have helped limit the damage in this situation.
Running container processes as non-root
Ensuring the processes within your container run as non-root users can again help in mitigating the potential damage were an attacker to escape a container.
This feature assigns the users within the container distinct user IDs from those on the host machine. What this means is that a user account (e.g. the user ubuntu) within a container is not the same as a user on the host machine, regardless if they have the same name. This still applies if the container runs as root.
This can be particularly useful if a user were somehow to escape the container environment, such as accessing the file system outside of the container. In this situation, as their user ID would differ to those on the host machine, existing host filesystem access controls would then likely limit them in which files they could access.
For example, were a root user within a container to escape with user namespacing enabled, it is likely that they would not be able to access sensitive root-only files on the host filesystem like /etc/shadow as their user ID would not be equivalent to root on the host.
Apparmor and Seccomp are kernel-level security tools which allow limiting what actions certain processes can perform. Docker supports integration with these tools in order to prevent containers from making certain dangerous system calls.
Please note that implementing restrictions via these tools typically requires a bit of work to get working and may break things without some tinkering.
https://github.com/docker/labs/tree/master/security/userns https://docs.docker.com/engine/security/protect-access/ https://docs.docker.com/engine/security/userns-remap/ https://book.hacktricks.xyz/linux-unix/privilege-escalation/docker-breakout/docker-breakout-privilege-escalation#mounted-docker-socket