By Andson Tung
We have seen a lot of reports on how the Linux kernel can be compromised by the Dirty Cow (CVE-2016-5195) exploit. One technique that attackers use is to exploit this kernel bug to overwrite a so-called setuid program in the system. A setuid program allows the user to temporarily elevate the privilege in order to perform a certain task. By replacing the setuid program, the attacker can gain root access privilege when the program is executed, and be able to do whatever he/she wants.
You may think that the damage can be cleaned up if the compromised container is stopped and removed. However, that is not the case! In this demo of a Dirty Cow container exploit we will show that it has a long lasting effect on the container host, beyond the lifecycle of the compromised container. In fact, container immutability is broken.
‘passwd’ in a Linux system is one of these setuid programs. We will use it as an example in this demo.
Let’s do this step by step to see how the file changes.
Step 1 – Start a clean ubuntu:14.04 container
In the beginning, we have a clean ubuntu 14.04 running on a host and then start a clean ubuntu:14.04 container.
docker run -ti --rm -v /path/dirtycow:/tmp/case ubuntu:14.04 bash
Let’s record the hash of /usr/bin/passwd file in ubuntu:14.04 container as shown below.
Let’s also record the hash of following files in the docker unification file system located on host node after the ubuntu:14.04 container is started.
044e63fc4a13bd08fba6fb457f36c2f7 /var/lib/docker/aufs/diff/1a84e3b38dc86d47c70e584051863b5547e205773d7e64dede837de559573710/usr/bin/passwd 044e63fc4a13bd08fba6fb457f36c2f7 /var/lib/docker/aufs/mnt/e2d3c4694e8d2089bc47125a2a6a9b74675dc8020b5b10a561a0e2da113b6b34/usr/bin/passwd
Step 2 – Stop and remove an ubuntu:14.04 container
The directory below will be removed after the ubuntu:14.04 container is stopped and removed.
The previous diff directory still stays on host node for the ubuntu:14.04 image.
044e63fc4a13bd08fba6fb457f36c2f7 /var/lib/docker/aufs/diff/1a84e3b38dc86d47c70e584051863b5547e205773d7e64dede837de559573710/usr/bin/passwd (stay in the system)
Step 3 – Start a clean ubuntu:14.04 container again using the same docker command as Step 1
When a new clean ubuntu:14.04 container is started, the new mnt directory will be created on the host.
044e63fc4a13bd08fba6fb457f36c2f7 /var/lib/docker/aufs/diff/1a84e3b38dc86d47c70e584051863b5547e205773d7e64dede837de559573710/usr/bin/passwd (reuse) 044e63fc4a13bd08fba6fb457f36c2f7 /var/lib/docker/aufs/mnt/4f92c046bc94d42e28f772a150ec6d5ec663154e32a75d14f87bae87b564b8ed/usr/bin/passwd (new created)
Step 4 – Run passwd before the system is compromised
As seen in the following, the user is promoted to enter the password.
Step 5 – Execute a dirty cow exploit with non-root user in the ubuntu:14.04 container
After the Dirty Cow container exploit is executed in the ubuntu:14.04 container, the md5 hash for passwd on the host node is changed for both diff and mnt directories.
62152cbd766001ae450a2b48c7f72d99 /var/lib/docker/aufs/diff/1a84e3b38dc86d47c70e584051863b5547e205773d7e64dede837de559573710/usr/bin/passwd (version 1) 62152cbd766001ae450a2b48c7f72d99 /var/lib/docker/aufs/mnt/4f92c046bc94d42e28f772a150ec6d5ec663154e32a75d14f87bae87b564b8ed/usr/bin/passwd
And of course, it also changes on /usr/bin/passwd in the container as well.
Step 6 – Copy the original passwd back to /usr/bin/passwd in the ubuntu:14.04 container
A new version of passwd on the host will be created.
044e63fc4a13bd08fba6fb457f36c2f7 /var/lib/docker/aufs/diff/4f92c046bc94d42e28f772a150ec6d5ec663154e32a75d14f87bae87b564b8ed/usr/bin/passwd (version 2) 62152cbd766001ae450a2b48c7f72d99 /var/lib/docker/aufs/diff/1a84e3b38dc86d47c70e584051863b5547e205773d7e64dede837de559573710/usr/bin/passwd (version 1) 044e63fc4a13bd08fba6fb457f36c2f7 /var/lib/docker/aufs/mnt/4f92c046bc94d42e28f772a150ec6d5ec663154e32a75d14f87bae87b564b8ed/usr/bin/passwd (current state)
Step 7 – Stop and remove an ubuntu:14.04 container
The mnt directory and diff directory with version 2 will be removed after the ubuntu:14.04 container is stopped and removed. The previous diff directory still stays on the host node for the ubuntu:14.04 image.
As you can see, the original file in the ubuntu:14.04 image is compromised now.
Step 8 – Start an ubuntu:14.04 container again
Use the docker command again as in Step 1. When a new ubuntu:14.04 container is started, the new mnt directory will be created on the host.
62152cbd766001ae450a2b48c7f72d99 /var/lib/docker/aufs/diff/1a84e3b38dc86d47c70e584051863b5547e205773d7e64dede837de559573710/usr/bin/passwd (reuse) 62152cbd766001ae450a2b48c7f72d99 /var/lib/docker/aufs/mnt/e595ebc3fe0b08abf46caf1a0a0bdfc08b2a3e822e91a9699d69c87513fcdf7d/usr/bin/passwd (new created)
Now you can see that the /usr/bin/passwd in the container is compromised already.
Step 9 – Run passwd with a non-root user after the system is compromised
You can see below that the password dialog is gone. Instead, the process gains root access permission now.
No matter how many times you keep starting, stopping and removing the container, the system will remain compromised with the Dirty Cow container exploit until the entire ubuntu:14.04 image is removed.
Detection and Prevention
NeuVector is a comprehensive run-time security solution for containers and their hosts. A hacking attack is often compromised of several steps in the chain, and NeuVector is able to detect the compromise at several points.
First, NeuVector scans hosts and containers for vulnerabilities, and would identify that the Dirty Cow vulnerability existed. Second NeuVector can detect when a compromised host or container process suffers from a privilege escalation to root (Step 5). Third, when a compromised container process attempts to break out and connect to another container, NeuVector violation detection would determine that this connection was suspicious unauthorized traffic. These connection could generate alerts and blocked if desired.
About the Author
Andson Tung is on the Technical Staff at NeuVector.