aiohttp目錄穿越漏洞(CVE-2024-23334)分析

發布時間 2024-04-01

一、漏洞概述


aiohtp 是構建于 Python l/0 框架 AsyncI0 之上的開源庫,用于處理無需基于傳統線程網絡的大量并發HTTP請求。aiohttp支持HTTP客戶端、HTTP服務端、WebSocket客戶端、WebSocket服務端、服務端中間件等。aiohttp被廣泛使用,在網絡中有大量基于該框架開發的在線系統。

啟明星辰ADLab研究員在漏洞情報跟蹤中發現了aiohttp目錄遍歷漏洞(CVE-2024-23334),并對其進行了深入分析和驗證。


二、影響版本


受影響版本:<3.9.2,請相關用戶盡快升級到3.9.2及以上版本。


三、漏洞分析


該漏洞的關鍵信息如下[1]:

aiohttp is an asynchronous HTTP client/server framework for asyncio and Python. When using aiohttp as a web server and configuring static routes, it is necessary to specify the root path for static files. Additionally, the option 'follow_symlinks' can be used to determine whether to follow symbolic links outside the static root directory. When 'follow_symlinks' is set to True, there is no validation to check if reading a file is within the root directory. This can lead to directory traversal vulnerabilities, resulting in unauthorized access to arbitrary files on the system, even when symlinks are not present. Disabling follow_symlinks and using a reverse proxy are encouraged mitigations. Version 3.9.2 fixes this issue.


根據關鍵信息,定位到開發文檔的說明[2]:



根據文檔描述,follow_symlinks是一個設計上用于非生產環境的功能,并且已在文檔中明確提示啟用該功能是一個安全風險。


編寫如下的示例代碼,測試follow_symlinks的功能:



在static目錄下創建符號鏈接d,指向其它目錄d:\test(該目錄下存在測試文件123.txt)。



以follow_symlink=fasle的模式啟動測試webserver,訪問static/d/123.txt的結果如下所示(提示找不到文件):



以follow_symlink=true的模式啟動測試webserver,訪問static/d/123.txt的結果如下所示(成功讀取文件內容):



顯然,根據文檔的描述,如果follow_symlink=true且存在符號鏈接,結果就是程序的正常預期功能。那么,該功能是如何被認定成漏洞?


漏洞的關鍵信息[1]中有一句重要描述:漏洞不依賴于符號鏈接的存在性。但是,在請求路徑中使用不存在的符號鏈接,底層又如何能訪問到目標文件。


經過分析,發現底層處理請求的關鍵函數如下:



首先,獲取請求文件名(filename)。以 GET /static/d/123.txt為例,filename就是d/123.txt。


然后,把filename轉換為Path對象,并檢測該對象是否存在anchor屬性。如果存在,則拒絕訪問。在windows平臺上,anchor對象就是盤符(比如d:\)。因此,此處存在安全檢測,即不允許跨盤符訪問。比如GET /static/d:\test\123.txt,會被視作非法請求而拒絕:



再然后,把static目錄的Path對象和filename的Path對象做拼接,形成新文件路徑filepath。最后,讀取filepath的數據,并返回給客戶端。


顯然,如果filename包含不存在的符號鏈接,但能訪問到目標文件,那說明對象拼接產生了非預期的結果。由于Path對象是標準的python類,直接單獨進行測試。


(1)設定directory=c:\test , filename = d:\test\123.txt,拼接代碼和結果如下:



拼接結果指向目標文件d:\test\123.txt,但是fname包含anchor,無法通過前面的filename.anchor檢查。


(2)設定directory=c:\test , filename = ..\d:\test\123.txt,拼接代碼和運行結果如下:



拼接結果讀取到目標文件,且fname不包含anchor,能通過filename.anchor檢查。


(3)設定directory=c:\test , filename = ..\..\d:\test\123.txt,拼接代碼和運行結果如下:



拼接結果也讀取到了目標文件,且fname不包含anchor,能filename.anchor檢查。


因此,只要在filename之前加上..\就能直接引入盤符,違背原始功能設計中需要符號鏈接存在的限制,從而形成了可以讀取磁盤上任意文件的安全漏洞。


四、補丁分析


補丁關鍵代碼如下:



補丁的核心機制是:路徑拼接成unresolved_path后,首先調用normpath處理unresolved_path來形成normalized_path,然后判定normalized_path是否位于靜態目錄_directory之下。


單獨測試補丁機制的代碼和結果如下:



顯然,由于拼接后的路徑不是static目錄的子目錄,所以觸發了異常,導致后續代碼不再讀取拼接后路徑下的文件,從而導致了該漏洞不再存在。


補丁不影響aiohttp的符號連接支持,因為符號鏈接文件必須存在于static目錄之下。使用符號鏈接文件來處理static資源本身就是一個潛在的安全風險,開發者仍需要引起足夠的重視,謹慎使用該功能。