來源:http://bbs.ichunqiu.com/thread-9823-1-1.html?from=ch
社區(qū):i春秋
時間:2016年8月10日
作者:MAX丶
大家肯定用過bugscan老板褲子里面經常出現這個漏洞提示。
【xxx存在http.sys遠程漏洞】今天我們來分析分析這漏洞如何存在的,據稱,利用HTTP.sys的安全漏洞,攻擊者只需要發(fā)送惡意的http請求數據包,就可能遠程讀取IIS服務器的內存數據,或使服務器系統(tǒng)藍屏崩潰。
根據公告顯示,該漏洞對服務器系統(tǒng)造成了不小的影響,主要影響了包括Windows 7、Windows Server 2008 R2、Windows 8、Windows Server 2012、Windows 8.1 和 Windows Server 2012 R2在內的主流服務器操作系統(tǒng)。
1. 首先對補丁文件做了二進制比對
以下是Windows 7 修復前后HTTP.SYS的變化。

值得注意的經驗是,每個函數名中都有’range’。 這不禁讓我想起了之前Apache HTTPd ‘Range’ 頭漏洞, (參見RFC2616章14.35節(jié))。
漏洞數據由 ‘range’ 頭帶入已經毋庸置疑。 下面要做的是深入研究其產生的原因。如IDA 自動分析出的的HTTP!UlpParseRange 函數的調用關系圖所示:

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

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

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

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

而新版本的代碼調用了HTTP!RtlULongLongAdd 來檢查是否有整數溢出。 注意,這個HTTP.sys內的函數調用5個參數而不是3個參數。重復之前的測試腳本, 就會發(fā)現系統(tǒng)返回的錯誤代碼是0xC000000D(STATUS_INVALID_PARAMETER),而不再是STATUS_INTEGER_OVERFLOW 。
修正之后的一個簡單的POC測試腳本如下(此腳本僅用來解析證明模塊內部對Range頭參數的解析過程)。

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

非常明顯了。EAX 是0x7A69 (Poc中設置的range上限 31337), EDI 是0x539(Poc中設置的range下限 1337)。 在老代碼中,如果我們的下限是0,則上限不會做如此的改變。在上限非常大的時候(整數臨界值), 我們加1, 就會發(fā)生整數溢出。 HexRays 的輸出更加明了:
*(_QWORD *)v18 = __PAIR__(v22, v23) – __PAIR__(v21, v20) + 1.讓我們來試試看。

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

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. 讓我們再看看打過補丁的模塊:

使用同樣的手法, 我們得到了一個不同的錯誤信息. 有趣的是很多情況下都會產生這個錯誤信息(比如節(jié)點深度問題等)。但是我們的主要目標是判斷是否打補丁, 所以這個沒什么大礙. 現在讓我們回到系統(tǒng)是否打補丁的預判上.
一種方法讓未打補丁的模塊返回STATUS_INVALID_PARAMETER錯誤信息的方法就是使下面代碼的關鍵處校驗失敗。

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

打完補丁以后當你提交了包含非法range頭字段的http包的時候, 系統(tǒng)會報上面的錯誤。
如果沒打補丁你看到的就是下面這樣:

這就是判斷是否打了補丁的關鍵.
打了補丁:??HTTP!RtlULongLongAdd在遇到非法range頭的時候會返回一個 STATUS_INVALID_PARAMETER 錯誤, 接著HTTP!UlpParseRang 產生一個”Invalid Header” 錯誤信息給客戶端.
打了補丁:??HTTP!UlpParseRange 返回 0, 接著產生一個 “Requested Range Not Satisfiable”.錯誤信息給客戶端.
下面給大家發(fā)一個檢測py腳本。
[Python]純文本查看復制代碼
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52importsocket
importrandom[/font][/color][/size]
[size=4][color=Red][font=微軟雅黑]
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"notinboringResp:
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"ingoodResp:
print"[!!] Looks VULN"
elif" The request has an invalid header name"ingoodResp:
print" Looks Patched"
else:
print"[/font][/color][color=Red][font=微軟雅黑] Unexpected response, cannot discern patch status"