【漏洞复现】Docker runC 容器逃逸漏洞(CVE-2019-5736)

2024-02-09 18:40

本文主要是介绍【漏洞复现】Docker runC 容器逃逸漏洞(CVE-2019-5736),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 声明
  • 一、漏洞描述
  • 二、漏洞原理
  • 三、漏洞分析
  • 四、POC分析
  • 五、利用方式
  • 六、影响版本
  • 七、环境搭建
  • 八、漏洞复现
  • 九、修复建议


声明

本篇文章仅用于技术研究和漏洞复现,切勿将文中涉及攻击手法用于非授权下渗透攻击行为,操作有风险,出现任何后果与本作者无关,谨慎操作!!!

重点看Tips提示

一、漏洞描述

2019年2月11日,runC的维护团队报告了一个新发现的漏洞,SUSE Linux GmbH高级软件工程师Aleksa Sarai公布了影响Docker, containerd, Podman, CRI-O等默认运行时容器runc的严重漏洞CVE-2019-5736。漏洞会对IT运行环境带来威胁,漏洞利用会触发容器逃逸、影响整个容器主机的安全,最终导致运行在该主机上的其他容器被入侵。漏洞影响AWS, Google Cloud等主流云平台。日前,该容器逃逸漏洞的PoC利用代码已在GitHub上公布。这是CVE-2019-5736漏洞利用的Go语言实现。漏洞利用是通过覆写和执行主机系统runc二进制文件完成的。


二、漏洞原理

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


三、漏洞分析

  • runC
    runC是docker中最为核心的部分,容器的创建、运行、销毁等操作都是通过runC程序来完成的。我们来看一下runC文件,如下所示:
    在这里插入图片描述
    当我们运行docker run等命令的时候实际上在底层调用的是runC程序,所以整个流程大概如下:
    在这里插入图片描述
    其中虚线位置表示,当runC生成一个子进程后runC程序将会结束占用。
    当触发POC后,runC程序会被重写并执行:
    在这里插入图片描述

  • /proc/

    根据官方文档,/proc/文件夹类似于一个文件系统,其中存放着各个进程与本地文件之间的映射,其中:

    /proc/[PID]/exe: 一种特殊的软连接,是该进程自身对应的本地文件

    /proc/[PID]/fd/: 这个目录下存放了该进程打开的所有文件描述符

    /proc/self/: 不同的进程访问该目录时获得的信息是不同的,内容等价于/proc/本进程pid/

    /proc/[PID]/exe的特殊之处在于当权限通过的情况下打开这个文件,内核将会之间返回一个指向该文件的文件描述符,并非按照传统的打开方式做路径分析和文件查找,这就会导致绕过了mnt命名空间和chroot的限制。

    当执行docker exec命令的时候,runc启动并加入到容器的命名空间中去,其实这个时候,容器内的进程已经能够通过内部的/proc/观察到它,因此通过打开/proc/[runc-PID]/exe可以获取宿主机上的runc文件标识符,由此能够达到覆盖的能力。

四、POC分析

POC地址:https://github.com/Frichetten/CVE-2019-5736-PoC

  • #!

    在unix中,凡是被#!注释的,统统是加载器的路径,常见的有#!/bin/sh,表示将该注释后的代码交给/bin/sh处理,我们常见的处理python脚本一般在bash中输入python run.py,而如果在run.py中将注释换成#!/path/to/python,则在bash中执行run.py即可。

    在此poc中,作者将/bin/sh进行了覆盖,修改成了#!/proc/self/exe,意义在于当宿主机执行docker exec -it ID /bin/sh时,/bin/sh将会替换成执行调用者自己,也就是宿主机下的runc文件,此时将会执行runc文件。

  • 两个for循环

    在第一个for循环中,攻击者持续监测/proc/目录,当产生runc进程时,以可读的方式打开runc文件夹获取文件标识符。

    在第二个for循环中,攻击者持续监听等待runc程序结束占用后就能够用之前循环获得的文件标识符以可写的方式向runc文件内写入payload。

攻击链流程图
在这里插入图片描述

五、利用方式

宿主机利用攻击者提供的image来创建一个新的container,拥有container root权限,并且该container后续被docker exec attach。一句话描述,docker 18.09.2之前的runC存在漏洞,攻击者可以修改runC的二进制文件导致提权。

六、影响版本

  • Docker Version <=18.09.2
  • runC Version <=1.0-rc6

七、环境搭建

下载地址:前往下载
在这里插入图片描述
添加更新源到 /etc/apt/source.list文件中
Sudo apt-get update ##更新apt软件包索引
在这里插入图片描述
Sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common ##安装软件包,以允许apt通过HTTPS使用镜像仓库。
在这里插入图片描述
Curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add – ##添加Docker的官方GPG密钥
在这里插入图片描述
Sudo apt-key fingerprint 0EBFCD88 ## 验证密钥指纹是否为 9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88
在这里插入图片描述
Sudo add-apt-repository “deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable” ##设置稳定存储库,直接写入到/etc/apt/source.list文件中。

Sudo apt-get update ##再次更新apt软件包索引,可以看出新增docker镜像仓库。
在这里插入图片描述
到这里环境均已准备完毕!!!

八、漏洞复现

Tips:建议提前拍好快照,漏洞复现完成之后可能会造成docker无法使用

卸载已经安装的docker
sudo apt-get remove docker docker-engine docker-ce docker.io
列出docker可用版本
apt-cache madison docker-ce
在这里插入图片描述
以下列表中选择低于18.09.2版本进行安装
Sudo apt-get install docker-ce=18.06.1-ce-3-0-ubuntu
在这里插入图片描述
启动docker并查看docker和runc版本(均在漏洞影响范围内)
在这里插入图片描述
下载CVE-2019-5736漏洞POC
git clone https://github.com/Frichetten/CVE-2019-5736-PoC.git
在这里插入图片描述
修改payload内容
在这里插入图片描述
此时编译payload需要go环境,直接安装即可,生成可执行脚本main
在这里插入图片描述
编译完成后,我们运行一个漏洞环境(以CVE-2020-1957漏洞为例)

这里需要注意一下,安装完docker-ce之后,docker-compose是默认没有的,直接使用apt-get install docker-compose 或 pip install docker-compose命令可能会出现错误(尝试安装),解决方法就是下载一个docker-compose来进行安装,命令如下:

curl -L https://get.daocloud.io/docker/compose/releases/download/v2.6.1/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose //下载docker-compose 版本为2.6.1 并添加到 /usr/local/bin目录下
sudo chmod +x /usr/local/bin/docker-compose //赋予docker-compose执行权限
docker-compose -v //查看版本

##以上命令需要root权限执行!!!

启动环境
在这里插入图片描述
执行以下命令将生成的main脚本cp到docker容器中(这就是模拟攻击者获取了docker容器权限,在容器中上传payload进行docker逃逸)

docker cp /home/szg/CVE-2019-5736-PoC/main 3d5341ae0bf5:/home

执行如下命令,进入容器,查看脚本是否拷进容器并启动main脚本

docker exec -it 3d5341ae0bf5 /bin/sh (第一次需使用/bin/sh启动)

在这里插入图片描述
KALI启动监听
在这里插入图片描述
ubuntu启动一个新终端,执行如下命令再次进入容器,触发payload,成功反弹shell,此时权限为服务器权限,docker逃逸成功。
在这里插入图片描述
在这里插入图片描述

九、修复建议

更新容器至 18.09.2版本以上。

这篇关于【漏洞复现】Docker runC 容器逃逸漏洞(CVE-2019-5736)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/695006

相关文章

Centos7 firewall和docker冲突问题及解决过程

《Centos7firewall和docker冲突问题及解决过程》本文描述了一个在CentOS7上使用firewalld和Docker容器的问题,当firewalld启动或重启时,会从iptable... 目录系统环境问题描述问题排查解决办法总结本文只是我对问题的记录,只能用作参考,不能China编程说明问题,请

Python容器转换与共有函数举例详解

《Python容器转换与共有函数举例详解》Python容器是Python编程语言中非常基础且重要的概念,它们提供了数据的存储和组织方式,下面:本文主要介绍Python容器转换与共有函数的相关资料,... 目录python容器转换与共有函数详解一、容器类型概览二、容器类型转换1. 基本容器转换2. 高级转换示

详解C++ 存储二进制数据容器的几种方法

《详解C++存储二进制数据容器的几种方法》本文主要介绍了详解C++存储二进制数据容器,包括std::vector、std::array、std::string、std::bitset和std::ve... 目录1.std::vector<uint8_t>(最常用)特点:适用场景:示例:2.std::arra

python项目打包成docker容器镜像的两种方法实现

《python项目打包成docker容器镜像的两种方法实现》本文介绍两种将Python项目打包为Docker镜像的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要... 目录简单版:(一次成功,后续下载对应的软件依赖)第一步:肯定是构建dockerfile,如下:第二步

Python + Streamlit项目部署方案超详细教程(非Docker版)

《Python+Streamlit项目部署方案超详细教程(非Docker版)》Streamlit是一款强大的Python框架,专为机器学习及数据可视化打造,:本文主要介绍Python+St... 目录一、针对 Alibaba Cloud linux/Centos 系统的完整部署方案1. 服务器基础配置(阿里

Docker + Redis 部署集群的实现步骤

《Docker+Redis部署集群的实现步骤》本文详细介绍了在三台服务器上部署高可用Redis集群的完整流程,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋... 目录一、环境准备1. 服务器规划(3 台服务器)2. 防火墙配置(三台服务器均执行)3. 安装 docke

解决docker目录内存不足扩容处理方案

《解决docker目录内存不足扩容处理方案》文章介绍了Docker存储目录迁移方法:因系统盘空间不足,需将Docker数据迁移到更大磁盘(如/home/docker),通过修改daemon.json配... 目录1、查看服务器所有磁盘的使用情况2、查看docker镜像和容器存储目录的空间大小3、停止dock

docker 重命名镜像的实现方法

《docker重命名镜像的实现方法》在Docker中无法直接重命名镜像,但可通过添加新标签、删除旧镜像后重新拉取/构建,或在DockerCompose中修改配置文件实现名称变更,感兴趣的可以了解一下... 目录使用标签(Tagging)删除旧的php镜像并重新拉取或构建使用docker Compose在Do

Java JUC并发集合详解之线程安全容器完全攻略

《JavaJUC并发集合详解之线程安全容器完全攻略》Java通过java.util.concurrent(JUC)包提供了一整套线程安全的并发容器,它们不仅是简单的同步包装,更是基于精妙并发算法构建... 目录一、为什么需要JUC并发集合?二、核心并发集合分类与详解三、选型指南:如何选择合适的并发容器?在多

python语言中的常用容器(集合)示例详解

《python语言中的常用容器(集合)示例详解》Python集合是一种无序且不重复的数据容器,它可以存储任意类型的对象,包括数字、字符串、元组等,下面:本文主要介绍python语言中常用容器(集合... 目录1.核心内置容器1. 列表2. 元组3. 集合4. 冻结集合5. 字典2.collections模块