Don’t let the funny name fool you – the Dirty Cow (dirty copy-on-write, designation CVE-2016-5195) exploit that can compromise the Linux kernel can also make a mess of your system, even when introduced through a compromised container that is subsequently stopped and removed.
Many attackers will make use of this exploit to overwrite a setuid program – such as “passwd” in Linux systems – that can temporarily increase a user’s access privileges so that they can complete some task that requires it. Attackers who replace this program can give themselves root access privileges when it runs, and then do any damage to the system that they want.
Unfortunately, this Dirty Cow attack can’t be washed clean by simply eliminating the container. Rather, the container host suffers from ongoing effects, and container immutability is broken.
Here’s a step-by-step demonstration of how this attack can corrupt the passwd file and keep it corrupt beyond the life of the container:
1) Begin With a Clean Ubuntu:14.04 Container
First, we’ll start fresh with a clean version of Ubuntu 14.04 running on a host, and start a clean Ubuntu:14.04 container.
docker run -ti --rm -v /path/dirtycow:/tmp/case ubuntu:14.04 bash
So that we can see changes later, we’ll record the hash of the /usr/bin/passwd file in the Ubuntu:14.04 container:
We’ll also record the hash of a couple of files in the Docker unification file system, which are located on the host node once the Ubuntu:14.04 container is started.
044e63fc4a13bd08fba6fb457f36c2f7 /var/lib/docker/aufs/diff/1a84e3b38dc86d47c70e584051863b5547e205773d7e64dede837de559573710/usr/bin/passwd 044e63fc4a13bd08fba6fb457f36c2f7
2) Stop and Remove the Ubuntu:14.04 Container
Stopping and removing the Ubuntu:14.04 container will also remove the mnt directory:
However, the existing diff directory will remain on host node for the Ubuntu:14.04 image.
044e63fc4a13bd08fba6fb457f36c2f7 /var/lib/docker/aufs/diff/1a84e3b38dc86d47c70e584051863b5547e205773d7e64dede837de559573710/usr/bin/passwd (stay in the system)
3) Start a New, Clean Ubuntu:14.04 container (Just Like in Step 1)
Starting a new, clean Ubuntu:14.04 container will create a new mnt directory 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)
4) Run passwd (Prior to the System Being Compromised)
Here you can see the passwd program’s normal behavior, securely prompting the user to provide their password.
5) Have a Non-Root User in the Ubuntu:14.04 Container Execute a Dirty Cow Exploit
Here’s where the fun begins. Pretend you’re a hacker and execute the Dirty Cow container exploit in the Ubuntu:14.04 container.
Once this has happened, we can see that the md5 hash for the passwd program on the host node has indeed been changed, in both the 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
The hash changes on /usr/bin/passwd in the container too.
6) Copy the Original passwd File Back to /usr/bin/passwd in the Uubuntu:14.04 Container
Doing this will create a new version of passwd on the host.
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)
7) Stop and Remove the Compromised Ubuntu:14.04 Container
Now taking off your hacker hat and acting as the administrator who has noticed a problem, you stop and remove the container, which will cause the mnt and diff directories with the second version of the passwd file to be removed as well. However, the previous diff directory remains on the host node for the Ubuntu:14.04 image.
The Dirty Cow exploit has now rubbed up against the original file in the Ubuntu:14.04 image, and the dirt is there to stay. The system is compromised.
8) Start a New Ubuntu:14.04 Container
Again, just as in Step 1, we create a new container. This will create a new mnt directory 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)
With the system corrupted, the /usr/bin/passwd within the container is compromised from the beginning.
9) Run passwd as a Non-Root User on the Compromised System
Acting as a hacker once more, run passwd. The dialog has changed: it no longer asks you for a password as a security measure but takes you straight to having permission for root access.
Try new containers as much as you wish: they’ll all be corrupt. The Dirty Cow exploit has fully compromised the system, the only option is to remove the entire Ubuntu:14.04 image.
Detecting and Preventing the Dirty Cow Container Exploit
Because this exploit and other similar hacking attacks require several stages of activity before their damage is done, run-time security that oversees containers and their hosts can often detect compromises along the way and put a stop to hacking attempts ahead of their completion. With exploits like the Dirty Cow vulnerability able to become so harmful once fully realized, it’s important that security measures are able to identify any such vulnerabilities, detect compromised activity, and recognize suspicious traffic to address and negate dangers through either alerts or automatic action.
Andson Tung is a DevOps QA Engineer at NeuVector, a Docker container network security solution that uses behavioral learning to secure containers during run-time.