Site icon UnixArena

How to get root access on the docker host filesystem?

Docker Privilege escalation - mount filesystem as root

Docker Privilege escalation - mount filesystem as root

How to gain root access to the host filesystem in a Docker environment when you don’t have root or “sudo” privileges on the host? Since many Kubernetes systems still run on Docker and a transition to Podman is ongoing, this article provides a solution to allow access to the host filesystem with root privileges from within a Docker container for making changes or reading files.

In the second part, we will see how to disable this option to lock down the environment from unauthorized access. It is just as dangerous to run processes as root inside a container as it is to run as root on the host, despite the “isolation” of the container. Misconfiguration or exploits can lead to abuse and compromise the supposed isolation.

Access container host filesystem with root privileges:

1. Login to the docker container host. Just assume that you need to access the files which are inside the following directory which is owned by root.

uxpro-$ $ ls -ld /etc
drwxr-xr-x 109 root root 4096 Feb  6 17:05 /etc

2. Let’s try to access the directory. Since this directory permission is set to 700, only the root user can access it.

uxpro-$ cd /etc
uxpro-$ touch test_file
touch: cannot touch 'test_file': Permission denied 

3. Start the docker container by mounting “/etc” host filesystem on /mnt in the container.

uxpro-$ docker run -it --rm -u root -v /etc:/mnt nginx:latest bash
Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx
01b5b2efb836: Pull complete
db354f722736: Pull complete
abb02e674be5: Pull complete
214be53c3027: Pull complete
a69afcef752d: Pull complete
625184acb94e: Pull complete
Digest: sha256:c54fb26749e49dc2df77c6155e8b5f0f78b781b7f0eadd96ecfabdcdfa5b1ec4
Status: Downloaded newer image for nginx:latest
root@3f7c7cee564d:/# cd /mnt
root@3f7c7cee564d:/mnt# ls -lrt
total 916
-rw-r--r-- 1 root root     887 Apr  1  2013 rpc
-rw-r--r-- 1 root root    2932 Apr  1  2013 protocols
-rw-r--r-- 1 root root     280 Jun 20  2014 fuse.conf
-rw-r--r-- 1 root root    3663 Jun 20  2016 screenrc
-rw-r--r-- 1 root root     604 Sep 15  2018 deluser.conf

4. Create a “test_file” under “/mnt” – which is actually host’s /etc/ filesystem.

root@feae8285eb31:/# cd /mnt
root@feae8285eb31:/mnt# touch test_file

root@feae8285eb31:/mnt# ls -lrt test_file
-rw-r--r-- 1 root root 0 Feb  6 17:16 test_file
root@feae8285eb31:/mnt# exit
exit
uxpro $ ls -lrt /etc/test_file
-rw-r--r-- 1 root root 0 Feb  6 17:16 /etc/test_file
uxpro $

As long as you only practice this hack in a controlled environment such as a lab or local system, everything will be fine. However, it is not advisable to have systems in production with such a significant security vulnerability. In the next section of the article, we will provide steps to mitigate this security risk by disabling it.

How to prevent user from privilege-escalation on docker host ?

On the docker host, identify user and group which can be used by the docker containers. If you do not have one , create it like below.

1. Create a new user called “dockerusr”

uxpro $ sudo adduser --system --no-create-home --disabled-password --d                                               isabled-login --gecos '' dockerusr
Adding system user `dockerusr' (UID 115) ...
Adding new user `dockerusr' (UID 115) with group `nogroup' ...
Not creating home directory `/home/dockerusr'.

2. Create a new group called “dockergrp”

uxpro $ sudo addgroup --system dockergrp
Adding group `dockergrp' (GID 124) ...
Done.

3. Add the newly created user to the group.

uxpro $ sudo adduser dockerusr dockergrp
Adding user `dockerusr' to group `dockergrp' ...
Adding user dockerusr to group dockergrp
Done.

Add the user to docker group.

uxpro $ sudo adduser dockerusr docker
Adding user `dockerusr' to group `docker' ...
Adding user dockerusr to group docker
Done.

4. Update the “subuid” file with newly created user.

uxpro $  echo "dockerusr:200000:65536" >> /etc/subuid
uxpro $ cat /etc/subuid
vagrant:100000:65536
lingesh:165536:65536
dockerusr:200000:65536

5. Updae the “subgid” file with newly created group.

uxpro $ echo "dockergrp:200000:65536" >> /etc/subgid
uxpro $ cat /etc/subgid
vagrant:100000:65536
lingesh:165536:65536
dockergrp:200000:65536

6. If “/etc/docker” directory is not exists, create a new directory and then create a file called “daemon.json”.

uxpro $ mkdir -p /etc/docker
uxpro $ vi /etc/docker/daemon.json
uxpro $ cat /etc/docker/daemon.json
{
  "userns-remap": "dockerusr:dockergrp"
}
uxpro $

7. Restart the docker daemon.

uxpro $ systemctl restart docker
uxpro $ systemctl status docker
● docker.service - Docker Application Container Engine
     Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
     Active: active (running) since Tue 2023-02-07 15:51:19 UTC; 1min 0s ago
TriggeredBy: ● docker.socket
       Docs: https://docs.docker.com
   Main PID: 77936 (dockerd)
      Tasks: 7
     Memory: 27.8M
     CGroup: /system.slice/docker.service
             └─77936 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

8. Let’s try to start the container by mounting host’s “/etc” on container’s “/mnt”.

$ docker run -it --rm -u root -v /etc:/mnt nginx:latest bash
Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx
01b5b2efb836: Pull complete
db354f722736: Pull complete
abb02e674be5: Pull complete
214be53c3027: Pull complete
a69afcef752d: Pull complete
625184acb94e: Pull complete
Digest: sha256:c54fb26749e49dc2df77c6155e8b5f0f78b781b7f0eadd96ecfabdcdfa5b1ec4
Status: Downloaded newer image for nginx:latest
root@728b0b25ec5a:/# 

9. Let’s verify the “/mnt” content. (host’s “/etc/” filesystem).

root@728b0b25ec5a:/# cd /mnt
root@728b0b25ec5a:/mnt# ls -lrt
total 920
-rw-r--r-- 1 nobody nogroup   887 Apr  1  2013 rpc
-rw-r--r-- 1 nobody nogroup  2932 Apr  1  2013 protocols
-rw-r--r-- 1 nobody nogroup   280 Jun 20  2014 fuse.conf
-rw-r--r-- 1 nobody nogroup  3663 Jun 20  2016 screenrc
-rw-r--r-- 1 nobody nogroup   604 Sep 15  2018 deluser.conf
-rw-r----- 1 nobody nogroup   144 Nov 12  2018 at.deny
-rw-r--r-- 1 nobody nogroup  1260 Dec 14  2018 ucf.conf
-rw-r--r-- 1 nobody nogroup   533 Jan 21  2019 logrotate.conf
-rw-r--r-- 1 nobody nogroup 14867 Feb  1  2019 ltrace.conf

Let’s try to create a empty on “/mnt” now.

root@728b0b25ec5a:/mnt#  touch 3
touch: cannot touch '3': Permission denied

We have successfully blocked the root access on the mounts. “userns-remap” is a feature in Docker that allows for user namespace remapping. It provides a way to map the host’s user ID (UID) and group ID (GID) to a different range of IDs inside a container, effectively separating the host’s user and group IDs from the container’s IDs. This helps in situations where the UID and GID inside a container should not match those on the host system, such as in cases where the container runs as a privileged user or where the host and container IDs conflict.

Hope this article is informative to you.

Exit mobile version