MS15-034/CVE-2015-1635 HTTP.SYS 漏洞分析
前言
在4月的補丁日,微軟透過標記為“高危”的MS15-034補丁,修復了HTTP.SYS中一處遠端程式碼漏洞CVE-2015-1635。據微軟公告(https://technet.microsoft.com/en-us/library/security/MS15-034)所稱,當存在該漏洞的HTTP伺服器接收到精心構造的HTTP請求時,可能觸發遠端程式碼在目標系統以系統許可權執行。
這是對於伺服器系統影響不小的安全漏洞,任何安裝了微軟IIS 6.0以上的Windows Server 2008 R2/Server 2012/Server 2012 R2以及Windows 7/8/8.1作業系統都受到這個漏洞的影響。
從微軟的公告致謝來看,這個漏洞是由“Citrix Security Response Team”(美國思傑公司的安全響應團隊)發現,從網上公開的資訊來看,Citrix公司是一家從事雲端計算虛擬化、虛擬桌面和遠端接入技術領域的高科技企業。這也引發了Twitter上很多關於該漏洞是否是由針對Citrix公司的APT攻擊中發現的疑問,而就在微軟釋出補丁的不到12個小時內,便有匿名使用者在Pastebin網站上貼出了針對這個漏洞可用的概念驗證攻擊程式碼,似乎也印證了這一點。
筆者和360Vulcan的小夥伴們獲得該資訊後,就開始針對其進行深入的分析,並在12小時內初步分析清楚了漏洞的原理和利用相關資訊,下面就將我們分析的一些結果分享給大家,以便更好地促進安全社群理解和防禦這一高危安全漏洞。
漏洞重現
結合Pastebin網站上貼出的資訊(http://pastebin.com/ypURDPc4)和微軟公告,我們知道這是一個位於HTTP.SYS中的整數溢位漏洞,根據Pastebin網站的python程式碼,我們知道透過給IIS伺服器傳送這樣格式的HTTP請求,就可以觸發(檢測)這個漏洞:
GET / HTTP/1.1
Host: stuff
Range: bytes=0-18446744073709551615
我們直接使用wget或curl工具,也可以直接測試這個漏洞,例如使用如下命令列:
#!bash
wget 127.0.0.1 –debug –header="Range: bytes=0-18446744073709551615"
此處18446744073709551615轉為十六進位制即是 0xFFFFFFFFFFFFFFFF(16個F),是64位無符號整形所能表達的最大整數,那麼我們很容易可以想到,這個“整數溢位”必然同這個異常的超大整數有關。
Pastebin上POC的作者提供的檢測工具程式碼認為,如上請求包,若IIS伺服器返回“Requested Range Not Satisfiable”,則是存在漏洞,否則如果返回”The request has an invalid header name“,則說明漏洞已經修補。
在實測中可能很多人也會發現並非如此,針對不同的伺服器,這個測試程式很可能導致伺服器直接BSOD甚至直接引發VM程式Crash(對於虛擬主機),這是為什麼呢?這究竟是發生在何處的什麼原因的整數一處呢?在下面的小節中我們將會進一步講到。
漏洞原理分析
HTTP.SYS是微軟從IIS6.0開始,為了在Windows平臺上最佳化IIS伺服器效能而引入的一個核心模式驅動程式。它為IIS及其他需要運用HTTP協議的微軟伺服器功能提供HTTP請求的接收與響應、快速快取、提高效能、日誌等功能服務。
更多關於HTTP.SYS的資訊,可以參考微軟Technet Library中”IIS 6.0 Architecture”中的“HTTP Protocol Stack”一章(https://technet.microsoft.com/en-us/library/cc739400(v=ws.10).aspx)。 HTTP.SYS提供了兩個最重要的功能是Kernel-mode caching 和Kernel mode request queuing,而本次的安全漏洞就出在Kernel mode caching(核心模式快取)中。
這裡筆者以Windows 8.1 X86平臺上安裝的IIS 8.5為例進行分析講解,這裡我們分析的存在漏洞的HTTP.SYS版本號為6.3.9600.16520,修補後的http.sys版本為6.3.9600.17712
Pastebin上POC程式碼的匿名作者提到,補丁修補了http!UlpParseRange函式,透過RtlUlonglongAdd函式實現了修補/攔截。
從測試程式碼和函式名上,我們都可以看出這個漏洞同HTTP頭中的”Range“域有直接的關係, Range請求是HTTP協議中HTTP客戶端用於只獲取伺服器上檔案的某一部分資料的請求域,更多關於Range請求的細節和規範,可以參考RFC 7233 “Hypertext Transfer Protocol (HTTP/1.1): Range Requests”(http://www.rfc-editor.org/rfc/rfc7233.txt)。
這裡先簡單介紹一下http.sys快取工作的原理,IIS程式w3wp.exe接收到HTTP請求後,將資料快取到核心中,並整合HTTP回應頭,最後由http.sys組織資料包經由網路核心元件傳送出去。請求中包括Ranges物件的指定範圍,而快取中則包含了http檔案和大小資訊等。
我們接下來先來看看這個UlpParseRange函式,看他是否是這個漏洞的根本原因。
UlpParseRange的整個程式碼比較長,這裡就不全部貼出了,函式的邏輯很簡單,就是從Range bytes=lower-upper
(也可以是lower-或-upper形式)中,解析出lower(即讀取範圍的開始offset)和upper(即讀取範圍的結束offset)),然後計算要讀取的長度,在正常的情況下,upper大於lower,因此長度=upper-lower +1
這裡如果是測試程式碼中的例子,lower=0 ,upper=0xFFFFFFFFFFFFFFFF
我們看看未修補前的程式碼是怎麼樣寫的
#!bash
PAGE:0009AD2C sub eax, edx
PAGE:0009AD2E sbb ecx, edi
PAGE:0009AD30 add eax, 1
PAGE:0009AD33 mov [esi], eax
PAGE:0009AD35 adc ecx, ebx
PAGE:0009AD37 mov [esi+4], ecx
透過彙編程式碼我們可知,這裡是將upper先減去lower,再加1,得到兩者之間的長度差距(例如 bytes=20-50, 則50-20+1 , 兩者之間有31個位元組)
按照例子裡的寫法,就是0xFFFFFFFFFFFFFFFF – 0 + 1
, 確實發生了整數溢位,64位無符號整數上溢為0。
我們來看修改後的版本:
#!bash
PAGE:0009B501 push ebx
PAGE:0009B502 sub eax, edx
PAGE:0009B504 push 1
PAGE:0009B506 sbb ecx, edi
PAGE:0009B508 push ecx
PAGE:0009B509 push eax
PAGE:0009B50A mov ecx, esi
PAGE:0009B50C call [email protected]
這裡的程式碼是將upper 先減去 lower,然後再用RtlUlonglongAdd 將結果同1相加,這裡RtlUlonglongAdd會做安全性檢查,如果相加結果溢位,則會返回STATUS_INTEGER_OVERFLOW.
由於測試程式碼中lower傳入的是0,所以這裡也發生了溢位並被捕獲、阻止,但如果lower != 0,這裡壓根就不會捕獲到整數溢位,這是怎麼回事呢?真正出現問題的地方是這裡嗎?
實際上,這可能是POC編寫者故意隱藏了一點關鍵細節: UlpParseRange透過操縱Range引數可以引發整數溢位,也確實被進行了修補,但是並非這個Range資料真正出現問題的地方。
我們進一步推測和分析,發現本次漏洞真正利用的地方,而是UlAdjustRangesToContentSize,這個函式用於最終修正Ranges中指定的StartingOffset和Length的合法性。
首先UrlpParseRange解析了Range引數並獲得StartingOffset和Length後,會將其儲存在http請求的物件中,而在解析到對應的快取後,對比Offset + Length的大小,是否超過要請求的快取檔案資料長度,如果超出了,就要把length裁剪為適合的長度,防止讀取超出的資料,見如下程式碼:
#!bash
PAGE:0007FD09 mov eax, [ebp+length_low]
PAGE:0007FD0C add eax, dword ptr [ebp+offset_low]
PAGE:0007FD0F mov dword ptr [ebp+offset_low], eax
PAGE:0007FD12 mov eax, [ebp+length_high]
PAGE:0007FD15 adc eax, dword ptr [ebp+offset_high] ;將Length + Offset
PAGE:0007FD18 cmp eax, esi ;esi = content length ,快取的實際資料長度,進行對比
PAGE:0007FD1A jb short loc_7FD30
PAGE:0007FD1C ja short loc_7FD23
PAGE:0007FD1E cmp dword ptr [ebp+offset_low], ecx
PAGE:0007FD21 jb short loc_7FD30
PAGE:0007FD23
PAGE:0007FD23 loc_7FD23:
PAGE:0007FD23
PAGE:0007FD23 sub ecx, [ebp+length_low] ;length = contentlength-offset
PAGE:0007FD26 mov eax, esi
PAGE:0007FD28 sbb eax, [ebp+length_high]
PAGE:0007FD2B mov [edx+4], eax
這裡我們看到是一處可利用的整數溢位,Length + offset
如果發生溢位,就會小於contentsize,這裡就會跳過這個”adjust”的過程,Length沒有得到任何處理和修正,我們成功控制了Length。
以例子中的數值為例, length + offset = (0xFFFFFFFFFFFFFFFF + 1 ) + 0 (這個+ 1是前面UlpParseRange新增的) = 0
,小於contentsize
而假設lower不為0,則結果 = lower ,只要結果小於contentsize,也是不會被adjust的。
也就是說,UlpParseRange處發生了整數溢位,而在此處導致了安全檢查的繞過,同時,如果lower != 0 ,UlpParseRange時不會被觸發整數溢位,而是應該在這裡得以觸發。
到這裡我們就弄清楚了這個漏洞的觸發流程和原理:
1.upper(range結束的offset) = 0xFFFFFFFFFFFFFFFF
時,UlpParseRange或UlAdjustRangesToContentSize會觸發整數溢位,導致繞過UlAdjustRangesToContentSize的Length檢查
2.Length 可控,但是Length = 0xFFFFFFFFFFFFFFFF – lower(range開始的offset)
, 且lower必須要小於要獲取目標檔案的資料長度contentlength。
BSOD的重現和原理
看到很多測試攻擊程式的研究人員都無法穩定重現BSOD,看Github上的討論,透過調整lower的數值,有些人可以打藍Server 2012 R2,有些人就不行,或者換個檔案就不行。
實際上,我們分析了這個漏洞的原理就可以很清楚的瞭解其中的規律了,首先一條原則是上面已經說到的lower不能大於請求的content length,例如假設請求iisstart.htm(648Bytes),lower就必須小於647。
同時,HTTP請求的處理實際是先透過w3wp發起的程式上下文內http先解析HTTP請求包,組合成緊湊的http回應包後,透過
UlSendData->UxTpTransmitPacket->UxpTpEnqueueTransmitPacket
排入佇列,然後再由UlSendCacheEntryWorker將其傳送出去,在這個過程中,如果range指定的資料開始offset小於緊湊的資料包頭部的總長度,那麼就不會觸發到後面繼續命中快取的處理。(range只允許對資料檔案記憶體指定,不能指定響應頭內的)
這裡我使用wget新增頭部的方式測試,回應包的長度應該是(針對Windows 8.1 X86)310個位元組,也就是說,lower必須大於等於310個位元組,其他的傳送還需要調整這個數值。
所以,針對iisstart.htm , lower >= 310 且 < 647 就可以穩定觸發BSOD了
進一步利用
這個漏洞難道只能BSOD嗎?說好的遠端程式碼執行呢?再深入看下漏洞觸發的細節,看上去似乎不能遠端程式碼執行,但是遠端讀取伺服器核心記憶體資料是有可能的。
在UlpSendCacheEntry->UlBuildFastRangeCacheMdlChain
中,http.sys會為HTTP回應頭和快取來源buffer/length(我們可控)建立MDL,那麼,對於我們的超長length,就會創造一個巨大的mdl,接著放入UxTpTransmitPacket的資料包物件中,透過tcpip->netio,最後解析MDL,將資料最終發出去。
此時是可以超過快取的空間,讀取快取記憶體往後的資料,如果快取記憶體後面是連續的0xffffffffffffffff – lower(4GB?)
左右核心記憶體(通常是X64),就有可能實現資訊洩露。
不過首先是很難有連續的4G記憶體,同時透過IIS也很難一下獲得如此多的資料,那麼只能設法降低這個記憶體要求:length = 0xFFFFFFFFFFFFFFFF – lower
,且lower < contetnlength才行,我們可以想辦法提高content length,達到降低Length的目的,例如在伺服器上尋找一個接近4GB大小的檔案:)
分析時間倉促,有任何進一步的利用和錯誤之處,歡迎討論指正。
相關文章
- MS15-034 HTTP.sys 遠端執行程式碼漏洞(原理掃描)/KB3021910、 KB2919355、KB3042553下載連結2024-11-08HTTP行程
- 【漏洞分析】KaoyaSwap 安全事件分析2022-08-28事件
- BlueKeep 漏洞利用分析2019-09-20
- XSS漏洞分析2017-11-27
- 漏洞分析 | Dubbo2.7.7反序列化漏洞繞過分析2020-07-02
- PfSense命令注入漏洞分析2020-08-19
- SSRF漏洞簡單分析2020-07-16
- JSON劫持漏洞分析2018-05-17JSON
- 從exp入手分析漏洞2016-07-26
- tp5漏洞分析2024-06-30
- ASP.NET Core 託管和部署(二)【HTTP.sys】2019-02-20ASP.NETHTTP
- 漏洞分析——變數缺陷漏洞及通用異常捕獲宣告缺陷漏洞2021-09-01變數
- 軟體漏洞分析技巧分享2020-08-19
- Java安全之Axis漏洞分析2021-11-26Java
- thinkphp3.2.x漏洞分析2024-06-30PHP
- 【漏洞分析】ReflectionToken BEVO代幣攻擊事件分析2023-05-09事件
- 某CCTV攝像頭漏洞分析2020-08-19
- Joomla 物件注入漏洞分析報告2020-08-19OOM物件
- CORS漏洞的學習與分析2020-04-18CORS
- Windows PrintDemon提權漏洞分析2020-05-25Windows
- Java安全之XStream 漏洞分析2021-07-22Java
- 【漏洞復現】Paraluni 安全事件分析2022-03-15事件
- Sunlogin RCE漏洞分析和使用2022-02-19
- 漏洞挖掘分析技術總結2014-03-22
- 網站漏洞修復服務商關於越權漏洞分析2022-07-15網站
- Apache Tomcat檔案包含漏洞分析2020-02-24ApacheTomcat
- 安卓Bug 17356824 BroadcastAnywhere漏洞分析2020-08-19安卓AST
- 某EXCEL漏洞樣本shellcode分析2020-08-19Excel
- Shellshock漏洞回顧與分析測試2020-08-19
- Android uncovers master-key 漏洞分析2020-08-19AndroidAST
- WordPress 3.8.2 cookie偽造漏洞再分析2020-08-19Cookie
- 關於libStagefright系列漏洞分析2020-08-19
- 漏洞掛馬網站趨勢分析2020-08-19網站
- WinRAR(5.21)-0day漏洞-始末分析2020-08-19
- [javaweb]strut2-001漏洞分析2022-01-16JavaWeb
- 從0開始fastjson漏洞分析2021-05-17ASTJSON
- CVE-2017-8890漏洞分析2018-08-15
- Log4j漏洞原始碼分析2021-12-14原始碼