Unit 42 研究人員調查了 Azure 的無服務器架構,發現他們能夠破壞底層主機的無服務器函數。研究人員還發現,他們的主機實際上是一個 HyperV 虛拟機,它托管了其他幾個無服務器函數。Hyper-V 是微軟的一款虛拟化産品,是微軟第一個采用類似 Vmware ESXi 和 Citrix Xen 的基于 hypervisor 的技術。
Azure serverless functions(通常稱為 Azure Functions)是一種無服務器解決方案,可以使用戶減少代碼編寫、減少需要維護的基礎結構并節省成本。無需擔心部署和維護服務器,雲基礎結構提供保持應用程序運行所需的所有最新資源。你可以專注于使用你認為最高效的語言編寫最重要的代碼,而 Azure Functions 處理其餘代碼。作為一個基于觸發器的服務,它運行代碼以響應各種事件。在本文中,這個事件是一個網頁請求。
研究人員發現,對于每個函數,主機都會生成一個新的容器。每個容器将在幾分鐘後終止并删除,以将無服務器函數與傳統的容器即服務區分開來。
問題主機隻托管研究的 Azure 用戶有權訪問的函數,因此不會造成真正的攻擊。很明顯,微軟竭盡全力阻止人們訪問主機,因此可能還有其他問題尚未被發現。虛拟機上可能有不應該顯示的重要信息,這些信息可能會被動機充分的攻擊者發現。
微軟經常使用容器來加強安全性,但由于容器本質上不如虛拟機那樣安全,因此通常不會将其視為安全邊界。在本文的示例中,他們實現了額外的安全層,這被證明是有效的。
Prisma 的無服務器解決方案為大多數雲提供商提供了函數發現和漏洞掃描功能。這些功能會作用于無服務器函數上,并在發現這些函數中存在已知漏洞時提醒你。
什麼是無服務器函數
無服務器函數是無服務器計算(通常簡稱為 " 無服務器 ")的一個特點,雲提供商按需為其客戶提供所有計算資源,并管理所有架構,包括雲基礎設施。
無服務器理想應用程序的一個很好的例子是聊天機器人。例如,Slack 使用名為 marbot 的無服務器應用程序通過 Slack 向 DevOps 團隊發送通知。
"serverless" 這個名字有點誤導人。不管它的名字意味着什麼,無服務器計算仍然需要物理服務器來執行代碼。與傳統計算的主要區别在于,無服務器抽象了與代碼本身無關的任何東西,從代碼運行的操作系統到實際運行代碼的設備硬件。
無服務器函數的内部結構
你可能會問自己的第一個問題是如何開始研究無服務器平台。任何使用過 Azure Serverless Functions 的人都知道,可研究的地方不是很多。你可以上傳一些代碼或更改一些設置,如下圖所示,但僅此而已。
通過 Azure 函數提供的所有不同運行時
研究人員決定從一個 HTTP 請求觸發的 Linux 上的 Python 函數開始研究,對于某些運行時,Windows 也可用。
下一步是在函數中獲得一個有效的交互式 shell,以更好地理解研究人員正在處理的内容,并獲得有關運行代碼的設備的一些信息。為了便于使用,研究人員決定使用逆向 shell。研究人員還決定使用數據傳輸工具 socat 而不是 netcat,因為它支持更廣泛的協議。
研究人員使用的 socat 二進制文件
研究人員隻是将 socat 二進制文件放在 Visual Studio 代碼中的項目目錄中,并将整個文件部署到研究人員之前創建的無服務器函數中。實際啟動逆向 shell 的代碼非常簡單,因為整個邏輯都在 socat 應用程序中,如下圖所示。
連接到逆向 shell 偵聽器的簡單函數代碼
執行逆向 shell 後,研究人員進入了一個名為 app 的用戶下的函數目錄。研究人員使用
cat/proc/1/cgroup_last_cap 命令,以 SandboxHost 開頭的設備主機名也暗示了這一點。
無服務器函數内部的 shell
在研究人員登錄的工作目錄中沒有太有趣的東西。這個目錄包括他們上傳的所有文件,外加一個額外的 lib 文件夾,其中包含 Python 與 Azure 通信所需的庫。
容器
這項研究一開始并沒有明确的目标,隻是為了改善 Prisma 的無服務器保護。然而,在了解了更多關于架構的知識後,研究人員渴望探索一下容器。
在熟悉了容器及其文件以及用戶權限等之後,研究人員決定檢查環境變量,因為它們通常包含一些有趣的信息。這一次沒有什麼不同。在其他有趣的事情中,研究人員注意到環境變量洩露了映像名稱。
環境變量中的映像名稱
在網上搜索這個映像名稱,研究人員找到了一個顯示映像名稱的微軟官方目錄,該目錄指向一個提供所有 Microsoft 映像 ( 包括我們正在查看的映像 ) 的官方存儲庫。
研究人員的第一個方法是獲取映像 " 源代碼 "(如果你使用 Docker,則為 Dockerfile)。經過一番搜索,研究人員發現有一個叫做 Whaler 的實用工具,它可以将 Docker 映像逆向工程到創建它們的 Dockerfile 中。該過程如下所示。
使用 Whaler 對微軟映像進行逆向工程
Whaler 有大量的映像,從而産生一個易于使用的單行命令。使用這個方法,研究人員成功地生成了一個足夠好的 Dockerfile 版本,如下圖所示。文件中最有趣的部分是最後一行。
逆向之後的 Dockerfile 版本
網格文件夾似乎包含一些有趣的文件,特别是 launch.sh 腳本,它似乎是容器内執行的第一件事。此時,研究人員隻需從映像内部複制整個網格文件夾,以進一步研究它。
還有一些腳本在不同的場景中調用了一些其他腳本,該文件夾中有趣的部分是一個名為 init 的二進制文件,它在每個 Azure 無服務器容器的後台運行。對研究人員來說幸運的是,這個二進制文件也包含了符号,所以逆向工程很容易。
在研究了函數和字符串列表之後,有一個函數特别有趣:init_server_pkg_mount_BindMount。在對其進行逆向工程之後,研究人員發現該函數将容器内的一條路徑綁定到另一條路徑,該路徑也位于容器内。此函數也不要求用戶具有特權,但它在 root 上下文中運行!要将一個文件綁定到任何其他文件,你所需要做的就是在容器中使用正确的參數在正确的端口上執行 HTTP 查詢。
init_server_pkg_mount_BindMount 函數簽名
init_server_pkg_mount_BindMount 函數解析來自 HTTP 請求的 sourcePath 和 targetPath
在這部分調查的過程中,研究人員還發現了許多關于 Azure 無服務器架構如何在幕後工作的信息。雖然這超出了本文的範圍,但可以在本文中深入探讨這一問題。
升級權限
簡而言之,雖然在一個沒有特權的用戶的容器中研究,但研究人員能夠将任何一個文件作為根文件綁定到任何其他文件。此時,研究人員的目标是在容器内将特權升級到根權限。可能有幾種方法可以實現這一點,但研究人員選擇用生成的文件替換 /etc/shadow 文件,然後将用戶更改為 root。
使用 OpenSSL 生成 /etc/shadow
為了實現這一點,研究人員執行了以下步驟:
為 root 用戶生成一個密碼已知的 /etc/shadow 文件;
将該文件上傳到 Function 容器的本地目錄;
使用正在運行的 init 服務和 BindMount 函數通過查詢 http://localhost:6060 将本地陰影文件綁定到實際的 /etc/shadow 文件;
使用 su-root 命令将用戶更改為 root。
不斷升級權限
利用 root 權限規避容器
可以利用新獲得的根訪問來規避容器,通過研究,研究人員選擇了菲利克斯 · 威廉姆(Felix Wilhelm)多年前發現的一個舊漏洞。
不過要使用此漏洞也不是一件簡單的事情,要使其正常工作,需要滿足以下幾個要求:
研究人員必須在容器内以 root 身份運行;
容器需要具有 SYS_ADMIN 函數;
容器要麼沒有 AppArmor 配置文件,要麼允許挂載系統調用;
cgroup v1 虛拟文件系統必須在容器内以讀寫方式安裝;
研究人員已經在早些時候實現了第一個需求。令人驚訝的是,其餘的需求在我們的容器中也可用。這是令人驚訝的,因為在默認情況下,容器啟動時具有一組受限的函數,并且沒有啟用 SYS_ADMIN 函數。此外,Docker 通常在默認情況下使用 AppArmor 策略啟動容器,這防止了在容器使用 SYS_ADMIN 運行時使用 mount sycall。通過在 /proc/PID/status 下的 shell 狀态文件上運行 capsh 命令,研究人員确認了所有必要的函數,如下圖所示。
使用 capsh 和一些 sed 腳本來打印特權用戶函數
關于此漏洞的詳細解釋已超出了本文範圍,我們建議閱讀 "Digging into cgroups Escape" 以更好地理解此技術。簡而言之,研究人員将通過以下步驟描述該漏洞:
查找或創建對 cgroup 控制器的訪問權限(大多數版本的漏洞利用使用 RDMA);
在該控制器中創建一個新的 cgroup;
将該 cgroup 的 notify_on_release 設置為 1;
将發布代理設置為容器和主機都可以訪問的文件;
在該 cgroup 中啟動一個快速完成流程,該流程将在終止時觸發發布代理的執行。
研究人員決定通過運行 ps aux 并将其與容器的 ps aux 進行比較來演示實現主機執行上下文。在本節開頭的視頻中,你可以看到漏洞的整個利用過程。需要注意的是,托管容器的設備是 HyperV 虛拟機,而不是物理服務器。
總結
不管怎樣,Azure 的用戶都可以訪問虛拟機托管的所有資源,因此,這種防禦沒有什麼意義。這是雲提供商緩解措施按預期工作的一個示例。在本文的示例中,他們選擇不依賴容器作為安全邊界,并實現另一種保護,這被證明是一個聰明的舉動。
但是,如果在虛拟機本身中發現另一個漏洞,這個漏洞可能會産生巨大的影響。此外,微軟在過去已經修複了類似的問題,即使他們本身沒有将其稱為漏洞。
虛拟機可能包含對無服務器函數用戶或可能的攻擊者不可見的重要信息或秘密。在與微軟分享該調查結果後,他們考慮了以下防禦措施,以更好地保護客戶:
對綁定裝載 API 進行額外驗證,以防止裝載過度;
盡可能從二進制文件中删除符号。