About addJavascriptInterface abuse in Android Browsers

So I started out writing this post like most of the other posts I've been writing this year, just another rash vulnerability disclosure; but I decided to turn it into more of a discussion about the addJavascriptInterface vulnerability.

I base my discussions here on some vulnerabilities I've found in various Android Browser apps. I'm going to specifically talk about some novel methods I used to enumerate Browser applications using JavaScript bridges insecurely. Obviously, in finding out how to detail the existence of the vulnerability you will also learn how to protect your applications from the discussed exploitation methods.

Find the vulnerability

Detailing the existence of the JavaScript bridge in most cases is pretty easy, all you do is run a grep match for the usage of the bridge in one of the local html files packaged with the application---granted, this will not always work for all apps but it does spot quite a number of them I busy working a drozer module to do this currently. This method assumes that there are easily identifiable usages of the JS bridge inside the application.

Usually browser apps like using customized "home"  and "settings" like pages that are integrated with powerful features like JavaScript bridges and Custom WebChromeClient/WebViewClient overrides for page event handling through native call backs.

These static HTML pages often appear inside the applications assets directory as detailed in the following screenshot:

If you manage to get results similar to these, you then have enough grounds to start looking at the actual application source to find references of its usage inside the native code.

You can also run this against a large number of apps ofcourse if your interested in collecting a count of the usage of JS bridges. Here's one I often use to check for new mentions of the vulnerability after swiping some apps from the play store:
for dex in `find . -type f -name *.dex -print `; do echo "[*] $dex"; strings $dex | grep -oE window\\.[a-zA-Z0-9]*\\.*; done

So greps aside, what you have now is two usages of the addJavaScriptinterface functionality, your final few checks for exploitability will involve how the affected interface is used. Whats required is that the affected WebView be within the attackers scope of influence to the extent that an attacker can effectively control the javascript being executed inside the WebView's worker thread. There are a number of situations in which this can arise:

  1.  Direct control of the URLs stuffed into loadUrl calls: You can identify this by grepping for the loadUrl API call and tracing back the parameter to the inputs on the application. What you should be looking for is a paramter passed to the loadUrl call that is sourced from an intent, TextView, EditViews or any input field users can control.
  2. Partial influence of WebView active JavaScript: Injection into the JavaScript URLs, this seems like it would be pretty common especially if the application makes prolific use of the DOM and URL fragments to source vectors for "homepage" or "aboutpage"  navigation. Basically what I'm saying is you may be able to exploit the issue if you can augment/modify the JS strings being stuffed into loadURL calls. Look for "home" and "about" pages sourcing URL fragments for input to loadURL calls in Browsers.
  3. SSL usage and implementation issues: Often applications will trade-off the SSL overhead for fast easy HTTP based connections to ad services or JavaScript libraries. There is also the common case of insecurely implemented SSL services---self signed, outdated and incorrectly configured certificates. In these cases exploiting is as simple as MITMing the HTTP connection being made and pointing it to a malicious JS page.
Another important "exploitability factor" involves the API level this application is targeted at, namely attribute values set in the <uses-sdk> element in the AndroidManifest.xml. According to the detail surrounding the addJavascriptInterface method on the Android Developers site:

This allows the Java object's methods to be accessed from JavaScript. For applications targeted to API level JELLY_BEAN_MR1 and above, only public methods that are annotated with JavascriptInterface can be accessed from JavaScript. For applications targeted to API level JELLY_BEAN or below, all public methods (including the inherited ones) can be accessed, see the important security note below for implications.
an extract from  http://developer.android.com/reference/android/webkit/WebView.html#addJavascriptInterface%28java.lang.Object,%20java.lang.String%29

Basically what this means is if you're looking for the presence of this protection you need to make sure that the targetSdkVersion, maxSdkVersion and minSdkVersion don't indicate any version that includes API levels before and including JELLY_BEAN_MR1.

So there is some level of control for devices above JELLY_BEAN_MR1, namely the requirement that the Annotation be present for the accessible methods. You can find out more about these changes in the commit log for the affected jelly bean version. Here's a quick summary of what changed:

diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index a2c1575..d23f52c 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -55,6 +55,7 @@
 import android.net.Uri;
 import android.net.http.SslCertificate;
 import android.os.AsyncTask;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -4119,10 +4120,17 @@
         WebViewCore.JSInterfaceData arg = new WebViewCore.JSInterfaceData();
-        // TODO in a separate CL provide logic to enable annotations  
for API level JB_MR1 and above.
         arg.mObject = object;
         arg.mInterfaceName = name;
-        arg.mRequireAnnotation = false;
+        // starting with JELLY_BEAN_MR1, annotations are mandatory for  
enabling access to
+        // methods that are accessible from JS.
+        if (mContext.getApplicationInfo().targetSdkVersion >=  
+            arg.mRequireAnnotation = true;
+        } else {
+            arg.mRequireAnnotation = false;
+        }
         mWebViewCore.sendMessage(EventHub.ADD_JS_INTERFACE, arg);
In the above code dump, I've highlighted the most important part, namely the code that indicates that Annotations are now required for a method to actually be reachable form the JSbridge. You can also see how this strictly depends on the Android version hosting the application.


Of course the quickest way to check for exploitability will always be simply list all the possible JS bridges, and try to use them in a payload by either intercepting all the HTTP and insecure SSL traffic and injecting something like this:

function execute(cmd){
  return window.AppsgeyserJSInterface.getClass().forName('java.lang.Runtime')\
execute(['/system/bin/sh','-c','echo \"PWNAGE\" > /data/data/com.Browser1XTRA/files/pwned.txt']);
execute(['/system/bin/sh','-c','echo \"PWNAGE2\" > /data/pwned.txt']);

This is a PoC for the 1XTRA Browser version 1.0  which simply tries to exploit the vulnerability to write to the internal storage of the applicaiton. This is something that should not require any special permissions to pull off since it happens at native level and is executed within the application that, by default has access rights to the /data/data/ directory named for it. If it works you should see something like this:

Some epic new things to try

  • Develop low false positive methods to detect instances of the vulnerability. I'm currently looking at developing a collection of drozer modules to aid detection on devices.
  • Develop a traffic analysis method to detect applications hosted on Android devices on the network suffering from this vulnerability, this would practically involve packet analysis and maybe analysis of the DNS lookups being performed---its easy to pick up possibly vulnerably ad services being used. This tech would be awesome for MDM solutions and IDS/IPSs.