-
容器逃逸成真:从CTF解题到CVE-2019-5736漏洞挖掘分析
-
我们在执行功能类似于
docker exec
的命令时,底层实际上是容器运行时在操作。例如
runc
-
相应地,
runc exec
命令会被执行。它的最终效果是在容器内部执行用户指定的程序。进一步讲,就是在容器的各种命名空间内,受到各种限制(如
cgroups
)的情况下,启动一个进程。除此以外,这个操作与宿主机上执行一个程序并无二致。
-
这个过程中存在的风险在于:
/proc
:如果尝试打开
/proc/[PID]/exe
,在权限检查通过的情况下,内核将直接返回一个指向该文件的描述符(file descriptor),而非按照传统的打开方式去做路径解析和文件查找。这样一来,它实际上绕过了
mnt
命名空间及
chroot
对一个进程能够访问到的文件路径的限制。
-
在
runc exec
加入到容器的命名空间之后,容器内进程已经能够通过内部
/proc
观察到它,此时如果打开
/proc/[runc-PID]/exe
并写入一些内容,就能够实现将宿主机上的
runc
二进制程序覆盖掉!这样一来,下一次用户调用
runc
去执行命令时,实际执行的将是攻击者放置的指令。
在未升级的容器环境上,上述思路是可行的,但是攻击者想要在容器内实现宿主机上的代码执行(逃逸),还需要面对两个限制:
-
需要具有容器内部 root 权限;
-
Linux 不允许修改正在运行进程对应的本地二进制文件。
事实上,限制1经常不存在,很多容器服务开放给用户的仍然是root权限;而限制2是可以克服的
docker version <= 18.09.2
RunC version < 1.0-rc6
因为个人服务器docker版本过高,且EXP成熟,就不复现了。流程:
-
使用EXP:
https://github.com/Frichetten/CVE-2019-5736-PoC
-
编译POC:
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build main.go
-
开启监听后在容器中模拟用户进入docker镜像:
docker exec -it container_id bash
-
此时会发现runC文件被改变
-
CVE-2022-0847 dirtypipe linux本地提权全网第二详细漏洞分析
总结一些前置知识点
-
管道与重定向的简单区别在于,重定向将命令与文件连接起来,而管道符将命令与命令连接起来。
-
pipe_write
函数对
PIPE_BUF_FLAG_CAN_MERGE
的操作,本来无关痛痒,只是可以随意覆写管道。但是由于
page cache
的存在,令我们随意覆写管道转换成随意覆写文件,后面想到可以覆写
/etc/passwd
,最终达到提权的目的
-
在虚拟机(centos 7, 3.10.0-1160 kernal)中使用
psych
用户进行测试
-
使用 github 上 poc,运行后直接提权为 root