Django < 2.0.8 任意URL跳轉漏洞(CVE-2018-14574)
漏洞分析
Django是一個開放源代碼的Web應用框架,由Python寫成。
在其默認配置下,如果匹配上的URL路由中最後一位是/,而用戶訪問的時候沒加/,Django默認會跳轉到帶/的請求中,(由配置項中的django.middleware.common.CommonMiddleware
、APPEND_SLASH
來決定)。
在path開頭爲//example.com
的情況下,Django沒做處理,導致瀏覽器認爲目的地址是絕對路徑,最終造成任意URL跳轉漏洞。
該漏洞利用條件是目標URLCONF
中存在能匹配上//example.com
的規則。
漏洞實現
進入Django的環境
docker -exec -it ID /bin/sh
查看/usr/src/app.py
文件
這也就是上文提到的中間件
進入/usr/local/lib/python3.7/site-packages/django/middleware
查看common.py文件
也就是這個中間件,一個類,類中有定義process_request,precess_response等方法
當我們發起請求時,會先進行檢查
當url不全時會調用request.get_full_path
函數,進入get_full_path_with_slash
返回一個完整的路徑,此時force_append_slash=True
查看/usr/local/lib/python3.7/site-packages/django/http/request.py中的get_full_path函數
當force_append_slash=True時會對path進行補全返回一個新的path,比如這裏會輸入
192.168.11.147:8000//baidu.com
返回新的path就是192.168.11.147:8000//baidu.com/
以//開頭的外部URL將由瀏覽器翻譯爲協議,通過絕對URL會實現url跳轉
response_redirect_class函數是HTTP跳轉的一個基類,圖中HttpResponsePermanentRedirect
是在/usr/local/lib/python3.7/site-packages/django/http/response.py
實現301跳轉的一個類
(我覺得再這樣下去就超出我的能力範圍了,response.py我猜又有大幾百行我怕眼花…)
大概知曉漏洞成因之後,抓包對響應頭分析一波,在Repeater模塊中發送//baidu.com相應包中實現跳轉
此後我們改成//baidu.com/
發現並沒有進行跳轉,個人淺顯理解是因爲不需要調用get_full_path函數
防禦
- 確保該函數中的所有URL都是相對路徑,即以單個“/”字符開頭的路徑
- 檢查重定向過程中HTTP請求頭部內的Referrer是否與域名匹配
- 增加一個編碼函數使其不能構成絕對路徑