云存儲桶枚舉與提權
對于那些不熟悉的人來說,GCP是一個云平臺,為任何規模的企業提供各種云計算解決方案。大多數人都會把它放在可用的“三大”云提供商中,即亞馬遜網絡服務(AWS)、Microsoft Azure和GCP。
云安全是一個極其重要的研究領域,對于這些云平臺的用戶來說,理解和接受它變得越來越重要。與競爭對手AWS相比,GCP安全是一個似乎未觸及的研究領域。這可能是出于許多不同的原因,主要原因可能是他們每個人控制的市場份額。根據最近在ZDNet.com上發布的一篇文章,AWS擁有最大的市場份額,其次是Microsoft Azure,其次是GCP,因此AWS安全性(和Azure安全性在小得多的情況下)將遠遠領先于GCP是有道理的。這并不意味著GCP完全是“不安全的”,而是更意味著對GCP安全性的外部第三方研究更少。
谷歌存儲桶安全
Google Storage是通過GCP提供的服務,在被稱為“桶”的資源中提供靜態文件托管。如果熟悉AWS,Google Storage是GCP版本的AWS簡單存儲服務(S3),S3存儲桶相當于兩個云的Google存儲桶。
GCP Bucket 提權策略與枚舉
不過,谷歌存儲桶權限策略可能會變得非常細粒度。根據設計,他們可以接觸到各種來源(其他帳戶、組織、用戶等),包括向公共互聯網或所有經過身份驗證的GCP用戶開放。
GCPBucketBrute
GCPBucketBrute目前在我們的GitHub上可用:https://github.com/RhinoSecurityLabs/GCPBucketBrute
該工具是用Python 3編寫的,只需要幾個不同的庫,因此安裝起來很簡單。
為此,請按照以下步驟操作:
- git clone https://github.com/RhinoSecurityLabs/GCPBucketBrute.git
- cd GCPBucketBrute && pip3 安裝 -r requirements.txt
安裝后,你可以向下移動到此帖子的下一部分開始,也可以運行以下命令自行查看
幫助輸出:
python3 gcpbucketbrute.py –help
工作方式
與其使用“gsutil”(谷歌存儲實用程序)CLI程序來執行枚舉,不如點擊我們正在尋找的每個存儲桶的HTTP端點來檢查是否存在要快得多,因為在這種情況下,“gsutil”CLI沒有開銷。它還使用子進程而不是線程進行設計并發執行。
當腳本開始時,它將根據提供給“-k/–keyword”參數的關鍵字生成一個排列列表。然后,它將通過向Google
API發送HTTP請求來開始粗暴執行存儲桶,并將根據HTTP響應代碼確定存儲桶的存在。通過提出HTTP HEAD請求而不是HTTP
GET請求,我們可以確保HTTP響應不包含正文,同時仍然獲得有效的響應代碼。雖然差異可能可以忽略不計,但理論上,較小的響應(即HEAD請求中沒有主體的響應)到達并解析的速度比較大的響應(即來自GET請求的正文的響應)到達和解析要快。使用HEAD請求還可以讓谷歌的服務器在嘗試處理我們的請求時工作更少,這在大規模上很有幫助。
每個HTTP HEAD請求都將發送到以下URL:“https://www.googleapis.com/storage/v1/b/BUCKET_NAME”,其中“BUCKET_NAME”被當前猜測所取代。如果HTTP響應代碼為“404”或“400”,則存儲桶不存在。根據測試期間發現的情況,我們遇到的任何其他HTTP響應代碼都表明存儲桶存在。
對于發現的任何存儲桶,將使用Google Storage TestIamPermissions
API來確定我們對目標存儲桶的訪問級別(如果有的話)。如果憑據傳遞到腳本中,則經過身份驗證的TestIamPermissions和未經身份驗證的TestIamPermissions調用的結果都將輸出到屏幕上進行比較,因此你可以看到授予allAuthenticatedUsers和allUsers的訪問權限之間的區別。如果沒有傳遞憑據,則僅進行未經身份驗證的檢查并輸出(如果傳遞到“-o/–out-file”參數,則輸出到屏幕和外部文件)。
如果發現用戶對存儲桶有任何權限(已身份驗證與否),則將輸出所有權限。在此之前,該工具將檢查一些常見的配置錯誤,并將輸出一條單獨的行,使事情更清晰一點。例如,授予“allUsers”“storage.objects.list”權限的存儲桶將在輸出所有權限之前輸出消息“未經身份驗證的LISTABLE(storage.objects.list)”。這只是為了在目標桶中出現配置錯誤時更清楚地說明問題。
還將檢查權限列表,看看用戶是否有權限通過修改存儲桶策略來升級其在存儲桶上的權限。
快速入門
注意:如果不傳遞任何與身份驗證相關的參數,腳本將提示執行你要做的事情(服務帳戶、訪問令牌、默認憑據、未經身份驗證)。
使用“netflix”作為關鍵字,使用5個并發子進程(默認)掃描存儲桶,提示身份驗證類型以檢查任何找到的存儲桶(默認)上的身份驗證列表權限:
python3 gcpbucketbrute.py -k netflix
使用“谷歌”作為關鍵字,使用10個并發子進程掃描存儲桶,同時保持未經身份驗證:
python3 gcpbucketbrute.py -k google -s 10 -u
使用“apple”作為關鍵字,使用5個并發子進程(默認)掃描存儲桶,提示身份驗證類型以檢查任何找到的存儲桶(默認)上的身份驗證列表權限,并將結果輸出到“out.txt”:
python3 gcpbucketbrute.py -k apple -o out.txt
使用“android”作為關鍵字,使用5個并發子進程(默認)掃描存儲桶,同時使用憑據存儲在sa.pem中的GCP服務帳戶進行身份驗證:
python3 gcpbucketbrute.py -k android -f sa.pem
使用“samsung”作為關鍵字,使用8個并發子進程掃描存儲桶,同時使用憑據存儲在service-account.pem中的GCP服務帳戶進行身份驗證:
python3 gcpbucketbrute.py -k samsung -s 8 -f service-account.pem
存儲桶提權
正如AWS S3存儲桶可能容易因配置錯誤的桶ACL而易受提權(此處深入討論))一樣,谷歌存儲桶也容易受到同類攻擊。
與GCPBucketBrute如何通過直接HTTP請求“https://www.googleapis.com/storage/v1/b/BUCKET_NAME/o”來檢查打開的谷歌存儲桶一樣,我們可以通過向“https://www.googleapis.com/storage/v1/b/BUCKET_NAME/iam”發出直接HTTP請求來檢查存儲桶的策略,或者我們可以使用“gsutil”CLI工具運行“gsutil
iam get
gs://BUCKET_NAME”。
如果允許“allUsers”或“allAuthenticatedUsers”閱讀存儲桶策略,我們將在拉動存儲桶策略時收到有效的響應,否則我們將被拒絕訪問。
桶策略很有幫助,但這要求我們擁有“storage.buckets.getIamPolicy”權限,而我們可能沒有。如果有一種方法可以確定我們被授予的權限,而無需查看存儲桶策略,該怎么辦?
等等,有!Google
Storage“TestIamPermissions”API允許我們提供存儲桶名稱和Google存儲權限列表,它將響應我們(提出API請求的用戶)在該存儲桶上的權限。這完全繞過了查看存儲桶策略的要求,甚至可以為我們提供更好的信息(在使用自定義角色的情況下)。
為了確定我們在存儲桶上擁有哪些權限,我們可以向類似于“https://www.googleapis.com/storage/v1/b/BUCKET_NAME/iam/testPermissions”的URL提出請求。permissions=storage.objects.list”,它將響應并告訴我們我們是否在存儲桶“BUCKET_NAME”上有“storage.objects.list”權限。權限參數可以傳遞多次以同時檢查多個權限,谷歌存儲Python庫支持test_iam_permissions
API(即使“gsutil”不支持)。
GCPBucketBrute將使用當前憑據(如果運行未經身份驗證的掃描,則使用無憑據/匿名憑據)來確定我們被授予每個發現的存儲桶哪些特權。如上所述,對于我們無法訪問的桶,不會輸出任何東西。對于我們有權訪問的存儲桶,它將輸出我們擁有的權限列表。對于我們有足夠的權限升級并成為完整存儲桶管理員的存儲桶,它將輸出權限和一條消息,表明它容易受到提權的影響。
以下屏幕截圖顯示了在查找具有一些特權的存儲桶和容易受到提權影響的存儲桶時輸出的內容。

對于報告容易受到提權影響的存儲桶,這本質上意味著存儲桶策略允許“allUsers”或“allAuthenticatedUsers”寫入他們的存儲桶策略(storage.buckets.setIamPolicy權限)。這使我們能夠寫信給“所有用戶”/“所有身份驗證用戶”是存儲桶所有者的提權策略,從而授予我們對存儲桶的完全訪問權限。
對于被發現容易受到公共提權影響的桶,我們向擁有它們的公司報告了這一發現(在那里我們可以識別這樣的事情,其余的直接報告給谷歌)。
為了執行提權,我們按照以下步驟操作:
- 根據我們提供的關鍵字,掃描現有存儲桶
- 對于找到的任何存儲桶,請檢查通過使用TestIamPermissions
- API作為經過身份驗證和未經身份驗證的用戶,檢查授予了哪些權限給“allUsers”或“allAuthenticatedUsers”。如果發現他們有權寫入存儲桶策略(storage.buckets.setIamPolicy),我們將有提權。脆弱的桶提權策略可能看起來像這樣:
{"bindings":[{"members":["allAuthenticatedUsers","projectEditor:my-test-project","projectOwner:my-test-project"],"role":"roles\/storage.legacyBucketOwner"},{"members":["projectViewer:my-test-project"],"role":"roles\/storage.legacyBucketReader"},{"members":["projectEditor:my-test-project","projectOwner:my-test-project"],"role":"roles\/storage.legacyObjectOwner"},{"members":["projectViewer:my-test-project"],"role":"roles\/storage
忽略了本提權策略中定義的大部分內容,我們可以看到“allAuthenticatedUsers”組是“roles/storage.legacyBucketOwner”角色的成員。如果我們看看該角色被授予了什么權限,我們會看到以下內容:
- storage.buckets.get
- storage.buckets.getIam策略
- storage.buckets.setIam策略
- storage.buckets.update
- storage.objects.create
- storage.objects.delete
- storage.objects.list
這意味著我們可以讀取(storage.buckets.getIamPolicy)和寫入(storage.buckets.setIamPolicy)到存儲桶策略,并且我們可以在存儲桶中創建、刪除和列出對象。
請注意,我們通過訪問以下URL看到相同的信息:(請注意,省略了“storage.objects.getIamPolicy”和“storage.objects.setIamPolicy”權限,因為它們會在設置為禁用對象級權限的任何存儲桶上拋出錯誤。對于啟用對象級權限的存儲桶,可以包含這些值)。
https://www.googleapis.com/storage/v1/b/BUCKET_NAME/iam/testPermissions?permissions=storage.buckets.delete&permissions=storage.buckets.get&permissions=storage.buckets.getIamPolicy&permissions=storage.buckets.setIamPolicy&permissions=storage.buckets.update&permissions=storage.objects.create&permissions=storage.objects.delete&permissions=storage.objects.get&permissions=storage.objects.list&permissions=storage.objects.update
如果我們查看存儲管理員角色授予的權限,我們可以看到它授予了這些特權:
- firebase.projects.get
- resourcemanager.projects.get
- resourcemanager.projects.list
- storage.buckets.create
- storage.buckets.delete
- storage.buckets.get
- storage.buckets.getIam策略
- storage.buckets.list
- storage.buckets.setIam策略
- storage.buckets.update
- storage.objects.create
- storage.objects.delete
- storage.objects.get
- storage.objects.getIamPolicy
- storage.objects.list
- storage.objects.setIam策略
- storage.objects.update
授予此角色的特權比“allAuthenticatedUsers”的角色成員還多,所以我們為什么不改變呢?
使用“gsutil”Google Storage CLI程序,我們可以運行以下命令,授予“allAuthenticatedUsers”對“存儲管理員”角色的訪問權限,從而將我們授予的權限升級到存儲桶中:
gsutil iam ch group:allAuthenticatedUsers:admin gs://BUCKET_NAME
現在,如果我們再次查看存儲桶策略,我們可以看到添加了以下內容(因為“ch”命令附加到策略中,而不是覆蓋):
{"members":["group:allAuthenticatedUsers"],"role":"roles\/storage.admin"}
就這樣,我們已經將我們的特權從存儲遺產桶所有者升級到我們甚至不擁有的存儲桶上的存儲管理員!
從LegacyBucketOwner升級到Storage Admin的主要吸引力之一是能夠使用“storage.buckets.delete”特權。理論上,你可以在升級權限后刪除存儲桶,然后你可以在自己的帳戶中創建存儲桶來竊取名稱。
現在,如果我們再次查看TestIamPermissions
API授予的特權,我們就會看到從我們使用的新角色中添加了一些額外內容。請注意,在使用TestIamPermissions
API(如resourcemanager.projects.list)時,并非該角色允許的所有特權都會列出,因為并非所有權限都是Google
Storage特定的權限,并且API不支持。
注意:“gsutil iam
ch”命令需要讀取目標存儲桶策略的權限,因為它首先讀取策略,然后添加你的添加,然后編寫新策略。即使你擁有SetBucketPolicy權限,你可能也不總是擁有此權限。在這些情況下,你需要覆蓋現有策略,并有可能在其環境中造成錯誤,例如,如果不小心撤銷了需要訪問的內容。
免責聲明:提權實際上沒有在任何易受攻擊的桶上執行,而是只確認存在漏洞。
總結
盡管存儲桶是默認私有創建的,但我們一次又一次地看到用戶錯誤配置其資產的權限,并將其暴露給公共中的惡意行為者,而Google Storage TestIamPermissions等簡單API只會讓它變得更容易。