AzureScape:ACI 容器中的 K8s 跨賬戶集群接管研究

來源: ZAKER
作者:ZAKER
時間:2021-09-24
17453
Azure 容器實例 ( ACI ) 是 Azure 的容器即服務(wù) ( CaaS ) 產(chǎn)品,ACI ) 使客戶能夠在 Azure 中運行容器而無需管理底層服務(wù)器。最近有研究人員發(fā)現(xiàn)并向 Microsoft 披露了 ACI 中的安全漏洞。惡意的 Azure 用戶可能會利用這些問題逃逸到其他用戶的容器上執(zhí)行代碼,竊取部署到平臺的客戶敏感文件,并可能濫用 ACI 的基礎(chǔ)設(shè)施進行挖礦。研究人員將該漏洞命名為 Azurescape ——公有云中的跨賬戶容器逃逸接管漏洞。

0x01 漏洞描述

Azure 容器實例 ( ACI ) 是 Azure 的容器即服務(wù) ( CaaS ) 產(chǎn)品,ACI ) 使客戶能夠在 Azure 中運行容器而無需管理底層服務(wù)器。最近有研究人員發(fā)現(xiàn)并向 Microsoft 披露了 ACI 中的安全漏洞。惡意的 Azure 用戶可能會利用這些問題逃逸到其他用戶的容器上執(zhí)行代碼,竊取部署到平臺的客戶敏感文件,并可能濫用 ACI 的基礎(chǔ)設(shè)施進行挖礦。研究人員將該漏洞命名為 Azurescape ——公有云中的跨賬戶容器逃逸接管漏洞。

https://azure.microsoft.com/en-us/services/container-instances/

Azurescape 允許惡意用戶破壞托管 ACI 的多租戶 Kubernetes 集群,建立對其他用戶容器的完全控制。這篇文章描述了研究過程、漏洞分析,并提出了保護 Kubernetes 的措施,重點是多租戶防止類似攻擊的緩解措施。

微軟在我們披露后不久修補了 ACI,現(xiàn)在還不知道 Azurescape 是否被在野利用。

0x02 Azure 容器實例

Azure 容器實例 ( ACI ) 于 2017 年 7 月發(fā)布,是大型云提供商提供的第一個容器即服務(wù) ( CaaS ) 產(chǎn)品。借助 ACI,客戶無需管理底層基礎(chǔ)結(jié)構(gòu)即可將容器部署到 Azure。ACI 負責擴展、請求路由和調(diào)度,為容器提供無服務(wù)器體驗。

https://azure.microsoft.com/en-us/blog/announcing-azure-container-instances/

Azure 官網(wǎng)對 ACI 的描述如下:" 無需管理虛擬機或?qū)W習新工具即可快速開發(fā)應(yīng)用程序,它只是在容器中、在云中運行的程序。"

在集群內(nèi)部,ACI 托管在客戶容器的多租戶集群上。剛開始是使用 Kubernetes 集群,在過去的一年里,微軟也開始在 Service Fabric 集群上托管 ACI。此處的漏洞會影響 Kubernetes 上的 ACI,本文的其余部分將僅參考該架構(gòu)。根據(jù)我們的測試,我們在平臺上部署了數(shù)千個容器,在披露時 Kubernetes 托管了大約 37% 的 ACI 新創(chuàng)建的容器。

該圖說明了托管在多租戶 Kubernetes 群集上的 Azure 容器實例,顯示了主節(jié)點上的 api 服務(wù)器如何與為三個不同客戶運行的三個工作節(jié)點相關(guān)聯(lián)。 租戶邊界用紅色虛線表示。


圖 1. 托管在多租戶 Kubernetes 集群上的 ACI。


在 ACI 等多租戶環(huán)境中,你需要在租戶之間實施強邊界。在 ACI 中,該邊界是節(jié)點虛擬機。每個客戶容器都在專用的單租戶節(jié)點上的 Kubernetes pod 中運行。這種 Kubernetes 多租戶方法通常稱為 node-per-tenant。

0x03 AzureScape 攻擊場景

ACI 會防止相鄰容器的惡意攻擊。由于幾乎任何人都可以將容器部署到平臺上,因此 ACI 必須確保惡意容器不會進行破壞、泄漏信息、執(zhí)行代碼或以其他方式影響其他客戶的容器,這種攻擊影響就是跨賬戶或跨租戶攻擊。

Azure 容器實例中的跨賬戶攻擊場景圖解,展示了惡意客戶如何占用工作節(jié)點。


圖 2. 跨賬戶攻擊場景。


以下部分涵蓋了我們對 ACI 中跨賬戶攻擊的研究。我們發(fā)現(xiàn)了一種跨租戶攻擊,惡意的 Azure 用戶可以通過這種攻擊進行容器逃逸,獲取特權(quán) Kubernetes 服務(wù)帳戶令牌并接管 Kubernetes api-server,從而建立對多租戶集群和在其中運行的所有客戶容器的完全控制。

0x04 ACI 容器逃逸

CaaS 產(chǎn)品很難研究。用戶只暴露了他們的容器環(huán)境,并且通過防火墻禁止訪問本地網(wǎng)絡(luò)。為了更好地了解 CaaS 平臺如何運行我們的容器,我們創(chuàng)建了 WhoC。WhoC 是一個容器鏡像,它可以讀取執(zhí)行它的容器 runtime,基于 Linux 容器中一個很少討論的設(shè)計缺陷,允許它們讀取底層主機的容器 runtime。這個想法與 CVE-2019-5736 非常相似,不同之處在于 CVE-2019-5736 是讀取 runtime,它 WhoC 是覆蓋主機的 runtime。

https://github.com/twistlock/whoc https://nvd.nist.gov/vuln/detail/CVE-2019-5736 https://unit42.paloaltonetworks.com/breaking-docker-via-runc-explaining-cve-2019-5736/

通過將 WhoC 部署到 ACI,我們能夠檢索平臺中使用的容器 runtime。不出所料,我們發(fā)現(xiàn)了行業(yè)標準容器 runtime runC。

https://github.com/opencontainers/runc

讓我們措手不及的是 runC 的版本,如圖 3 所示。

屏幕截圖顯示了在 2016 年 10 月 1 日發(fā)布的 runC v1.0.0-rc2 上運行的 Azure 容器實例。


圖 3. ACI 中使用的容器 runtime。


RunC v1.0.0-rc2 于 2016 年 10 月 1 日發(fā)布,并且容易受到至少兩個容器逃逸漏洞的攻擊。

https://unit42.paloaltonetworks.com/breaking-docker-via-runc-explaining-cve-2019-5736/

ACI 中存在這個舊版本的 runC,使用這個容器映像對其進行優(yōu)化并將其部署到 ACI。通過 cve-2019-5736 成功突破容器,并獲得了一個在底層主機上以 root 身份運行的反向 shell,主機是一個 Kubernetes 節(jié)點(Node)。

https://docs.paloaltonetworks.com/prisma/prisma-cloud/20-12/prisma-cloud-compute-edition-admin/runtime_defense/incident_types/reverse_shell.html

一旦我們發(fā)現(xiàn) ACI 中存在這個舊版本的 runC,我們就采用了當時開發(fā)的 PoC 容器映像,對其進行了優(yōu)化并將其部署到 ACI。 我們成功地突破了容器,并獲得了一個在底層主機上以 root 身份運行的反向 shell,結(jié)果證明它是一個 Kubernetes 節(jié)點。 在這里,我們展示了利用 CVE-2019-5736 來逃避我們的 ACI 容器的過程的屏幕截圖。


圖 4. 利用 CVE-2019-5736 來逃逸 ACI 容器。


雖然實現(xiàn)了容器逃逸,但仍然在租戶邊界內(nèi)—— VM 節(jié)點 。CaaS 平臺可以抵御復(fù)雜的攻擊者,這些攻擊者可以通過內(nèi)核漏洞實現(xiàn)權(quán)限提升和容器逃逸。

該圖顯示了租戶邊界如何防范惡意客戶。 雖然我們逃離了我們的容器,但我們?nèi)匀辉谧鈶暨吔鐑?nèi)——節(jié)點 VM。 CaaS 平臺旨在抵御復(fù)雜的攻擊者,這些攻擊者擁有內(nèi)核漏洞,可實現(xiàn)權(quán)限提升和容器突破。 惡意容器爆發(fā)是一種預(yù)期的威脅,通過節(jié)點級隔離可以容忍。


圖 5. 獲取節(jié)點權(quán)限后任然在 node 中。


0x05 探測 K8s 節(jié)點環(huán)境

探測掃描節(jié)點可以驗證當前容器是唯一的客戶容器。使用 Kubelet 憑據(jù),我們列出了集群中的 pod 和節(jié)點。該集群托管了大約 100 個客戶 pod,擁有大約 120 個節(jié)點。每個客戶都被分配了一個 Kubernetes 命名空間,他們的 pod 在其中運行;我們的容器 ID 是 caas-d98056cf86924d0fad1159XXXXXXXXXX。

https://kubernetes.io/docs/concepts/overview/components/#kubelet

可以看到節(jié)點的 Kubelet 允許匿名訪問,嘗試訪問相鄰節(jié)點上的 Kubelet。所有嘗試訪問相鄰節(jié)點的請求都超時了,可能是由于防火墻配置阻止了工作節(jié)點之間的通信。

節(jié)點在 kubernetes.azure.com/cluster 標簽中引用了集群名稱,格式如下:CAAS-PROD-< LOCATION >-LINUX-< ID >。


圖 6. 集群名稱。


我們部署了幾個分支容器,它們在不同的 Kubernetes 集群節(jié)點上。發(fā)現(xiàn)每個集群節(jié)點都有唯一的集群 ID,范圍在 1-125 之間。這些集群 ID 表明托管了幾十個集群節(jié)點。

1.Kubernetes 1 day

接下來,我們檢查了集群的 Kubernetes 版本。

Azure 容器實例托管在運行 Kubernetes v1.8.4、v1.9.10 或 v1.10.9 的群集上,如下所示。 這些版本于 2017 年 11 月至 2018 年 10 月期間發(fā)布,容易受到多個已知漏洞的攻擊。


圖 7. ACI Kubernetes 版本。


ACI 托管在運行 Kubernetes v1.8.4、v1.9.10 或 v1.10.9 的集群上。這些版本于 2017 年 11 月至 2018 年 10 月期間發(fā)布,容易受到多個已知漏洞的攻擊。運行較舊的 Kubernetes 版本有較大的風險,但它不一定會導(dǎo)致 ACI 中的安全問題。

回顧過去的 Kubernetes 漏洞,尋找可以通過被控節(jié)點提升權(quán)限或訪問其他節(jié)點的漏洞,目標鎖定: CVE-2018-1002102。

https://github.com/kubernetes/kubernetes/issues/85867

2.Kubernetes CVE-2018-1002102

當為 kubectl exec < pod > < cmd >命令提供服務(wù)時,api-server 會將請求推遲到適當?shù)?Kubelet 的 / exec 端點。

CVE-2018-1002102 是 api-server 與 Kubelets 通信中存在的漏洞,可以實現(xiàn)重定向。通過將 api-server 的請求重定向到另一個節(jié)點的 Kubelet,惡意 Kubelet 命令可以在集群中傳播。圖 8 展示了漏洞的基本流程:

CVE-2018-1002102 的基本流程:1 ) 由 api-server 服務(wù)的命令,2 ) api-server 將請求延遲到適當?shù)亩它c,3 ) 302 重定向,4 ) 通過集群傳播。


圖 8. CVE-2018-1002102 利用流程。


漏洞利用前提條件:

存在漏洞的 api-server 版本:

獲取一個節(jié)點權(quán)限:

通過 api-server 可以使被控節(jié)點與其他節(jié)點通信。例如,可以通過向被控節(jié)點上的 pod 發(fā)出 kubectl exec 來完成。

事實證明,ACI 滿足第三個前提條件。ACI 支持通過鏡像 kubectl exec 的 az container exec 命令在上傳的容器上執(zhí)行命令。

az container exec --name --exec-command

創(chuàng)建一個利用 CVE-2018-1002102 的自定義 Kubelet 映像,將傳入的 exec 請求重定向到其他節(jié)點上的 pod。為了最大限度地發(fā)揮作用,將其配置為以 api-server pod 為目標,最后,運行 az container exec my-ctr --exec-command /bin/bash,希望能在 api-server 容器上建立一個 shell。

執(zhí)行命令失敗了,經(jīng)過一些調(diào)試,我們注意到重定向操作僅在目標容器托管在同一節(jié)點上時才有效。這有效地消除了攻擊,因為我們無法傳播到其他節(jié)點。分析 CVE-2018-1002102 的補丁,確實對該漏洞的修復(fù)。

https://github.com/kubernetes/kubernetes/pull/66516

重新檢查到達節(jié)點的 exec 請求,請求可能會從 api-server IP 到達,如圖 8 所示。但是,求來自在默認命名空間中運行的 "bridge" pod。

重新檢查到達節(jié)點的 exec 請求后發(fā)現(xiàn),這些請求源自在默認命名空間中運行的被稱為 " 網(wǎng)橋 " 的 pod,如圖所示。


圖 9.az container exec 會話期間的 Kubelet 連接。


我們發(fā)現(xiàn) ACI 將 exec 請求的處理從 api-server 轉(zhuǎn)移到自定義服務(wù)。這可能是通過將 az 容器 exec 命令路由到橋接容器而不是 api-server 來實現(xiàn)的。

我們發(fā)現(xiàn) ACI 將 exec 請求的處理從 api-server 轉(zhuǎn)移到自定義服務(wù)。 這可能是通過將 az 容器 exec 命令路由到橋接容器而不是 api-server 來實現(xiàn)的。


圖 10. Bridge Pod 處理 ACI 中的執(zhí)行程序。


網(wǎng)橋鏡像標簽是 master_20201125.1,表明它是在 CVE-2018-1002102 之后更新的。從其最近的構(gòu)建時間和拒絕重定向 exec 請求來看,似乎 CVE-2018-1002102 的補丁已經(jīng) patch 到了 bridge 上。微軟應(yīng)該是注意到了此漏洞影響了他們的自定義網(wǎng)橋 Pod 并進行了修補。

值得一提的是,CVE-2018-1002102 也可以在其他情況下被利用,例如,當客戶端要求惡意 Kubelet 檢索容器日志(例如 kubectl 日志)時。這實際上與 ACI 相關(guān),其中此功能是通過 az container logs 命令實現(xiàn)的。但與 exec 請求一樣,ACI 將日志檢索的處理推遲到適當?shù)?log-fetch 專用 pod 上 。與 Bridge Pod 一樣,CVE-2018-1002102 的修復(fù)程序也被移植到 log-fetch Pod,以防止被利用。

0x06 獲取集群管理員權(quán)限

CVE-2018-1002102 不在討論范圍內(nèi),但我們在調(diào)試漏洞利用時確實注意到了一些奇怪的事情。到達節(jié)點的 exec 請求包含一個 Authorization Header 頭,其中包含一個 Kubernetes 服務(wù)帳戶令牌,如圖 11 所示。

到達節(jié)點的 exec 請求包含一個 Authorization 標頭,其中包含一個 Kubernetes 服務(wù)帳戶令牌,如圖所示。


圖 11. Bridge 發(fā)送帶有服務(wù)帳戶令牌的 "exec" 請求。


在這里找到令牌令人驚訝。如前所述,集群中的 Kubelet 被配置為允許匿名訪問,因此請求不需要通過令牌進行身份驗證,也許是舊版本中遺留的令牌。

Kubernetes 服務(wù)帳戶令牌是未加密的 JSON Web 令牌 ( JWT ) ,因此它們是可解碼的。如下所示,接收到的令牌是 "bridge" 服務(wù)帳戶的服務(wù)帳戶令牌??紤]到來自橋接 Pod 的請求,這是有道理的。

https://jwt.io/

收到的令牌是 " 網(wǎng)橋 " 服務(wù)帳戶的服務(wù)帳戶令牌。 考慮到來自橋接 Pod 的請求,這是有道理的。


圖 12. 已解碼的橋接服務(wù)帳戶令牌。


如果你要運行 Kubernetes,一定要注意要將服務(wù)帳戶令牌發(fā)送給誰:任何收到令牌的人都可以自由使用它并偽裝成其所有者。令牌竊取者很可能對他們被盜令牌的權(quán)限非常感興趣。api-server 公開了兩個允許客戶端查詢其權(quán)限的 API,SelfSubjectAccessReview 和 SelfSubjectRulesReview。kubectl 提供了 kubectl auth can-i 作為訪問這些 API 的便捷方式。

以下是默認命名空間中 "Bridge" 令牌的權(quán)限:

這顯示了默認命名空間中 " 橋 " 令牌的權(quán)限。


圖 13. 橋接令牌權(quán)限——默認命名空間。


查看其他命名空間,權(quán)限是一致的,表明它們是集群范圍的(而不是命名空間范圍的)。以下是 kube-system 命名空間中令牌的權(quán)限。嘗試確定允許我們在多租戶集群中傳播的權(quán)限:

這顯示了 kube-system 命名空間中令牌的權(quán)限,包括 pods/exec 權(quán)限,表明令牌可用于在集群中的任何 Pod 上執(zhí)行命令。


圖 14. 橋接令牌權(quán)限 - kube-system 命名空間。


經(jīng)驗豐富的 Kubernetes 安全人員可能已經(jīng)確定了 pods/exec 權(quán)限,這表明該令牌可用于在集群中的任何 pod 上執(zhí)行命令——包括 api-server pod!圖 15 顯示了在 api-server 容器上打開 shell 的令牌:

這顯示了在 api-server 容器上打開 shell 的令牌。


圖 15. 使用網(wǎng)橋的令牌在 api-server 上彈出一個 shell。


我們剛剛完成了一次跨賬戶攻擊。通過在 api 服務(wù)器上執(zhí)行代碼,我們現(xiàn)在是集群管理員了,可以完全控制多租戶集群和其中的所有客戶容器 : )

0x07 Azurescape 攻擊總結(jié)

讓我們總結(jié)一下惡意 Azure 客戶可能通過托管 ACI 的多租戶 Kubernetes 集群獲得管理權(quán)限的步驟:

將利用 CVE-2019-5736 的鏡像部署到 ACI。惡意鏡像在執(zhí)行時在底層節(jié)點上實現(xiàn)逃逸代碼執(zhí)行。

在節(jié)點上,監(jiān)聽 Kubelet 端口 10250 上的流量,并等待在 Authorization 標頭中包含 JWT 令牌的請求。

發(fā)出 az container exec 以在上傳的容器上運行命令。橋接 Pod 將向受感染節(jié)點上的 Kubelet 發(fā)送 exec 請求。

在節(jié)點上,從請求的 Authorization 標頭中提取橋接令牌,并使用它在 api-server 上獲取 shell。

以下視頻演示了該攻擊:

https://youtu.be/YfZBwKP18CQ

惡意 Azure 用戶可以破壞托管 ACI 的多租戶 Kubernetes 集群。作為集群管理員,攻擊者可以在其他客戶容器中執(zhí)行命令、泄露部署到平臺的敏感信息和私有映像,或者部署加密挖礦程序。

0x08 獲取 Cluster 權(quán)限的另一種方法:Bridge SSRF

某些功能僅在 Kubernetes 上受支持,例如 gitRepo volume。如果 ACI 容器使用了此類功能,并且它部署在 Kubernetes 集群上,這意味著其他容器可能會控制 Kubernetes。私有虛擬網(wǎng)絡(luò)中的容器就是這種情況。

https://docs.microsoft.com/en-us/azure/container-instances/container-instances-volume-gitrepo

https://docs.microsoft.com/en-us/azure/container-instances/container-instances-vnet

我們發(fā)現(xiàn)的第二個問題是網(wǎng)橋 Pod 中的服務(wù)器端請求偽造 ( SSRF ) 漏洞。

當橋接 Pod 為 az 容器 exec< ctr > < cmd >命令提供服務(wù)時,它會向相應(yīng)的 Kubelet 的 /exec 端點發(fā)送請求。橋接器根據(jù) Kubelet 的 /exec 端點的 API 規(guī)范構(gòu)造請求,生成以下 URL:

https://< nodeIP >:10250/exec///?command=&error=1&input=1&output=1&tty=1

Bridge 必須以某種方式填充 中缺少的參數(shù),< nodeIP >的值是從客戶 pod 的 status.hostIP 字段中檢索到的。發(fā)現(xiàn)這一點非常有趣,因為節(jié)點有權(quán)更新其 pod 的狀態(tài)(例如,為了將其 pod 的 status.state 字段更新為 Running、Terminated 等)。

我嘗試使用受感染節(jié)點的憑據(jù)更改 pod 的 status.hostIP 字段,確實起作用了,但在一兩秒鐘后,api-server 將 hostIP 字段更正為其原始值。盡管更改沒有持續(xù)存在,但我們可以重復(fù)更新此字段。

我們編寫了一個小腳本來反復(fù)更新 pod 的狀態(tài),并使用它來將 status.hostIP 字段設(shè)置為 1.1.1.1。然后發(fā)送了一個 az container exec 命令。命令執(zhí)行失敗,驗證網(wǎng)橋?qū)?exec 請求發(fā)送到 1.1.1.1 而不是真實節(jié)點 IP。我們開始考慮哪些特制的 hostIP 可以誘使網(wǎng)橋在其他 pod 上執(zhí)行命令。

簡單地將 pod 的 status.hostIP 設(shè)置為另一個節(jié)點的 IP 也沒有成功。Kubelets 只接受指向它們托管的容器的請求,即使 Bridge 將 exec 請求發(fā)送到另一個 Kubelet 的 IP,URL 仍將指向我們的命名空間、pod 名稱和容器名稱。

然后我們意識到 api-server 實際上并沒有驗證 status.hostIP 值是否是一個有效的 IP,并且會接受任何字符串——包括 URL 組件。經(jīng)過幾次嘗試,我們想出了一個 hostIP 值,它會誘使網(wǎng)橋在 api-server 容器而不是我們的容器上執(zhí)行命令:

:10250/exec/kube-system//?command=&error=1&input=1&output=1&tty=1#

此 hostIP 值將導(dǎo)致網(wǎng)橋?qū)?exec 請求發(fā)送到以下 URL:

https:// :10250/exec/kube-system//?command=&error=1&input=1&output=1&tty=1 # :10250/exec///?command=&error=1&input=1&output=1&tty=1

我們將 pod 的 status.hostIP 設(shè)置為此值并通過 az container exec 執(zhí)行命令。攻擊成功了!我們拿到的不是容器的 shell,而是 api-server 容器的 shell。完整的攻擊可以在以下視頻中看到:

https://youtu.be/7Alea_9oZgU

欺騙 Bridge 打開 api-server 上的 shell。

這里的影響與之前的攻擊完全相同——對多租戶集群的完全管理控制。

0x09 研究總結(jié)

跨賬戶漏洞是公有云的 " 噩夢 "。Azurescape 證明它們比我們想象的更真實。云提供商在保護他們的平臺方面投入了大量資金,但不可避免地會存在未知的 0 day 漏洞并使用戶面臨風險。云用戶應(yīng)該對云安全采取深度防御方法,以確??刂坪蜋z測漏洞,無論威脅來自外部還是來自平臺本身。

立即登錄,閱讀全文
版權(quán)說明:
本文內(nèi)容來自于ZAKER,本站不擁有所有權(quán),不承擔相關(guān)法律責任。文章內(nèi)容系作者個人觀點,不代表快出海對觀點贊同或支持。如有侵權(quán),請聯(lián)系管理員(zzx@kchuhai.com)刪除!
優(yōu)質(zhì)服務(wù)商推薦
更多