應用程序與文件系統的交互始終是高度安全敏感的,因為較小的功能漏洞很容易成為可利用漏洞的來源。這種觀察在web文件管理器的情況下尤其正確,其作用是復制完整文件系統的功能并以透明的方式將其公開給客戶端的瀏覽器。
elFinder 是一種流行的 Web 文件管理器,常用于 CMS 和框架,例如 wordPress/ target=_blank class=infotextkey>WordPress 插件 (wp-file-manager) 或 Symfony 包,以允許對本地和遠程文件進行簡單操作。在過去,elFinder一直是針對不安全配置或實際代碼漏洞的活躍攻擊的一部分。因此,elFinder的發布帶有一個安全的默認配置,以防止攻擊者進行任何惡意使用。
作為對廣泛部署的開源項目的定期評估的一部分,研究人員在elFinder中發現了多個新的代碼漏洞。在以下關于web文件管理器常見代碼漏洞的案例研究中,研究人員發現了五個不同的漏洞鏈,并演示了如何利用它們來獲得對底層服務器及其數據的控制。研究人員還將討論一些稍后由供應商實現的補丁,以展示如何在用戶的代碼中防止它們。
惡意影響
我們在開發分支上工作,提交 f9c906d。調查結果也在 2.1.57 版中得到證實;都影響默認配置(除非本文另有說明)并且不需要事先認證。正如研究人員所提到的,利用這些漏洞會讓攻擊者在安裝elFinder的服務器上執行任意php代碼,最終導致其受到攻擊。
研究人員在這篇文章中討論的發現均分配了 CVE-2021-32682,并成功地利用了這些發現來獲得代碼執行:
刪除任意文件;
移動任意文件;
PHP文件上傳;
參數注入;
競爭條件(Race Condition);
所有這些漏洞類在向用戶公開文件系統的軟件中都非常常見,并且可能影響到大量產品,而不僅僅是elFinder。
elFinder發布了2.1.59版本,以解決研究人員負責披露的所有bug。毫無疑問,這些漏洞也會被廣泛利用,因為針對舊版本的漏洞已經被公開發布,而連接器文件名是試圖破壞網站時要查找的路徑匯編的一部分。因此,研究人員強烈建議所有用戶立即將elFinder升級到最新版本。
技術細節
elFinder帶有一個用PHP編寫的后端(也稱為連接器)和一個用html和JAVAScript編寫的前端。連接器是將前端代碼的操作分派給右后端代碼以實現文件系統特性的主要腳本。連接器可以配置為禁止危險操作,將上傳限制為特定的 MIME 類型:默認安裝中有兩種不同的類型。研究人員在所謂的“最小”連接器中發現了漏洞。它只允許鏡像和純文本上傳,FTP是唯一支持的遠程虛擬文件系統:這可能是最安全的,也是最有可能部署的。
為了更好地理解研究人員將用來演示發現的代碼片段,研究人員將首先描述elFinder的路由是如何工作的。與許多現代PHP應用程序一樣,連接器(例如connector.minimal. PHP)是唯一的入口點。它聲明配置指令和閉包,然后實例化elFinder(核心)和elFinderConnector (elFinder和傳輸通道之間的接口,這里是HTTP)。
屬性elFinder::$commands包含了每個有效的操作和預期的參數:
php/elFinder.class.php
用戶可以通過PATH_INFO、GET或POST向cmd參數提供所需的命令參數來調用這些命令,在每個命令處理程序中,使用$args訪問參數。
為了允許遠程文件系統(FTP、Dropbox等)與本地文件系統一起使用,elFinder實現了一個文件系統抽象層(elFinderVolumeDriver) ,所有驅動程序都在該層之上構建。然后文件通過它們的卷名(例如t1_是垃圾,l1_是默認的本地卷)和url安全的名稱Base64來引用。
首先深入研究一個任意文件刪除漏洞鏈,它由兩個不同的漏洞組成。
刪除任意文件
PHP 核心不提供運行后臺線程或執行同步和進程間通信的有效方法。 elFinder 試圖通過大量使用臨時文件和請求后掛鉤來平衡這一點。例如,用戶可以通過調用同名方法來終止正在進行的操作:
php/elFinder.class.php
可以看到,[1]和[2]存在一個代碼漏洞:用戶控制的參數在沒有事先檢查的情況下被連接到一個完整的路徑中。對于[1],它最終會創建一個名稱完全可控的空文件,而在[2]中,它可以用來刪除任意文件。這兩個漏洞的SonarCloud漏洞都是可用的:[1]和[2]。
由 [1] 生成的文件名將以 elfreq 為前綴,在路徑遍歷攻擊中,如果路徑中的任何足跡不存在或不是目錄,POSIX系統將無法解析路徑。例如,解析/tmp/i_do_not_exist/../或/ tmp / i_am_a_file / . ./將分別在ENOENT和ENOTDIR中運行失敗。這個先決條件使得利用這兩個漏洞不可能按原樣進行,并且需要另一個漏洞,例如創建任意目錄的能力。
然后攻擊者可以查看命令mkdir并發現允許這種行為的原語,下面是它的頂層處理程序,出現在它通過文件系統抽象層之前:
php/elFinder.class.php
elFinderVolumeDriver 中存在一個通用實現來處理應該創建的卷和路徑。它將使用文件系統上的卷絕對路徑作為第一個參數和目標名稱作為第二個參數調用 [1] 中特定于卷的實現:
php/elFinderVolumeDriver.class.php
它的定義如下:
php/elFinderVolumeLocalFileSystem.class.php
elFinderVolumeLocalFileSystem::_joinPath() 只是將兩個值連接起來,導致路徑遍歷漏洞。這提供了在本地文件系統上創建任意空文件夾的原語。雖然本身不是漏洞,但它將允許利用上述漏洞。
同樣值得注意的是,rm命令中出現了完整路徑公開,公開給定文件在本地文件系統上的絕對路徑:
php/elFinderVolumeDriver.class.php
這個漏洞的影響很大程度上取決于環境:它可能與其他的elFinder漏洞結合在一起,用于在其他應用程序中觸發有趣的行為(例如刪除WordPress的wp-config.php文件以獲得代碼執行)或用于影響現有的安全措施(例如刪除.htaccess文件)。
通過改進
elFinderVolumeLocalFileSystem::_joinPath()的實現來斷言最終路徑不會在基路徑之外,這個漏洞已經被修復了。作為加固措施,還在代碼庫中添加了幾個對basename()的調用。
移動任意文件
相同的
elFinderVolumeLocalFileSystem::_joinPath() 方法用于其他操作,例如重命名:它結合了一個卷基本目錄和一個用戶提供的目標名稱。因此,它很容易受到研究人員剛才描述的漏洞的攻擊。
在執行所有負責解碼路徑并確保允許目標擴展名的代碼之后,
elFinderVolumeLocalFileSystem::rename()的實際實現如下面的代碼片段所示:
php/elFinderVolumeLocalFileSystem.class.php
雖然目標擴展名仍然受到 MIME 檢查的嚴格限制,但對于未經身份驗證的攻擊者來說,根據環境,通過覆蓋authorized_keys、composer.json 等文件,該原語足以在服務器上執行命令。這個漏洞已經用研究人員之前討論過的同一個補丁修復了。
上傳 PHP 文件
對于大多數PHP應用程序來說,elFinder面臨的最大威脅是攻擊者可以將PHP腳本上傳到服務器,因為沒有任何東西(除了經過加固的web服務器配置)可以阻止他們直接訪問它來執行它的內容。維護人員最初試圖通過制作一個將危險的MIME類型與相關擴展關聯起來的塊列表來防御:
php/elFinderVolumeDriver.class.php
在Ubuntu 20.10上的Apache HTTP 2.4.46-1ubuntu1的測試環境中,默認配置聲明 .phar 文件應該被視為 Application/x-httpd-php ([1]) 并被解釋為:
在Debian的穩定版本中也可以看到這種配置,雖然對文件的內容執行另一遍MIME類型檢測,因為PHP解釋器允許在解釋文件的任何地方使用語句(例如PHP可以放在一些虛擬數據之后),因此也可以很容易被繞過。
修復很簡單:它聲明 .phar 文件與默認情況下不允許的 MIME text/x-php 相關聯。
參數注入
在elFinder如此強大的默認功能中,用戶可以選擇多個文件,并使用zip、rar和7z等外部工具對它們進行壓縮。該函數在名為archive的操作下被發布:
php/elFinder.class.php
請注意,即使上傳文件被禁止,用戶也可以通過對現有文件調用archive命令來創建壓縮,該實現特定于正在使用的虛擬文件系統。研究人員只關注默認的命令行,因為它是由
elFinderVolumeLocalFileSystem繼承的,elFinderVolumeLocalFileSystem創建了完整的命令行([1]),并使用默認shell([2])執行它:
php/elFinderVolumeLocalFileSystem.class.php
name的值來自用戶控制的參數name的值來自用戶控制的參數_GET['name'],雖然使用escapeshellarg()正確地轉義以防止使用命令替換序列,但程序將嘗試將此值解析為標志 (--foo=bar),然后解析為位置參數。還值得注意的是,在選擇 ZIP壓縮程序的情況下,用戶的值以. ZIP作為后綴。
命令壓縮包實現了一個完整性測試特性(-T),可以與-TT一起使用該特性來指定要運行的測試命令。在本例中,它為攻擊者提供了一種使用此參數注入執行任意命令的方法。
為了能夠利用此漏洞,攻擊者需要創建一個虛擬文件(例如a.txt),將其壓縮以創建a.zip,然后以原始文件和壓縮為目標調用壓縮操作,使用的名稱如下: TmTT="$(id>out.txt)foooo"。
生成的命令行將是 zip -r9 -q '-TmTT="$(id>out.txt)foooo".zip' './a.zip' './a.txt',從而執行 id 并記錄其標準輸出到 out.txt,此文件將與 elFinder 界面中的其他文檔一起使用。
當需要修復這個漏洞時,壓縮操作不能很好的運行。通?;赑OSIX的方法,故不能在此處應用,因為zip將退出,并出現以下漏洞:
然后維護人員決定在壓縮名稱前加上 ./ 以防止任何參數注入的風險,他們還決定在同一個補丁中加強對其他壓縮程序(7z、rar等)的調用。
隔離和競爭條件
看看研究人員在這個案例研究中的最后發現,由于壓縮文件無法上傳,因此無法在默認配置中利用隔離特性中的此漏洞,由于設計特點,該函數可能會導致未來的安全問題。
隔離的基本原理是壓縮文件可能包含不需要的文件(主要是PHP腳本) ,如果沒有首先運行安全檢查(例如,使用 MIME 驗證),則不應在當前文件夾中提取這些文件。因此,elFinder選擇將壓縮文件提取到一個名為.quarantine的文件夾中,該文件夾位于files/文件夾下,
elFinderVolumeLocalFileSystem::_extract()為每個壓縮文件提取生成一個隨機的目錄名(位于[1]):
php/elFinderVolumeLocalFileSystem.class.php
這可以通過strace或inotify套件動態確認,例如這里有一個包含PHP文件的壓縮文件:
這個進程如下:
創建了一個名為
efbf975ccbac8727f434574610a0f1b6 的文件夾;
在
efbf975ccbac8727f434574610a0f1b6 中創建了一個名為 win.php 的文件;
數據被寫入win.php;
win.php被刪除;
efbf975ccbac8727f434574610a0f1b6被刪除;
如果服務器被配置為列出目錄,這個行為很容易被利用,因為可以在 MIME 驗證步驟和刪除它們之前訪問危險文件(例如 .php)。然而,如果無法以這種方式找到隨機目錄名稱,那么競爭條件窗口太小而無法考慮使用暴力破解的攻擊。
攻擊者可能會發現復制操作可用于內部文件夾,例如 .quarantine,并復制任何文件,而不管其內容如何。雖然它本身是一個無害的函數漏洞,但它可以與隔離函數鏈接在一起,以便在刪除之前復制包含研究人員提取的壓縮文件夾。復制的文件夾在界面中可見,并允許攻擊者繞過隨機名稱訪問惡意腳本,最終允許執行任意代碼。
作為修復措施,維護人員決定將.quarantine文件夾移到files/之外。
elFinderVolumeLocalFileSystem抽象層不知道此文件夾之外的任何內容,從而防止對.quarantine執行任何意外操作。
總結
在這個案例研究中,研究人員研究了在web文件管理器中常見的關鍵代碼漏洞。本文的研究證明無害的漏洞通常可以組合起來形成有害漏洞鏈,比如獲得任意代碼執行。研究人員認為,記錄和報告這些漏洞是很重要的,以緩解漏洞鏈,并減少類似漏洞的風險。