Jump to content

Laravel 是一個廣泛使用的開源PHP Web 框架。它可用於相對輕鬆地創建複雜的Web 應用程序,並在許多流行的項目中使用。

在最近對該應用程序的滲透測試中,我們獲得了對框架環境文件的訪問權限。該文件包含許多敏感的Laravel 配置設置,包括應用程序APP_KEY 。

APP_KEY 用於多個與安全相關的任務,在過去,APP_KEY的信息是獲得遠程代碼執行的可靠方法,因為它用於對(序列化的)XSRF令牌簽名。了解APP_KEY的攻擊者能夠創建惡意的XSRF令牌,然後使用已知的小工具鏈,通過不安全的反序列化(CVE-2018-15133)導致RCE。

由於Lavel 5.6.30 默認禁用cookie 序列化。因此,APP_KEY不再授予一個有保證的RCE,攻擊者需要在攻擊路徑上更有創意一點。在這篇文章中,我們會重點介紹攻擊者可以利用洩露的環境文件利用的一些替代攻擊媒介。

APP_KEY 基礎知識Laravel 期望它的環境文件.env 在應用程序的根文件夾中。該文件包含幾個Laravel 配置設置,包括APP_KEY、數據庫憑據和常規設置等機密信息。文件內容的洩露(例如通過任意文件讀取漏洞)會產生嚴重影響,因為洩露的信息可能會以多種方式被濫用。

最顯著的秘密是APP_KEY,它經常可以被濫用來獲得RCE。使用APP_KEY 的最值得注意的函數是:

1.Laravel 的默認“encrypt()”和“decrypt()”函數。如果開發人員想要加密或解密任何值或對象,那麼他們很可能會使用這些函數。它們也被用來加密Laravel的會話cookie,從而進行篡改保護。

2.Laravel 還具有創建防篡改簽名URL 的內置功能。此外,大多數簽名函數使用應用程序APP_KEY 作為機密。

3.在復雜的Web 應用程序中,你可能會看到需要對時間不敏感的任務進行排隊(例如發送提醒郵件)。這樣的任務可以通過Laravel 隊列來處理。由於隊列對象可能存儲在外部,它們也使用APP_KEY 進行簽名。

我們將簡要討論過去利用APP_KEY的方式和原因,以及當前最常用的利用方式。然後,我們將詳細討論通過Laravel隊列提供程序進行攻擊的情況,它允許攻擊者利用Laravel實例,甚至不需要APP_KEY。

Laravel隊列可以通過各種隊列提供程序實現,如Amazon SQS,Redis,local等,在我們的示例中,我們將重點討論如何利用在Amazon SQS中實現的隊列。

過去的攻擊媒介讓我們首先快速了解一下過去Laravel是如何通過不安全的反序列化被利用的。在5.6.30版本之前,Laravel默認對Laravel會話cookie進行序列化和反序列化。與許多其他語言一樣,這為反序列化攻擊打開了大門。

一旦攻擊者獲得對APP_KEY 的訪問權限,他們還可以將任意對象簽名或加密為cookie。攻擊者可以簡單地使用已知的PHP 小工具鏈(例如PHPGGC)創建一個惡意序列化對象,對惡意對象進行簽名,然後將其發送到會話cookie 的位置。 Laravel 試圖反序列化惡意製作的會話cookie,並觸發了小工具鏈的安全相關副作用(通常是RCE)。

在2018 年8 月發布的Laravel v5.6.30 之前,這種利用路徑是可能的。

負責解密cookie的代碼(Laravel 5.4)可以在以下中間軟件代碼片段中找到。中間軟件提取cookie,並將它們發送到加密器類進行解密。

1.png

乍一看,這段代碼似乎還不錯。然而,decrypt()函數有第二個默認參數unserialize=true(請參閱Laravel API 文檔),它定義了在解密過程中必須對傳遞的(加密的)值進行反序列化。

2.png

可以看到,解密後Laravel 嘗試反序列化攻擊者控制的cookie(惡意序列化對象),這會觸發PHPGGC 小工具鏈的安全相關副作用。現在cookie 處理行為已經改變,Laravel調用解密函數時無需對內容進行反序列化。這可以防止先前已知的帶有洩露APP_KEY 的簡單利用路徑:

3.png

目前的利用由於現在的利用並不那麼簡單,我們需要一些其他的攻擊媒介。

濫用其他不安全的“decrypt()”調用在理想的攻擊場景中,易受攻擊的Laravel 應用程序仍然會簡單地反序列化一個用戶控制的對象,該對象受APP_KEY 的篡改保護。當我們分析一些流行的Laravel 應用程序和擴展時,我們注意到一些開發人員犯了與Laravel 的會話cookie 相同的錯誤。因為“decrypt(…)”函數默認反序列化對象,所以開發人員很容易忽略將攻擊者控制的加密內容輸入其中,即使他們並不期望得到PHP對象。

例如,Laravel Package 的OPcache 就是這種情況,這是一個幫助開發人員處理PHP OPcache 的插件。該軟件包安裝了一個中間軟件控制器,用於處理對laravel-opcache 的所有請求。 opcache 處理程序通過提取和解密密鑰URL 參數來執行授權檢查。這是通過使用默認的“解密”函數而不禁用值的反序列化來完成的。在以下代碼片段的第13 行中,可以看到如何使用默認值$unserialize=true 解密密鑰值。

4.png

如果攻擊者知道APP_KEY ,他們可以通過以下方式利用易受攻擊的Laravel 實例:

1.創建惡意的序列化PHP對象;

2.使用洩漏的APP_KEY加密對象;

3.將有效負載發送到易受攻擊的opcache處理程序:https://

4.應用程序將嘗試不安全地解密攻擊者控制的對象。

利用Laravel 隊列以下漏洞利用路徑在Laravel 8 和Laravel 9.2.0 上進行了測試。

按照設計,Laravel 隊列需要在(外部)隊列提供程序中臨時存儲任務和對象。為了防止在靜止時被篡改,這些對象的部分簽名都是使用APP_KEY的。

在研究中,我們發現Laravel 在簽名驗證檢查之前不安全地處理隊列對象。這允許任何可以訪問配置隊列(例如AWS SQS 訪問)的攻擊者獲得遠程代碼執行,即使不知道APP_KEY。

要理解這個問題,我們需要對隊列對象結構有一個大致的了解。通常,隊列對象包含以下(對我們來說很重要)元素:

job -將作業排隊的類;

data -保存我們將執行的實際隊列命令的數據對象;

data.commandName -命令的名稱;

data.command -作為序列化對象的實際命令;

data.command.hash - data.command 的簽名,防止篡改。

5.png

命令對象包含一個哈希,它確保序列化的對像沒有被篡改。但是,由於哈希是序列化PHP 對象的一部分,因此只能在對象未序列化後執行此檢查。

因此,在執行對命令對象的非序列化調用時沒有事先進行任何驗證,這導致了不安全的反序列化漏洞。

隊列命令的不安全反序列化攻擊者可以通過將惡意作業注入Laravel 隊列來利用命令對象的不安全反序列化。

我們使用Laravel 框架本身實現了一個PoC 漏洞利用,這樣我們就可以輕鬆地重用該功能而無需大量複製粘貼。在Laravel 中,你可以使用dispatch 函數將對象分派到隊列中,如下面的代碼片段所示。

6.png

隊列對像在Illuminate 類Illuminate\Queue\Queue 中處理。此類處理隊列對象的創建,該隊列對象將被序列化並稍後發送到隊列中。出於利用目的,我們可以修復createObjectPayload() 函數。在修復的函數中,我們將合法的命令對象替換為惡意製作的序列化對象。

7.png

在示例中,我們使用了來自PHP 反序列化庫PHPGGC 的PendingBroadcast Gadget 鏈(Laravel/RCE9)。

特別是,我們使用了這個鏈,因為它在所有最近的Laravel版本中都有效,並且在鏈中使用了魔術方法__destruct。基於__toString 魔術方法的小工具鏈不起作用,因為Queue 處理程序從不將我們的惡意Queue 對像作為字符串處理,因此不會觸發這些鏈。

如果我們現在看一下作業對象,我們將在命令部分看到我們的反序列化小工具。因為我們以一種非常快速和不方便的方式替換了命令對象,所以對像沒有使用哈希簽名。然而,這無關緊要,因為一旦命令被反序列化,目標就會被利用。

微信截图_20220921100706.png

此時我們只需要等到目標處理隊列中的惡意作業即可。在此過程中,應用程序將嘗試通過從作業對像中反序列化命令對象來獲取命令對象。以下代碼片段顯示瞭如何在作業命令上調用反序列化函數。

請注意,Laravel 還允許用戶使用加密的命令對象。如前所述,加密或解密需要有效的APP_KEY 才能利用。但是,只要我們的命令以字符串O: 開頭(表示序列化PHP 對像中的“對象”),Laravel 將始終嘗試以明文形式反序列化我們的攻擊者控制的命令(第4-6 行)。

9.png

攻擊者控制的命令成功反序列化後,隊列例程繼續。稍後,Laravel 注意到命令對像沒有預期的格式。應用程序將拋出異常,然後嘗試清理無效的惡意對象。在清理過程中,我們的小工具鏈的魔術方法__destroy 被調用,攻擊者控制的命令touch /tmp\/pwnedThroughQueue 被執行。

10.webp.jpg

總而言之,Laravel 在調用對象的反序列化之前不會驗證隊列作業中的命令對象。因此,有權訪問隊列(SQS、Redis 等)的攻擊者可以在不知道APP_KEY 的示例中獲得RCE。如果攻擊者通過不公開APP_KEY 的漏洞獲得對隊列的訪問權限,則這種攻擊場景特別有趣。 (例如,隊列連接的硬編碼或易於猜測的憑據,或洩露的AWS 訪問令牌)。

利用由於隊列閉包的任意作用域此漏洞利用路徑也適用於Laravel 隊列閉包。閉包是“需要在當前請求週期之外執行的簡單任務”,它們允許攻擊者通過隊列執行任意PHP 代碼。

然而,在本例中,攻擊者需要訪問隊列和APP_KEY。如果Laravel 環境文件被公開,則通常會滿足這些條件,因為該文件包含所有必要的信息。與前面的示例不同,這種方法不依賴於反序列化,因此如果沒有可用的小工具鏈可用,它也可以工作。

如下所示,可以使用以下代碼片段將閉包分派到隊列中:

11.png

我們首先假設隊列閉包通常期望在用戶定義的類上運行,在用戶定義的作用域內,例如Podcast 類或Newsletter 類。此外,我們認為隊列閉包中的函數需要實際存在。然而,這兩個假設都是錯誤的。只要隊列關閉作業中的作用域存在,攻擊者就可以執行任意PHP 代碼。

作為概念證明,我們修改了現有的供應商類(在我們的攻擊者環境中)Illuminate\Cookie\Middleware\EncryptCookies 以包含我們的惡意sendMaliciousClosure() 函數。 EncryptCookies 類應該存在於所有Laravel 項目中,因此作用域應該始終存在。請注意,我們也可以通過反射手動更改前面提到的作業對象內的作用域。

首先,我們更改EncryptCookies 類,如以下代碼片段(第11-18 行)所示。這樣,我們定義了一個閉包,它只是調用shell_exec 來執行任意操作系統命令。然後這個閉包作為作業被分派到配置的Laravel 隊列中。

12.png

我們的惡意關閉可以通過我們自己的Laravel Artisan 命令發送,如以下代碼片段所示。請注意,我們在EncryptCookies 作用域內靜態調用函數sendMaliciousClosure。這很重要,因為此作用域也需要存在於目標應用程序中。

13.png

在作業調度期間,隊列閉包被創建並使用洩露的APP_KEY 簽名。下面我們可以看到存儲在隊列中的序列化作業。我們的SerializableClosure 可以在命令對像中找到。

當我們向隊列發送一個閉包時,所有需要的函數定義都包含在閉包中:

14.png

同樣,一旦目標應用程序檢索到隊列對象,它就會嘗試(不安全地)反序列化命令對象。完成此操作後,Laravel 使用APP_KEY 驗證哈希。驗證哈希後,Laravel 將嘗試解析作用域App\Http\Middleware\EncryptCookies。如果此作用域存在,則執行攻擊者控制的閉包或代碼。這可以立即得到驗證,因為攻擊者控制的echo 是從目標隊列工作人員的上下文中調用的。

15.webp.jpg

特別是考慮到閉包,值得一提的是,Laravel並不期望通過隊列接受什麼。開發人員唯一需要的設置是Laravel Queue的配置。一旦配置了這個隊列,Laravel就不會檢查它應該處理哪些隊列功能,而是Laravel 會嘗試處理它通過隊列提供的所有內容。該代碼不區分用於處理排隊閉包的隊列或應該只處理Newsletter 類對象的隊列。

開發工具包/測試環境為了驗證這些漏洞,我們創建了一個小型Laravel 測試和利用環境。

你可以按照以下步驟設置環境:

複製測試環境存儲庫:

16.png

手動安裝composer 依賴項(這應該不需要,但我們過去遇到了一些問題):

17.png

設置測試環境:

laravel_victim_app 和laravel_exploit_scope_app 需要有相同的APP_KEY;

laravel_queue_exploit_client_laravel_exploit_1 會有一個隨機的APP_KEY;

你可以在相應的.env 文件中編輯APP_KEY 變量;

所有三個環境文件都需要設置相同的AWS SQS。可以在此處找到有關如何設置的教程。

18.png

為了利用目標,應用程序需要監聽/工作配置的隊列。這可以使用以下命令完成:

微信截图_20220921100325.png

然後可以使用漏洞利用客戶端發送有效負載。以下命令會將作業發送到隊列中,這將利用命令的不安全反序列化:

微信截图_20220921100351.png

下一個命令將通過隊列閉包執行任意PHP 代碼:

微信截图_20220921100414.png

你將看到目標定期處理傳入隊列。成功的利用應該在目標文件系統的/tmp/目錄中創建文件:

22.png

如果你想檢查哪些代碼片段已更改,可以使用grep 查找字符串“惡意更改”(Malicious Changes),該字符串表示在客戶端中更改的代碼段。

23.png

創建惡意簽名URL另一個不太嚴重的利用場景可能是創建簽名URL。使用簽名URL,開發人員可以驗證請求的URL 是否未被篡改。這可以用於各種示例。 Laravel 在官方文檔中描述的一個示例是將簽名URL 用於“取消訂閱”鏈接。在本示例中,簽名鏈接通過驗證防篡改URL的簽名來防止用戶取消訂閱其他鏈接。

大多數示例中,與其他APP_KEY 攻擊向量相比,創建簽名URL 的影響相對較小。但是,讓開發人員依賴簽名URL 來彌補輸入驗證的不足也是可行的,例如防止SQL 注入或IDOR 漏洞。

從以下代碼示例中可以看出,簽名URL 創建過程非常簡單,可以在Laravel Artisan 命令中輕鬆創建:

24.png

總結雖然獲得對洩露的APP_KEY 的訪問權限不再是代碼執行的保證,但仍有許多攻擊場景可以將此目標存檔。

大多數示例中,洩露的APP_KEY 本身不足以利用應用程序。攻擊者總是需要額外的錯誤

0 Comments

Recommended Comments

There are no comments to display.

Guest
Add a comment...