HTTP.SYS 遠程執行代碼漏洞分析(MS15-034 )


  在2015年4月安全補丁日,微軟發布了11項安全更新,共修復了包括Microsoft Windows、Internet Explorer、Office、.NET Framework、Server軟件、Office Services和Web Apps中存在的26個安全漏洞。其中就修復了HTTP.sys 中一處允許遠程執行代碼漏洞,編號為:CVE-2015-1635(MS15-034 )。
      據稱,利用HTTP.sys的安全漏洞,攻擊者只需要發送惡意的http請求數據包,就可能遠程讀取IIS服務器的內存數據,或使服務器系統藍屏崩潰。
      根據公告顯示,該漏洞對服務器系統造成了不小的影響,主要影響了包括Windows 7、Windows Server 2008 R2、Windows 8、Windows Server 2012、Windows 8.1 和 Windows Server 2012 R2在內的主流服務器操作系統。

  1. 首先對補丁文件做了二進制比對

  以下是Windows 7 修復前后HTTP.SYS的變化。

  

  值得注意的經驗是,每個函數名中都有’range’。 這不禁讓我想起了之前Apache HTTPd ‘Range’ 頭漏洞, (參見RFC2616章14.35節)。

  漏洞數據由 ‘range’ 頭帶入已經毋庸置疑。 下面要做的是深入研究其產生的原因。如IDA 自動分析出的的HTTP!UlpParseRange 函數的調用關系圖所示:

  

  這里我使用Vmware搭建了一個未打補丁的Windows 7 SP1 作為測試目標,並且啟用了內核調試器, 對所有關鍵函數設置斷點,收集關鍵數據和內核信息。

  

  在斷點被觸發之后, 堆棧信息會被打印出來, 接着程序繼續執行.  我們使用了之前的Apache Rangedos 測試樣本針對目標服務器做了攻擊性測試, 調試器捕獲到了下面這些信息:

  

  標准的Apache RangeDos 腳本確實產生了效果,下面讓我們更進一步的來看一下 HTTP!UlpParseRange 函數的實現:

  

  在舊代碼的調試中發現函數在此處調用了一個很大的整數。

  

  而新版本的代碼調用了HTTP!RtlULongLongAdd 來檢查是否有整數溢出。 注意,這個HTTP.sys內的函數調用5個參數而不是3個參數。重復之前的測試腳本, 就會發現系統返回的錯誤代碼是0xC000000D(STATUS_INVALID_PARAMETER),而不再是STATUS_INTEGER_OVERFLOW 。

  修正之后的一個簡單的POC測試腳本如下(此腳本僅用來解析證明模塊內部對Range頭參數的解析過程)。

  

  接着讓我們在未打補丁的模塊上下斷點。

  

  非常明顯了。EAX 是0x7A69 (Poc中設置的range上限 31337), EDI 是0x539(Poc中設置的range下限 1337)。 在老代碼中,如果我們的下限是0,則上限不會做如此的改變。在上限非常大的時候(整數臨界值), 我們加1, 就會發生整數溢出。 HexRays 的輸出更加明了:

  *(_QWORD *)v18 = __PAIR__(v22, v23) – __PAIR__(v21, v20) + 1.讓我們來試試看。

  

  這時候可以看到上限已經非常的大了(0xFFFFFFFF)。代碼接着執行。

  We can see that EAX is predictably small now.  Now that we have some indication of what the pre-patch block is doing, let’s look at the patch again.

  最后EAX在加1之后溢出變成了0. 讓我們再看看打過補丁的模塊:

  使用同樣的手法, 我們得到了一個不同的錯誤信息. 有趣的是很多情況下都會產生這個錯誤信息(比如節點深度問題等)。但是我們的主要目標是判斷是否打補丁, 所以這個沒什么大礙. 現在讓我們回到系統是否打補丁的預判上.

  一種方法讓未打補丁的模塊返回STATUS_INVALID_PARAMETER錯誤信息的方法就是使下面代碼的關鍵處校驗失敗。

  使用調試器動態改變跳轉條件, 我們可以讓服務器返回下面這個有趣的頁面(手工內存補丁成功):

  打完補丁以后當你提交了包含非法range頭字段的http包的時候, 系統會報上面的錯誤。

  如果沒打補丁你看到的就是下面這樣:

  這就是判斷是否打了補丁的關鍵.

  打了補丁:  HTTP!RtlULongLongAdd在遇到非法range頭的時候會返回一個 STATUS_INVALID_PARAMETER 錯誤, 接着HTTP!UlpParseRang 產生一個”Invalid Header” 錯誤信息給客戶端.  

  打了補丁:  HTTP!UlpParseRange 返回 0, 接着產生一個 “Requested Range Not Satisfiable”.錯誤信息給客戶端.

 

2、漏洞測試腳本:

#sutff.py
import socket
import random
 
ipAddr = "這里填入檢測IP地址"
hexAllFfff = "18446744073709551615"
 
req1 = "GET / HTTP/1.0\r\n\r\n"
req = "GET / HTTP/1.1\r\nHost: stuff\r\nRange: bytes=0-" + hexAllFfff + "\r\n\r\n"
 
print "[*] Audit Started"
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect((ipAddr, 80))
client_socket.send(req1)
boringResp = client_socket.recv(1024)
if "Microsoft" not in boringResp:
                print "[*] Not IIS"
                exit(0)
client_socket.close()
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect((ipAddr, 80))
client_socket.send(req)
goodResp = client_socket.recv(1024)
if "Requested Range Not Satisfiable" in goodResp:
                print "[!!] Looks VULN"
elif " The request has an invalid header name" in goodResp:
                print "[*] Looks Patched"
else:
                    print "[*] Unexpected response, cannot discern patch status"

 

  一個簡單的檢測方法:

  curl http://xxx.com/ -H "Host: irrelevant" -H "Range: bytes=0-18446744073709551615"|grep "range is not satisfiable"

  有發現 返回”range is not satisfiable”就說明有漏洞了.

  3、修復方法

  修復相關漏洞,打漏洞補丁。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM