Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 106 additions & 0 deletions src/mobile-pentesting/android-app-pentesting/webview-attacks.md
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,109 @@ webView.reload()

- To mitigate risks, **restrict JavaScript bridge usage** to code shipped with the APK and prevent loading JavaScript from remote sources. For older devices, set the minimum API level to 17.

#### Abusing dispatcher-style JS bridges (invokeMethod/handlerName)

A common pattern is a single exported method (e.g., `@JavascriptInterface void invokeMethod(String json)`) that deserializes attacker-controlled JSON into a generic object and dispatches based on a provided handler name. Typical JSON shape:

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

Risk: if 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
- Decompile and grep for `addJavascriptInterface(` to learn the bridge object name (e.g., `xbridge`).
- In Chrome DevTools (chrome://inspect), type the bridge object name in the Console (e.g., `xbridge`) to enumerate exposed fields/methods; look for a generic dispatcher like `invokeMethod`.
- Enumerate handlers by searching for classes implementing `getModuleName()` or registration maps.

#### 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 to exfiltrate the Chromium WebView cookie DB (session hijack):

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

Notes
- 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`
- The handler returns Base64; decode to recover cookies and impersonate the user in the app’s WebView profile.

Detection tips
- Watch for large Base64 strings returned via `evaluateJavascript` when using the app.
- Grep decompiled sources for handlers that accept `uri`/`path` and convert them to `new File(...)`.

#### Bypassing WebView privilege gates – endsWith() host checks

Privilege decisions (selecting a JSB-enabled Activity) often rely on host allowlists. A flawed pattern is:

```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
```

Equivalent logic (De Morgan’s):

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

This is not an origin check. Many unintended hosts satisfy the second clause, letting untrusted domains into the privileged Activity. Always verify scheme and host against a strict allowlist (exact match or a correct subdomain check with dot-boundaries), not `endsWith` tricks.

#### javascript:// execution primitive via loadUrl

Once inside a privileged WebView, apps sometimes execute inline JS via:

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

If an internal flow triggers `loadUrl("javascript:...")` in that context, injected JS executes with bridge access even if the external page wouldn’t normally be allowed. Pentest steps:
- Grep for `loadUrl("javascript:` and `evaluateJavascript(` in the app.
- Try to reach those code paths after forcing navigation to the privileged WebView (e.g., via a permissive deep link chooser).
- Use the primitive to call the dispatcher (`xbridge.invokeMethod(...)`) and reach sensitive handlers.

Mitigations (developer checklist)
- Strict origin verification for privileged Activities: canonicalize and compare scheme/host against an explicit allowlist; avoid `endsWith`-based checks. Consider Digital Asset Links when applicable.
- Scope bridges to trusted pages only and re-check trust on every call (per-call authorization).
- Remove or tightly guard filesystem-capable handlers; prefer `content://` with allowlists/permissions over raw `file://` paths.
- Avoid `loadUrl("javascript:")` in privileged contexts or gate it behind strong checks.
- Remember `setAllowFileAccess(false)` doesn’t protect against native file reads via the bridge.

#### JSB enumeration and debugging tips

- Enable WebView remote debugging to use Chrome DevTools Console:
- App-side (debug builds): `WebView.setWebContentsDebuggingEnabled(true)`
- System-side: modules like [LSPosed](https://github.com/LSPosed/LSPosed) or Frida scripts can force-enable debugging even in release builds. Example Frida snippet for Cordova WebViews: [cordova enable webview debugging](http://codeshare.frida.re/@gameFace22/cordova---enable-webview-debugging/)
- In DevTools, type the bridge object name (e.g., `xbridge`) to see exposed members and probe the dispatcher.


### Reflection-based Remote Code Execution (RCE)

- A documented method allows achieving RCE through reflection by executing a specific payload. However, the `@JavascriptInterface` annotation prevents unauthorized method access, limiting the attack surface.
Expand Down Expand Up @@ -393,6 +496,9 @@ xhr.send(null)
- [Samsung S24 Exploit Chain Pwn2Own 2024 Walkthrough](https://medium.com/@happyjester80/samsung-s24-exploit-chain-pwn2own-2024-walkthrough-c7a3da9a7a26)
- [Pwn2Own Ireland 2024 – Samsung S24 attack chain (whitepaper)](https://maliciouserection.com/2025/05/13/pwn2own-ireland-2024-samsung-s24-attack-chain-whitepaper.html)
- [Demonstration video](https://www.youtube.com/watch?v=LAIr2laU-So)
- [Account takeover in Android app via JSB – tuxplorer.com](https://tuxplorer.com/posts/account-takeover-via-jsb/)
- [LSPosed – systemless Xposed framework](https://github.com/LSPosed/LSPosed)
- [Frida codeshare: Cordova – enable WebView debugging](http://codeshare.frida.re/@gameFace22/cordova---enable-webview-debugging/)

{{#include ../../banners/hacktricks-training.md}}

Expand Down