Skip to main content

A serious security flaw in runC can result in root privilege escalation in Docker and Kubernetes

Written by:

February 13, 2019

0 mins read

A security flaw discovered by Adam Iwaniuk and Borys Popławski and found in open source software runC was disclosed on February 11th, 2019 and described in CVE-2019-5736.

The vulnerability, affecting several container engines such as Docker and Kubernetes, is found in a key component of container engines and allows containers to break out of their isolated context and gain access to the host server which they run on, effectively accessing other containers as well and gaining root-level privileges on the host.

This security issue follows a critical vulnerability reported on December 3rd 2018 that found a kubernetes API component susceptible to attacks that allows execution of arbitrary commands in running containers.

William Bowling shared a video on Twitter that shows the proof-of-concept attack in action. The runC binary on the host server is altered from within a running container with a backdoored version:

Iwaniuk and Popławski released a blog post today detailing the runC attack describing their inspiration for the research that leads to the discovery of the vulnerability.

The Vulnerability

How is the vulnerability made possible? Christian Brauner wrote about the importance of understanding the semantics of privileged vs unprivileged containers:

What we really mean by a privileged container is a container where the semantics for id 0 are the same inside and outside of the container ceteris paribus. I say “ceteris paribus” because using LSMs, seccomp or any other security mechanism will not cause a change in the meaning of id 0 inside and outside the container. For example, a breakout caused by a bug in the runtime implementation will give you root access on the host.

An unprivileged container is a container in which the semantics for id 0 inside the container are different from id 0 outside the container. For example, a breakout caused by a bug in the runtime implementation will not give you root access on the host by default. This should only be possible if the kernel’s user namespace implementation has a bug.

The high severity of this vulnerable and its applicability is due to the fact that Docker containers run as privileged containers by default, as well as is attributed to the nature of how the runC command-line binary is used.

As Brauner explains, container technology implementations such as Docker executes the runC binary every time a container command is instructed, after which the runC process terminates. Because of that, a malicious container can alter therunC binary, and all further container instructions will effectively execute the modified runC binary.

This is a substantial difference from how LXC works, whereby a similar process doesn’t terminate after executing container instructions:

LXC cannot be attacked through a malicious image since the monitor process (a singleton per-container) never exits during the containers life cycle. Since the kernel does not allow modifications to running binaries it is not possible for the attacker to corrupt it. When the container is shut down or killed the attacking task will be killed before it can do any harm. Only when the last process running inside the container has exited will the monitor itself exit. This has the consequence, that if you run privileged OCI containers via our OCI template with LXC you are not vulnerable to malicious images. Only the vector through the attaching binary still applies.

This vulnerability further reminds us of the least privilege security principle and best practice that is often advised to make sure that the weakest link isn’t a source for deeper escalations and exploitations.

Security Concerns & Responsible Disclosure

The ultimate premise of containerization technology is the isolation between different apps and services, which undoubtedly causes alarms to go off when this isn’t the case.

Software supply chain attacks are not new in the container world and have made headlines in applications libraries as well. In an article posted on threatpost in 2018, it was found by the research of Kromtech Security Center that more than seventeen malicious containers were actively in-use in illegal cryptomining activity. The malicious images were hosted and later removed on Docker Hub, the official public registry for docker images.

In an update about the runC vulnerability, Aleksa Sarai, a runC maintainer and a senior software engineer at SUSE Linux, shared yesterday that another linux container technology called LXC is also vulnerable to the aforementioned CVE, although through a different attack vector.

It also mentioned that exploit code will be made public on February 18th to test and verify whether the security vulnerability has been patched successfully, urging users to apply patches in a responsible manner.

If you haven’t tried Snyk yet, consider trying our CLI to run tests locally or connect your source code repositories for automated scanning and remediation. If you're already using Snyk you should know we track this vulnerability in the database.

We’re happy to find that the Open Container Initiative (OCI) has added a SECURITY.md to their registry to provide researchers with responsible disclosure guidelines for security matters. We had recommended this in the past along with other secure source-code management guidelines that you can find in our GitHub Security Best Practices.

Takeaways

  • Avoid running untrusted and unverified container base images

  • Always apply least privilege principle and opt-in to run unprivileged containers

  • Scan for vulnerabilities in open source libraries to surface any unpatched servers you may have that are still vulnerable to this CVE