CVE-2016-0143漏洞分析算法
4月20日,Nils Sommer在exploitdb上爆出了一枚新的Windows內核漏洞PoC。該漏洞影響全部版本的Windows操做系統,攻擊者利用成功後可得到權限提高,微軟在4月補丁日修復了該漏洞。shell
Nils Sommer並無說明該漏洞爲什麼種類型的漏洞,咋看崩潰場景會認爲是NULL Pointer dereference或者UAF漏洞,粗略分析後,以爲是整數溢出漏洞,可是最後仍是將其定義爲特殊的NULL Pointer dereference漏洞。下面對漏洞成因進行簡單分析。函數
In xxxRealDrawMenuItem spa
崩潰的地方是在win32k!xxxRealDrawMenuItem函數內,在windbg中查看崩潰時的內存狀態:操作系統
崩潰上下文代碼的IDA截圖,將其命名爲過程A(最後說明時會用到): code
在crash以前,eax會和[ebp+arg_8]作有符號乘法,並將結果和ebx作比較,來肯定是否執行crash的指令。blog
此時的eax爲PoC中r.bottom和r.top運算後的結果,具體操做在win32k!xxxDrawMenuBarTemp內,算法爲:eax= r.bottom-r.top-1; 內存
[ebp+arg_8]爲PoC中的info.bmiHeader.biSize; it
PoC 給的值會讓"imul eax,[ebp+arg_8]"產生溢出,走向crash流程。這裏看起來是因爲整數溢出形成的漏洞,其實正常流程都會走這個流程的,這並非漏洞成因所在。io
所操做的ecx從[ebp+var_28]獲取,原始值爲1,[ebp+var_28]本應該爲DIBObject的地址,可是在爲其分配內存的函數win32k!SURFMEM::bCreateDIB中,並無爲其分配內存空間,漏洞的關鍵在這裏。
下面分析建立DIBObject失敗的緣由。
In SURFMEM::bCreateDIB
SURFMEM::bCreateDIB的函數調用棧:
xxxDrawMenuBarTemp
à GreCreateDIBitmapReal
àSURFMEM::bCreateDIB
在SURFMEM::bCreateDIB函數內有這樣一段代碼,將其命名爲過程B:
此時eax等於xxxRealDrawMenuItem函數中的edi,[ebp+arg_0]爲PoC中的info.bmiHeader.biSize*4,按照PoC中設定的值,二者分別爲0x7fffff69和0x274。
當二者進行乘法運算後,一樣發生了溢出,但因爲是無符號運算,因此edx!=0。調用函數ULongLongAdd後,[ebp+AllocationSize+4]=edx=139h!=0,所以便走向了失敗的流程,不會爲DIBObject分配內存,也致使GreCreateDIBitmapReal函數的返回值爲0。
若是未發生溢出,而且二者的乘積(+0x154)小於7FFFFFFFh, SURFMEM::bCreateDIB函數就會根據這個乘積(+0x154)爲DIBObject分配一塊內存。分配內存的代碼在IDA中的截圖:
分配成功後,會將AllocateObject的返回值做爲GreCreateDIBitmapReal函數返回值,而且賦值給xxxRealDrawMenuItem 函數中的[ebp+var_28]。
來看看微軟是怎麼來補這個漏洞的,補丁後的部分xxxRealDrawMenuItem函數代碼在IDA中的截圖:
能夠看到,補丁後,xxxRealDrawMenuItem函數在調用GreCreateDIBitmapReal函數後,對返回值作了檢查:若是返回值等於0,表示建立DIBObject失敗,則不會再進入到操做DIBObject的流程,也就是過程A中了。
目前尚未人公開本身的利用代碼,下面對該漏洞存在的可能利用方式作一個說明。
crash處是一個對ecx進行循環操做的代碼段,循環次數爲"imul eax,[ebp+arg_8]"的乘積。正常狀況下是對申請的DIBObject進行操做。
這個循環操做中,存在一個可控的寫入操做指令,在IDA中的截圖:
紅框中的指令就是所說的寫入操做指令,edx雖然經歷多條指令操做後才獲得,可是參與操做的都是ecx相關內存值,由於ecx也就是零頁地址的內容可控,因此edx也是可控的。
那麼理論狀況下,在win8以前的系統中,是能夠將這條指令操做轉變爲:
mov [HalDispatchTable+4],shellcodeAddress
以後用戶層再觸發一下就完成了提權。
通過深刻分析後,要觸發漏洞,r.bottom、r.top和info.bmiHeader.biWidth知足必定的約束就好了,不必定須要和做者給出PoC的數值徹底相同。r.bottom、r.top和info.bmiHeader.biWidth的值能知足下面兩個條件就能夠致使crash:
過程B和過程A要知足這兩個條件,具體狀況以下。
過程B
1. 過程B未發生溢出,而且乘積後的值 < 0x7FFFFFFF,形成AllocateObject調用失敗。
2. 過程B未發生溢出,而且乘積後的值 > 0x7FFFFFFF,不走調用AllocateObject的流程。
3. 過程B發生溢出,不走調用AllocateObject的流程。
過程A
1.未溢出。
2.溢出後的結果爲負數,而且改變sf位爲1(有符號數比較)。
根據上面分析給出的過程A和過程B會致使crash的狀況,這裏給出兩種具體的組合,有興趣的能夠修改原PoC中對應的值嘗試一下,都會crash的。
組合1
過程B狀況1+過程A的狀況1,兩個地方都沒有溢出,可是仍是crash了,也說明了不是整數溢出漏洞。
組合2
過程B狀況3+過程A狀況2:
by:會飛的貓轉載請註明:http://www.cnblogs.com/flycat-2016