1. 程式人生 > 其它 >IE 11瀏覽器0day漏洞(CVE-2015-2425)UAF分析

IE 11瀏覽器0day漏洞(CVE-2015-2425)UAF分析

前言

CVE-2015-2425Hacking team洩露出來的一個IE110day漏洞,影響了IE11及之前的版本。在一封Hacking Team高層收到的來自Vectra Networks安全公司的信件中被發現。Vectra Networks公司的研究者在信中向Hacking Team提供了對於Windows 7/8.1最新版的IE11的poc程式碼。但Hacking Team並沒有購買,所以只洩露了poc,並沒有攻擊程式碼。

環境

測試環境是win8.132位,IE版本是IE11。

poc

poc.html:

把IE11附加到windbg上,然後執行poc.html,IE11崩潰到一個無法讀取的地址:

windbg+IDA分析

由於崩潰在一個不可訪問的地址,不好確定之前的指令,這時需要用到與棧回溯相關的命令,就是windbg中的k一系列命令:

每一行描述當前的一個棧幀,最上面的一行描述的是當前指令的返回地址:

由此可知崩潰的返回地址是63dfcf3c,在JavascriptFunction::CallFunction<1>中,看當前的esp也可以得出同樣的結論:

為了看到函式是怎麼呼叫的,需要用到.frame命令,使用.frame /c 1回到崩潰棧的第一層,也就是上層函式呼叫時的狀態:

看到回到了上層函式中,eip的值為崩潰處的返回地址,在反彙編視窗可以看到上層函式,也可以用u

命令:

產生崩潰的地方是63dfcf39call函式,呼叫的是[ebp-1Ch]處的函式指標,在IDA中看一下CallFunction<1>的定義:

這個函式是__fastcall方式呼叫的,__fastcall是一種快速呼叫方式,規定將前兩個引數由暫存器ecxedx來傳遞,其餘引數還是通過堆疊傳遞(從右到左),不同編譯器編譯的程式規定的暫存器不同。在Intel 386平臺上,使用ECXEDX暫存器。

往前找更改ebp-1Ch內容的指令,只有63dfcec6處的mov指令:

edx是函式的第二個引數,也就是一個函式指標,所以63dfcf39處的指令是呼叫了函式指標所指向的函式,這樣的話,還需要向上層看,到底是什麼樣的函式指標,回到上一層函式:

看到edx來源是[eax+0Ch],而eax的來源是[ebx+4]ebx來源於下面一句:

看一下這個函式的定義:

__thiscall為了解決類成員呼叫中this指標傳遞而規定的,__thiscall要求把this指標放在特定暫存器中,該暫存器由編譯器決定。VC使用ecx。所以這裡ecx裡的指標就是this指標。梳理一下這裡的過程:

推測這裡呼叫了某個物件的成員函式,而這個物件是JavascriptFunction物件。

弄清楚後我們回到崩潰點所在的函式內,選擇在call [ebp-1Ch]處下斷點,斷點會多次觸發,觸發5次後,停下,步入函式看:

63e0631b處的call後,eax就會變成一段已經釋放記憶體的地址,看到這句的jmp指令跳到了eax指向的值,把這段函式彙編看一下:

eax裡存放的應該是NativeCodeGenerator::CheckCodeGen的返回值,這次在這個函式上下斷點再次除錯,會觸發六次斷點,在返回前呼叫了NativeCodeGenerator::CheckCodeGenDoneeax置為了不可訪問的地址:

看看NativeCodeGenerator::CheckCodeGenDone,這次還在呼叫NativeCodeGenerator::CheckCodeGen上下斷點,六次斷點後進入CheckCodeGenDone,發現裡面還有一個call改變了eax的值,然後還有mov eax,edi:

再次用相同的方式除錯,這次進入ScriptFunction::UpdateThunkEntryPoint看看,這個函式如下:

63e06604mov語句改變了eax:

這個函式返回後有一個mov eax,esi的指令,但這裡edi值也已經是返回後eax的值了,看來還要追蹤edi,看一下CheckCodeGenDone函式:

edi是作為引數傳入UpdateThunkEntryPoint的,並且在函式內沒有被改變,那麼還要往回追蹤,經過回溯,從CheckCodeGenDone函式開頭開始跟,由於中間還有跳轉,所以edi的值還會改變,跟到edi變成崩潰時的返回地址時可以得出:

那麼還需要跟蹤一下esi,可以看到來自eax,而eax來自ecx:

所以ecx中是CheckCodeGen的第一個引數:

ScriptFunction物件,說明在最後一次呼叫CheckCodeGen前這個物件就已經被釋放了,用poi看看指標引用的過程,通過三次引用找到了那塊已經釋放的記憶體:

重啟後在第五次斷在63e0631b時,ebx指向了ScriptFunction物件,這時看一下觸發漏洞的指標,然後在第六次時看一下指標:

兩次指標並不相同,說明指標被改寫了一次,重新執行一樣在第五次斷點被觸發時看一下這裡的記憶體,此時還沒有被改寫:

在這裡可以下一個記憶體寫入斷點,看看什麼時候被改寫了:

真正的寫入發生在上一句mov語句,這時的esi05a49120eax05a50000:

eax裡的是上一個call的返回值,也就是InterpreterThunkEmitter::GetNextThunk的返回值,這次在63e06cd7下斷點,會觸發五次,最後一次時步入函式:

由於這個函式是__thiscall,所以ecx就是this指標,63e06df5就是把類的一個成員賦給了eax

為IE開啟堆頁,命令是:

再次下斷點除錯,看看這裡堆的情況:

這時eax指向的內容還沒有被釋放,是一段函式程式碼:

那我們要找到這段記憶體是如何釋放的,還是回到63e06cd7斷點處,這次不進入函式,步過後那段記憶體並沒有被釋放,為了弄清楚在哪裡被釋放,給this指標和那段uaf的記憶體下訪問斷點:

斷點觸發時,09f90000還沒有被釋放,函式返回時已經被釋放了,記憶體就是用FreeAllocations來釋放,在EmitBufferManager類中還有NewAllocation函式,應該是分配記憶體的函式。

總結

所以漏洞的成因應該是在記憶體被FreeAllocations釋放後又在JavascriptFunction::CallFunction<1>中使用而造成的UAF。由於這個漏洞的返回地址不可控,所以要用堆噴的方法的話可能還需要結合其他方法來繞過DEPASLR。