Mobile VAPT Notes (iOS)
#
iOS Static Analysis
#Static Analysis
#Automated Analysis with MobSF
#Modern MobSF Setup and Usage:
## MobSF Docker (Recommended - Latest version, isolated environment)
# Pull latest image:
docker pull opensecurity/mobile-security-framework-mobsf:latest
# Run with persistent storage and optimized settings:
docker run -d \
--name mobsf \
-p 8000:8000 \
-v "$HOME/mobsf-data:/home/mobsf/.MobSF" \
-e MOBSF_ANALYZER_IDENTIFIER="com.mobsf.analyzer" \
--restart unless-stopped \
opensecurity/mobile-security-framework-mobsf:latest
# Access MobSF: http://localhost:8000
# Default credentials: mobsf / mobsf
# CRITICAL: Change default password immediately
docker exec -it mobsf python manage.py changepassword mobsf
# Alternative: Direct installation (for customization)
git clone https://github.com/MobSF/Mobile-Security-Framework-MobSF.git
cd Mobile-Security-Framework-MobSF
./setup.sh # Installs all dependencies
# Configure MobSF (optional):
nano MobSF/settings.py
# Key settings:
# - MALWARE_ANALYSIS = True # Enable VirusTotal integration
# - VT_API_KEY = "your_key" # VirusTotal API key
# - DOMAIN_MALWARE_SCAN = True # Scan domains
# - APKID_ENABLED = True # Better packer/protector detection
# Run MobSF:
./run.sh # Linux/macOS
# Or: python manage.py runserver 0.0.0.0:8000
Analyzing iOS Applications with MobSF:
## Method 1: Web Interface (Interactive)
# 1. Browse to http://localhost:8000
# 2. Drag and drop IPA file
# 3. Wait for analysis (2-10 minutes depending on app size)
# 4. Review comprehensive security report
# Method 2: REST API (Automation)
# Get API key: MobSF Web UI → API Docs → Generate Key
# Upload and analyze IPA:
curl -X POST http://localhost:8000/api/v1/upload \
-H "Authorization: YOUR_API_KEY_HERE" \
-F "file=@app.ipa"
# Response includes scan hash, use for retrieving results:
SCAN_HASH="abc123def456..."
# Get analysis report:
curl -X POST http://localhost:8000/api/v1/report_json \
-H "Authorization: YOUR_API_KEY_HERE" \
-H "Content-Type: application/json" \
-d "{\"hash\": \"$SCAN_HASH\"}" \
| jq . > mobsf_report.json
# Download PDF report:
curl -X POST http://localhost:8000/api/v1/download_pdf \
-H "Authorization: YOUR_API_KEY_HERE" \
-d "hash=$SCAN_HASH" \
-o report.pdf
# Automation script:
cat > analyze_with_mobsf.sh << 'SCRIPT'
#!/bin/bash
IPA_FILE="$1"
API_KEY="YOUR_API_KEY"
MOBSF_URL="http://localhost:8000"
if [ ! -f "$IPA_FILE" ]; then
echo "Usage: $0 <path_to_ipa>"
exit 1
fi
echo "[*] Uploading $IPA_FILE to MobSF..."
RESPONSE=$(curl -s -X POST "$MOBSF_URL/api/v1/upload" \
-H "Authorization: $API_KEY" \
-F "file=@$IPA_FILE")
SCAN_HASH=$(echo "$RESPONSE" | jq -r '.hash')
echo "[+] Scan hash: $SCAN_HASH"
echo "[*] Waiting for analysis to complete..."
sleep 30 # Wait for analysis
echo "[*] Retrieving report..."
curl -s -X POST "$MOBSF_URL/api/v1/report_json" \
-H "Authorization: $API_KEY" \
-H "Content-Type: application/json" \
-d "{\"hash\": \"$SCAN_HASH\"}" \
| jq . > "${IPA_FILE%.ipa}_mobsf_report.json"
echo "[+] Report saved: ${IPA_FILE%.ipa}_mobsf_report.json"
SCRIPT
chmod +x analyze_with_mobsf.sh
./analyze_with_mobsf.sh app.ipa
Key Areas to Review in MobSF iOS Report:
#1. Binary Analysis (Security Features):
## MobSF automatically checks for critical binary protections:
# PIE (Position Independent Executable) - ASLR:
# ✓ Expected: Enabled (PIE flag present)
# ✗ Risk: Disabled - Predictable memory layout, easier exploitation
# Stack Canaries (Stack Smashing Protection):
# ✓ Expected: Enabled (__stack_chk_guard, __stack_chk_fail symbols)
# ✗ Risk: Disabled - Buffer overflow vulnerabilities easier to exploit
# ARC (Automatic Reference Counting):
# ✓ Expected: Enabled (_objc_release, _objc_retain symbols)
# ✗ Risk: Disabled - Memory management issues, potential UAF vulnerabilities
# Binary Encryption (FairPlay DRM):
# App Store apps: cryptid = 1 (encrypted)
# Jailbroken dumps: cryptid = 0 (decrypted)
# Analysis requires decrypted binary
# Restricted/Banned APIs:
# MobSF flags usage of dangerous functions:
# - strcpy, strcat, sprintf (buffer overflows)
# - gets, scanf (unsafe input)
# - system, popen (command injection risks)
# - rand, random (weak randomness)
# Manual verification in MobSF report:
jq '.binary_analysis' mobsf_report.json
2. App Transport Security (ATS) Analysis:
## Critical: ATS weakening allows insecure HTTP connections
# MobSF checks Info.plist for:
# CRITICAL FINDING: NSAllowsArbitraryLoads = YES
# Risk: Allows all HTTP connections, defeats HTTPS-only policy
# HIGH FINDING: NSAllowsArbitraryLoadsInWebContent = YES
# Risk: WebViews can load HTTP content
# HIGH FINDING: NSAllowsLocalNetworking = YES
# Risk: Allows unencrypted local network connections
# MEDIUM: NSExceptionDomains with insecure settings
# Risk: Specific domains exempted from HTTPS
# Review ATS configuration in MobSF report:
jq '.app_transport_security' mobsf_report.json
# Example bad configuration:
{
"NSAppTransportSecurity": {
"NSAllowsArbitraryLoads": true // CRITICAL vulnerability
}
}
# Example acceptable exception (should be justified):
{
"NSAppTransportSecurity": {
"NSExceptionDomains": {
"legacy-api.example.com": {
"NSExceptionAllowsInsecureHTTPLoads": true,
"NSExceptionMinimumTLSVersion": "TLSv1.2"
}
}
}
}
3. URL Schemes and Deep Links:
## MobSF extracts custom URL schemes from Info.plist
# These are potential attack vectors for:
# - Deep link hijacking
# - Parameter injection
# - Unauthorized data access
# Review URL schemes:
jq '.urls' mobsf_report.json
# Example vulnerable URL scheme:
# myapp://webview?url=https://evil.com (open arbitrary URLs)
# myapp://profile?id=../../../etc/passwd (path traversal)
# myapp://pay?amount=1000000&account=attacker (parameter tampering)
# Testing URL schemes (documented in report):
# Use adb or direct testing on device
4. Permissions and Entitlements:
## MobSF analyzes Info.plist for privacy-sensitive permissions:
# HIGH RISK permissions (require justification):
# - NSCameraUsageDescription (Camera access)
# - NSMicrophoneUsageDescription (Microphone access)
# - NSLocationAlwaysUsageDescription (Background location)
# - NSPhotoLibraryUsageDescription (Photo access)
# - NSContactsUsageDescription (Contacts access)
# - NSCalendarsUsageDescription (Calendar access)
# Review permissions:
jq '.permissions' mobsf_report.json
# MobSF also extracts entitlements from binary:
# - keychain-access-groups (keychain sharing)
# - application-identifier
# - com.apple.developer.associated-domains (universal links)
# - com.apple.security.application-groups (app group sharing)
# Check for excessive or unnecessary permissions
5. Hardcoded Secrets Detection:
## MobSF scans for hardcoded sensitive data:
# API Keys and Tokens:
# - AWS keys (AKIA...)
# - Firebase: google-services.json/plist
# - API endpoints with embedded keys
# - OAuth client secrets
# Credentials:
# - Hardcoded passwords
# - Database credentials
# - Private keys (PEM, p12, etc.)
# URLs and Endpoints:
# - API base URLs
# - Admin panels
# - Debug/staging endpoints
# Review in MobSF report:
jq '.secrets' mobsf_report.json
jq '.urls' mobsf_report.json
# Common patterns flagged:
# - "password" : "hardcoded123"
# - "api_key" : "sk_live_abc123..."
# - "secret" : "confidential_data"
# - Regex matches for API keys, tokens, etc.
6. File and Database Analysis:
## MobSF identifies sensitive files in IPA:
# Databases:
# - *.sqlite, *.db (SQLite databases)
# - Core Data stores (*.momd, *.mom)
# - Realm databases (*.realm)
# Configuration files:
# - *.plist (preferences, configuration)
# - *.json (settings, API config)
# - *.xml (configuration data)
# Certificates and keys:
# - *.pem, *.crt, *.cer (certificates)
# - *.key, *.p12 (private keys)
# - *.keystore (Java keystores)
# Cache and logs:
# - Cache.db (WebKit cache)
# - *.log (log files with potential secrets)
# Review files:
jq '.files' mobsf_report.json
# Extract specific file types for manual review:
unzip app.ipa
find Payload/ -name "*.plist" -o -name "*.sqlite" -o -name "*.db"
7. Code Analysis and Vulnerabilities:
## MobSF performs static code analysis (SAST):
# Cryptography issues:
# - Weak algorithms (DES, RC4, MD5, SHA1)
# - Hardcoded encryption keys
# - ECB mode usage
# - Weak random number generation
# Insecure data storage:
# - NSUserDefaults for sensitive data
# - Unencrypted databases
# - Files in shared directories
# Insecure communication:
# - HTTP usage
# - Weak TLS configuration
# - Certificate validation bypasses
# WebView vulnerabilities:
# - JavaScript enabled
# - File access enabled
# - JavaScript bridges
# Review vulnerabilities:
jq '.code_analysis' mobsf_report.json
jq '.severity_count' mobsf_report.json # Count by severity
8. Third-Party Libraries and Components:
## MobSF identifies embedded frameworks and libraries:
# Security concerns:
# - Outdated libraries with known CVEs
# - Vulnerable SDKs
# - Unnecessary permissions from libraries
# Review libraries:
jq '.libraries' mobsf_report.json
# Common vulnerable libraries to check:
# - AFNetworking (check version)
# - Alamofire (check version)
# - Firebase SDK (check version)
# - Facebook SDK (known privacy issues)
# - OpenSSL (check version for Heartbleed, etc.)
# Cross-reference with CVE databases:
# https://www.cvedetails.com/
# https://nvd.nist.gov/
Manual Static Analysis
#Extract and Explore IPA Contents:
## Rename and extract IPA:
cp app.ipa app.zip
unzip -q app.zip
cd Payload/
# Find the .app bundle:
APP_NAME=$(ls -1 | grep ".app$" | head -1)
cd "$APP_NAME"
# Overview of IPA structure:
tree -L 2 # If tree is installed
# Or:
find . -maxdepth 2 -type d
# Key directories and files:
# - Info.plist (app configuration and metadata)
# - <AppName> (binary) (main executable)
# - Frameworks/ (embedded frameworks)
# - PlugIns/ (app extensions)
# - Assets.car (compiled asset catalog)
# - Base.lproj/ (base localization resources)
# - *.mobileprovision (provisioning profile)
# - embedded.mobileprovision (embedded provisioning)
# - SC_Info/ (Swift metadata)
# - *.storyboard (interface files)
# - *.plist (various configuration files)
Binary Protection Analysis:
## Identify main executable:
MAIN_EXEC=$(ls -1 | grep -v "\\." | head -1)
echo "Main executable: $MAIN_EXEC"
# Get file type and architecture:
file "$MAIN_EXEC"
# Expected: Mach-O universal binary with 2 architectures (arm64, armv7)
# Or: Mach-O 64-bit executable arm64
# 1. Check ASLR/PIE (Position Independent Executable):
otool -hv "$MAIN_EXEC" | grep PIE
# Expected output: PIE
# If missing: Binary is not position-independent (security risk)
# Alternative using jtool2 (modern alternative to otool):
# Install: brew install --cask jtool2
jtool2 --pages "$MAIN_EXEC" | grep PIE
# 2. Check Stack Canaries (Stack Protection):
otool -I -v "$MAIN_EXEC" | grep stack
# Expected: __stack_chk_guard and __stack_chk_fail symbols
# These indicate stack canary protection is enabled
# More detailed check:
nm "$MAIN_EXEC" | grep -E "stack_chk|stack_chk_fail"
# 3. Check ARC (Automatic Reference Counting):
otool -I -v "$MAIN_EXEC" | grep objc_release
# Expected: _objc_release, _objc_retain symbols present
# Indicates modern memory management
# More comprehensive ARC check:
nm "$MAIN_EXEC" | grep -E "objc_release|objc_retain|objc_autorelease"
# 4. Check Binary Encryption (FairPlay DRM):
otool -arch arm64 -l "$MAIN_EXEC" | grep -A5 LC_ENCRYPTION_INFO
# Key field: cryptid
# cryptid 1 = encrypted (App Store binary)
# cryptid 0 = decrypted (required for analysis)
# If encrypted, analysis is limited - must decrypt first
if otool -l "$MAIN_EXEC" | grep -q "cryptid 1"; then
echo "[!] Binary is encrypted - use frida-ios-dump to decrypt"
fi
# 5. Check for Weak Cryptographic Functions:
otool -I -v "$MAIN_EXEC" | grep -E "_CC_MD5|_CC_SHA1|_DES_|_RC4_|_CCCrypt"
# MD5, SHA1, DES, RC4 are considered weak
# Should use SHA256+, AES, modern algorithms
# Detailed crypto analysis:
nm "$MAIN_EXEC" | grep -i -E "md5|sha1|des|rc4" | sort -u
# 6. Check for Insecure Memory Functions:
otool -I -v "$MAIN_EXEC" | grep -E "_gets|_strcpy|_strcat|_sprintf|_vsprintf"
# These functions are buffer overflow risks
# Modern code should use safer alternatives (strlcpy, snprintf, etc.)
# 7. Check for Debugging Symbols:
otool -I -v "$MAIN_EXEC" | grep -E "_NSLog|_printf"
# Excessive logging may leak sensitive information
# Check if binary is stripped:
nm "$MAIN_EXEC" | wc -l
# Low count (< 100) indicates stripped binary
# High count indicates symbols present (easier to reverse)
# 8. Check for Anti-Debugging:
nm "$MAIN_EXEC" | grep -i -E "ptrace|sysctl|isatty"
# Presence suggests anti-debugging measures
# 9. Check Code Signing:
codesign -dv "$MAIN_EXEC" 2>&1
# Shows: Authority, TeamIdentifier, Sealed Resources
# Verify signature:
codesign --verify --verbose "$MAIN_EXEC"
# If valid: no output
# If invalid: error message
# 10. Extract entitlements:
codesign -d --entitlements - "$MAIN_EXEC" 2>/dev/null | xmllint --format -
# Shows app capabilities and permissions
# Alternative using jtool2:
jtool2 --ent "$MAIN_EXEC"
# 11. Modern security features check (iOS 15+):
# Pointer Authentication Codes (PAC):
otool -hv "$MAIN_EXEC" | grep -i "pac"
# If present: Enhanced exploit mitigation
# Control Flow Integrity (CFI):
# Check for __auth sections:
otool -l "$MAIN_EXEC" | grep -i "__auth"
Comprehensive Binary Analysis Script:
##!/bin/bash
# ios_binary_analysis.sh - Comprehensive binary security check
BINARY="$1"
if [ ! -f "$BINARY" ]; then
echo "Usage: $0 <binary_path>"
exit 1
fi
echo "======================================"
echo "iOS Binary Security Analysis"
echo "Binary: $BINARY"
echo "======================================"
echo
# File info
echo "[*] File Information:"
file "$BINARY"
echo
# Architecture
echo "[*] Architectures:"
lipo -info "$BINARY" 2>/dev/null || echo "Single architecture"
echo
# PIE/ASLR
echo "[*] PIE (ASLR) Protection:"
if otool -hv "$BINARY" | grep -q PIE; then
echo "✓ ENABLED"
else
echo "✗ DISABLED - SECURITY RISK"
fi
echo
# Stack Canaries
echo "[*] Stack Canaries:"
if nm "$BINARY" 2>/dev/null | grep -q stack_chk; then
echo "✓ ENABLED"
else
echo "✗ DISABLED - SECURITY RISK"
fi
echo
# ARC
echo "[*] ARC (Automatic Reference Counting):"
if nm "$BINARY" 2>/dev/null | grep -q objc_release; then
echo "✓ ENABLED"
else
echo "✗ DISABLED - Memory safety risk"
fi
echo
# Encryption
echo "[*] Binary Encryption:"
CRYPTID=$(otool -l "$BINARY" 2>/dev/null | grep cryptid | head -1 | awk '{print $2}')
if [ "$CRYPTID" = "1" ]; then
echo "✗ ENCRYPTED - Decrypt before analysis"
elif [ "$CRYPTID" = "0" ]; then
echo "✓ DECRYPTED - Ready for analysis"
else
echo "? UNKNOWN"
fi
echo
# Weak crypto
echo "[*] Weak Cryptography Functions:"
WEAK_CRYPTO=$(nm "$BINARY" 2>/dev/null | grep -i -E "md5|sha1|_des_|_rc4_" | wc -l)
if [ "$WEAK_CRYPTO" -gt 0 ]; then
echo "✗ FOUND ($WEAK_CRYPTO references)"
nm "$BINARY" 2>/dev/null | grep -i -E "md5|sha1|_des_|_rc4_" | head -5
else
echo "✓ NONE DETECTED"
fi
echo
# Insecure functions
echo "[*] Insecure Memory Functions:"
INSECURE=$(nm "$BINARY" 2>/dev/null | grep -E "gets|strcpy|strcat|sprintf" | wc -l)
if [ "$INSECURE" -gt 0 ]; then
echo "✗ FOUND ($INSECURE references)"
nm "$BINARY" 2>/dev/null | grep -E "gets|strcpy|strcat|sprintf" | head -5
else
echo "✓ NONE DETECTED"
fi
echo
# Symbols stripped
echo "[*] Symbol Information:"
SYMBOL_COUNT=$(nm "$BINARY" 2>/dev/null | wc -l)
if [ "$SYMBOL_COUNT" -lt 100 ]; then
echo "✓ STRIPPED ($SYMBOL_COUNT symbols) - Harder to reverse"
else
echo "✗ NOT STRIPPED ($SYMBOL_COUNT symbols) - Easier to reverse"
fi
echo
# Code signing
echo "[*] Code Signing:"
codesign --verify --verbose "$BINARY" 2>&1 | head -3
echo
# Entitlements
echo "[*] Entitlements:"
codesign -d --entitlements - "$BINARY" 2>/dev/null | xmllint --format - | head -20
echo
echo "======================================"
echo "Analysis complete!"
echo "======================================"
Usage:
#chmod +x ios_binary_analysis.sh
./ios_binary_analysis.sh Payload/Instagram.app/Instagram
iOS Info.plist and Configuration Analysis
#Info.plist Analysis
#Extract and Convert Info.plist:
## Info.plist is often in binary format, must convert to XML for readability
# Method 1: Using plutil (built-in on macOS)
plutil -convert xml1 Info.plist -o Info.xml
# Verify conversion:
file Info.xml
# Should show: XML 1.0 document text
# Method 2: Using plistutil (Linux alternative)
# Install: sudo apt install libplist-utils
plistutil -i Info.plist -o Info.xml
# Method 3: Using Python (cross-platform)
python3 << 'PYTHON'
import plistlib
with open('Info.plist', 'rb') as f:
plist = plistlib.load(f)
with open('Info.xml', 'w') as f:
plistlib.dump(plist, f)
PYTHON
# Pretty print for analysis:
plutil -p Info.plist | less
# Extract specific values:
plutil -extract CFBundleIdentifier raw Info.plist
plutil -extract CFBundleVersion raw Info.plist
plutil -extract CFBundleShortVersionString raw Info.plist
Critical Security-Relevant Info.plist Keys:
#1. App Transport Security (ATS) Configuration:
## Extract ATS configuration:
plutil -extract NSAppTransportSecurity json Info.plist 2>/dev/null || echo "ATS not configured"
# Search for dangerous ATS configurations:
grep -A 10 "NSAppTransportSecurity" Info.xml
# CRITICAL vulnerabilities to identify:
# CRITICAL: Global HTTP allowed
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/> <!-- CRITICAL: Disables ATS entirely -->
</dict>
# HIGH: WebView HTTP allowed
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoadsInWebContent</key>
<true/> <!-- HIGH: WebViews can load HTTP content -->
</dict>
# HIGH: Local networking unencrypted
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsLocalNetworking</key>
<true/> <!-- HIGH: Allows HTTP to local IP addresses -->
</dict>
# MEDIUM: Specific domain exceptions
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>legacy-api.example.com</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/> <!-- MEDIUM: HTTP allowed for specific domain -->
<key>NSIncludesSubdomains</key>
<true/> <!-- Applies to all subdomains -->
<key>NSExceptionMinimumTLSVersion</key>
<string>TLSv1.2</string> <!-- Minimum TLS version -->
<key>NSExceptionRequiresForwardSecrecy</key>
<false/> <!-- Disables Perfect Forward Secrecy -->
</dict>
</dict>
</dict>
# Secure ATS configuration (recommended):
<key>NSAppTransportSecurity</key>
<dict>
<!-- No NSAllowsArbitraryLoads -->
<!-- Specific exceptions only, with justification -->
<key>NSExceptionDomains</key>
<dict>
<key>api.example.com</key>
<dict>
<key>NSExceptionMinimumTLSVersion</key>
<string>TLSv1.3</string>
<key>NSExceptionRequiresForwardSecrecy</key>
<true/>
</dict>
</dict>
</dict>
# Automated ATS security check:
cat > check_ats.sh << 'SCRIPT'
#!/bin/bash
PLIST="$1"
echo "[*] Checking ATS configuration..."
if plutil -extract NSAppTransportSecurity.NSAllowsArbitraryLoads raw "$PLIST" 2>/dev/null | grep -q "1\|true"; then
echo "✗ CRITICAL: NSAllowsArbitraryLoads is enabled (HTTP allowed globally)"
elif plutil -extract NSAppTransportSecurity.NSAllowsArbitraryLoadsInWebContent raw "$PLIST" 2>/dev/null | grep -q "1\|true"; then
echo "✗ HIGH: NSAllowsArbitraryLoadsInWebContent is enabled (WebViews can use HTTP)"
elif plutil -extract NSAppTransportSecurity.NSAllowsLocalNetworking raw "$PLIST" 2>/dev/null | grep -q "1\|true"; then
echo "⚠ MEDIUM: NSAllowsLocalNetworking is enabled (local HTTP allowed)"
else
echo "✓ ATS appears properly configured"
fi
# Check for domain exceptions
if plutil -extract NSAppTransportSecurity.NSExceptionDomains json "$PLIST" 2>/dev/null; then
echo "⚠ Domain exceptions configured - review each for necessity"
fi
SCRIPT
chmod +x check_ats.sh
./check_ats.sh Info.plist
2. URL Schemes (Deep Links) Analysis:
## Extract URL schemes:
plutil -extract CFBundleURLTypes json Info.plist 2>/dev/null
# Search in XML format:
grep -A 15 "CFBundleURLTypes" Info.xml
# URL Scheme structure:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string> <!-- or Viewer -->
<key>CFBundleURLName</key>
<string>com.example.app.url</string>
<key>CFBundleURLSchemes</key>
<array>
<string>myapp</string>
<string>mycompany</string>
</array>
</dict>
</array>
# Extract all URL schemes:
plutil -extract CFBundleURLTypes json Info.plist 2>/dev/null | \
jq -r '.[].CFBundleURLSchemes[]'
# Or using grep/sed:
grep -A 2 "CFBundleURLSchemes" Info.xml | \
grep "<string>" | \
sed 's/.*<string>\(.*\)<\/string>.*/\1/'
# Common URL scheme vulnerabilities:
# 1. Generic/Collision-prone schemes:
# - "http", "https" (conflicts with Safari)
# - "file" (path traversal risks)
# - Common words like "app", "open", "view"
# 2. Dangerous URL handlers:
# - myapp://webview?url=https://evil.com (arbitrary URL loading)
# - myapp://file?path=/etc/passwd (path traversal)
# - myapp://execute?cmd=whoami (command injection)
# - myapp://sql?query=DROP TABLE users (SQL injection)
# Security testing for URL schemes:
# Create test URLs and open on device:
# xcrun simctl openurl booted "myapp://test"
# From computer (device connected):
idevice-app-runner -u <UDID> --url "myapp://profile?id=1"
# Via Safari on device:
# Type URL in address bar: myapp://action?param=value
# URL Scheme security checklist script:
cat > check_url_schemes.sh << 'SCRIPT'
#!/bin/bash
PLIST="$1"
echo "[*] Extracting URL schemes..."
SCHEMES=$(plutil -extract CFBundleURLTypes json "$PLIST" 2>/dev/null | \
jq -r '.[].CFBundleURLSchemes[]' 2>/dev/null)
if [ -z "$SCHEMES" ]; then
echo "✓ No custom URL schemes found"
exit 0
fi
echo "[!] Found URL schemes:"
echo "$SCHEMES" | while read scheme; do
echo " - $scheme://"
# Check for dangerous patterns
if echo "$scheme" | grep -qE "^(http|https|file|ftp)$"; then
echo " ✗ CRITICAL: Reserved scheme name (collision risk)"
fi
if [ ${#scheme} -lt 4 ]; then
echo " ⚠ WARNING: Very short scheme name (collision risk)"
fi
# Generate test URLs
echo " Test URLs:"
echo " $scheme://webview?url=https://evil.com"
echo " $scheme://file?path=../../../etc/passwd"
echo " $scheme://profile?id=1' OR '1'='1"
done
SCRIPT
chmod +x check_url_schemes.sh
./check_url_schemes.sh Info.plist
3. Universal Links (Associated Domains):
## Extract associated domains (Universal Links):
plutil -extract com.apple.developer.associated-domains json Info.plist 2>/dev/null
# Or from entitlements:
codesign -d --entitlements - Payload/*.app/* 2>/dev/null | \
grep -A 5 "associated-domains"
# Format:
<key>com.apple.developer.associated-domains</key>
<array>
<string>applinks:example.com</string>
<string>applinks:www.example.com</string>
<string>applinks:*.example.com</string> <!-- Wildcard subdomain -->
</array>
# Universal Links require apple-app-site-association file on server
# Verify AASA file exists:
curl https://example.com/.well-known/apple-app-site-association
# Or: curl https://example.com/apple-app-site-association
# Validate AASA format:
curl -s https://example.com/.well-known/apple-app-site-association | jq .
# Expected structure:
{
"applinks": {
"apps": [],
"details": [
{
"appID": "TEAM_ID.com.example.app",
"paths": [
"/articles/*",
"/products/*",
"NOT /admin/*"
]
}
]
}
}
# Security concerns:
# - Wildcard domain matching (*.example.com)
# - Overly broad path matching (/* allows all paths)
# - Misconfigured AASA file (allows unintended deep links)
# - HTTP AASA file (must be HTTPS)
4. Privacy-Sensitive Permissions (iOS 14+ Privacy Manifest):
## iOS 14+ requires usage descriptions for privacy-sensitive features
# Extract all NSUsageDescription keys:
plutil -p Info.plist | grep -i "UsageDescription"
# Critical permissions to check:
# Location (always high-risk):
plutil -extract NSLocationAlwaysAndWhenInUseUsageDescription raw Info.plist 2>/dev/null
plutil -extract NSLocationWhenInUseUsageDescription raw Info.plist 2>/dev/null
plutil -extract NSLocationAlwaysUsageDescription raw Info.plist 2>/dev/null
# Camera and Microphone:
plutil -extract NSCameraUsageDescription raw Info.plist 2>/dev/null
plutil -extract NSMicrophoneUsageDescription raw Info.plist 2>/dev/null
# Photo Library:
plutil -extract NSPhotoLibraryUsageDescription raw Info.plist 2>/dev/null
plutil -extract NSPhotoLibraryAddUsageDescription raw Info.plist 2>/dev/null
# Contacts and Calendar:
plutil -extract NSContactsUsageDescription raw Info.plist 2>/dev/null
plutil -extract NSCalendarsUsageDescription raw Info.plist 2>/dev/null
plutil -extract NSRemindersUsageDescription raw Info.plist 2>/dev/null
# Health and Motion:
plutil -extract NSHealthShareUsageDescription raw Info.plist 2>/dev/null
plutil -extract NSHealthUpdateUsageDescription raw Info.plist 2>/dev/null
plutil -extract NSMotionUsageDescription raw Info.plist 2>/dev/null
# Bluetooth:
plutil -extract NSBluetoothAlwaysUsageDescription raw Info.plist 2>/dev/null
plutil -extract NSBluetoothPeripheralUsageDescription raw Info.plist 2>/dev/null
# Face ID:
plutil -extract NSFaceIDUsageDescription raw Info.plist 2>/dev/null
# Speech Recognition:
plutil -extract NSSpeechRecognitionUsageDescription raw Info.plist 2>/dev/null
# Tracking (iOS 14.5+, critical for privacy):
plutil -extract NSUserTrackingUsageDescription raw Info.plist 2>/dev/null
# HomeKit:
plutil -extract NSHomeKitUsageDescription raw Info.plist 2>/dev/null
# Media Library:
plutil -extract NSAppleMusicUsageDescription raw Info.plist 2>/dev/null
# Local Network (iOS 14+):
plutil -extract NSLocalNetworkUsageDescription raw Info.plist 2>/dev/null
plutil -extract NSBonjourServices json Info.plist 2>/dev/null
# Comprehensive permission audit:
cat > audit_permissions.sh << 'SCRIPT'
#!/bin/bash
PLIST="$1"
echo "======================================"
echo "iOS Privacy Permission Audit"
echo "======================================"
echo
PERMISSIONS=(
"NSLocationAlwaysAndWhenInUseUsageDescription:Location (Always)"
"NSLocationWhenInUseUsageDescription:Location (When In Use)"
"NSCameraUsageDescription:Camera"
"NSMicrophoneUsageDescription:Microphone"
"NSPhotoLibraryUsageDescription:Photo Library"
"NSContactsUsageDescription:Contacts"
"NSCalendarsUsageDescription:Calendar"
"NSRemindersUsageDescription:Reminders"
"NSMotionUsageDescription:Motion & Fitness"
"NSHealthShareUsageDescription:Health (Read)"
"NSHealthUpdateUsageDescription:Health (Write)"
"NSBluetoothAlwaysUsageDescription:Bluetooth"
"NSFaceIDUsageDescription:Face ID"
"NSSpeechRecognitionUsageDescription:Speech Recognition"
"NSUserTrackingUsageDescription:App Tracking"
"NSLocalNetworkUsageDescription:Local Network"
)
for perm in "${PERMISSIONS[@]}"; do
KEY="${perm%%:*}"
NAME="${perm##*:}"
DESC=$(plutil -extract "$KEY" raw "$PLIST" 2>/dev/null)
if [ $? -eq 0 ]; then
echo "✓ $NAME:"
echo " Usage Description: $DESC"
# Check if description is generic/insufficient
if echo "$DESC" | grep -qE "^(App|Application|This app)"; then
echo " ⚠ WARNING: Generic description - Apple may reject"
fi
echo
fi
done
# Check for tracking (iOS 14.5+ requirement)
if plutil -extract NSUserTrackingUsageDescription raw "$PLIST" 2>/dev/null >/dev/null; then
echo "⚠ App requests tracking permission - ensure user consent"
else
echo "✓ No tracking permission requested"
fi
SCRIPT
chmod +x audit_permissions.sh
./audit_permissions.sh Info.plist
5. Dangerous Application Settings:
## Check for dangerous configuration flags:
# 1. UIFileSharingEnabled (iTunes File Sharing):
plutil -extract UIFileSharingEnabled raw Info.plist 2>/dev/null
# If true: App's Documents folder is accessible via iTunes/Finder
# Risk: Sensitive data exposure
<key>UIFileSharingEnabled</key>
<true/> <!-- HIGH RISK: Exposes Documents folder -->
# 2. LSSupportsOpeningDocumentsInPlace:
plutil -extract LSSupportsOpeningDocumentsInPlace raw Info.plist 2>/dev/null
# If true: Allows in-place document opening
# Risk: Path traversal, unauthorized file access
<key>LSSupportsOpeningDocumentsInPlace</key>
<true/> <!-- MEDIUM RISK: Document access -->
# 3. UISupportsDocumentBrowser:
plutil -extract UISupportsDocumentBrowser raw Info.plist 2>/dev/null
# If true: Enables document browser
# Risk: Broader file system access
# 4. UIRequiresPersistentWiFi:
plutil -extract UIRequiresPersistentWiFi raw Info.plist 2>/dev/null
# If true: Keeps WiFi active in background
# OPSEC: May indicate background data collection
# 5. UIBackgroundModes (background execution):
plutil -extract UIBackgroundModes json Info.plist 2>/dev/null
# Modes to investigate:
# - "location" (background location tracking)
# - "fetch" (background data fetching)
# - "remote-notification" (push notification handling)
# - "voip" (VoIP calling)
# - "audio" (background audio)
# - "bluetooth-central" (Bluetooth in background)
# - "bluetooth-peripheral" (Bluetooth peripheral)
<key>UIBackgroundModes</key>
<array>
<string>location</string> <!-- Background location -->
<string>fetch</string> <!-- Background refresh -->
<string>remote-notification</string>
</array>
# 6. Debug/Development flags (should NOT be in production):
plutil -extract ITSAppUsesNonExemptEncryption raw Info.plist 2>/dev/null
# If false: App uses encryption exempt from export compliance
# Should be properly justified
# Dangerous settings check script:
cat > check_dangerous_settings.sh << 'SCRIPT'
#!/bin/bash
PLIST="$1"
echo "[*] Checking for dangerous application settings..."
echo
# File sharing
if plutil -extract UIFileSharingEnabled raw "$PLIST" 2>/dev/null | grep -q "1\|true"; then
echo "✗ HIGH RISK: UIFileSharingEnabled - Documents folder exposed via iTunes"
else
echo "✓ File sharing disabled"
fi
# Document handling
if plutil -extract LSSupportsOpeningDocumentsInPlace raw "$PLIST" 2>/dev/null | grep -q "1\|true"; then
echo "⚠ MEDIUM RISK: LSSupportsOpeningDocumentsInPlace enabled"
fi
# Background modes
BG_MODES=$(plutil -extract UIBackgroundModes json "$PLIST" 2>/dev/null)
if [ $? -eq 0 ]; then
echo "⚠ Background modes enabled:"
echo "$BG_MODES" | jq -r '.[]' | while read mode; do
echo " - $mode"
if [ "$mode" = "location" ]; then
echo " ✗ WARNING: Background location tracking"
fi
done
else
echo "✓ No background modes enabled"
fi
echo
# Check for debuggable flag (shouldn't exist in Info.plist, but check)
if grep -q "debuggable" "$PLIST"; then
echo "✗ CRITICAL: Debuggable flag found - remove for production"
fi
SCRIPT
chmod +x check_dangerous_settings.sh
./check_dangerous_settings.sh Info.plist
6. Application Metadata Extraction:#
# Extract key application metadata for documentation:
# Bundle Identifier (unique app ID):
BUNDLE_ID=$(plutil -extract CFBundleIdentifier raw Info.plist)
echo "Bundle ID: $BUNDLE_ID"
# Display Name:
DISPLAY_NAME=$(plutil -extract CFBundleDisplayName raw Info.plist 2>/dev/null || \
plutil -extract CFBundleName raw Info.plist)
echo "Display Name: $DISPLAY_NAME"
# Version information:
VERSION=$(plutil -extract CFBundleShortVersionString raw Info.plist)
BUILD=$(plutil -extract CFBundleVersion raw Info.plist)
echo "Version: $VERSION (Build $BUILD)"
# Minimum iOS version:
MIN_IOS=$(plutil -extract MinimumOSVersion raw Info.plist 2>/dev/null || \
plutil -extract LSMinimumSystemVersion raw Info.plist 2>/dev/null)
echo "Minimum iOS: $MIN_IOS"
# Supported device families:
DEVICES=$(plutil -extract UIDeviceFamily json Info.plist 2>/dev/null)
echo "Device Families: $DEVICES"
# 1 = iPhone/iPod, 2 = iPad
# Supported orientations:
ORIENTATIONS=$(plutil -extract UISupportedInterfaceOrientations json Info.plist 2>/dev/null)
echo "Orientations: $ORIENTATIONS"
# Launch screen/storyboard:
LAUNCH=$(plutil -extract UILaunchStoryboardName raw Info.plist 2>/dev/null || \
plutil -extract UILaunchImages raw Info.plist 2>/dev/null)
echo "Launch: $LAUNCH"
# Status bar configuration:
STATUS_BAR=$(plutil -extract UIStatusBarHidden raw Info.plist 2>/dev/null)
echo "Status Bar Hidden: $STATUS_BAR"
# Complete metadata extraction script:
cat > extract_metadata.sh << 'SCRIPT'
#!/bin/bash
PLIST="$1"
cat << EOF
====================================
iOS Application Metadata
====================================
Application Information:
Bundle ID: $(plutil -extract CFBundleIdentifier raw "$PLIST" 2>/dev/null)
Display Name: $(plutil -extract CFBundleDisplayName raw "$PLIST" 2>/dev/null || plutil -extract CFBundleName raw "$PLIST" 2>/dev/null)
Version: $(plutil -extract CFBundleShortVersionString raw "$PLIST" 2>/dev/null)
Build: $(plutil -extract CFBundleVersion raw "$PLIST" 2>/dev/null)
Platform Requirements:
Minimum iOS: $(plutil -extract MinimumOSVersion raw "$PLIST" 2>/dev/null || echo "Not specified")
Device Families: $(plutil -extract UIDeviceFamily json "$PLIST" 2>/dev/null | jq -r 'join(", ")' || echo "Not specified")
Security:
Requires iPhone OS: $(plutil -extract LSRequiresIPhoneOS raw "$PLIST" 2>/dev/null || echo "false")
Supports Secure Coding: $(plutil -extract NSSupportsSecureCoding raw "$PLIST" 2>/dev/null || echo "false")
====================================
EOF
SCRIPT
chmod +x extract_metadata.sh
./extract_metadata.sh Info.plist
iOS Filesystem and Code Analysis
#Filesystem Analysis
#1. Comprehensive File Discovery:
## Navigate to extracted IPA contents:
cd Payload/*.app/
# 1. List all files with metadata:
find . -type f -exec ls -lh {} \; | sort -k5 -h
# Shows files sorted by size
# 2. Identify file types:
find . -type f -exec file {} \; | grep -v "ASCII text" | sort -u
# Shows non-text files (binaries, images, databases, etc.)
# 3. Search for sensitive file types:
find . -type f \( \
-name "*.plist" -o \
-name "*.sqlite" -o \
-name "*.db" -o \
-name "*.realm" -o \
-name "*.pem" -o \
-name "*.crt" -o \
-name "*.cer" -o \
-name "*.p12" -o \
-name "*.key" -o \
-name "*.keystore" -o \
-name "*.jks" -o \
-name "*.json" -o \
-name "*.xml" -o \
-name "*.conf" -o \
-name "*.config" -o \
-name "*.properties" \
\) -ls
# 4. Find configuration files:
find . -type f -name "*config*" -o -name "*settings*" -o -name "*preferences*"
# 5. Database files analysis:
find . -name "*.sqlite" -o -name "*.db" | while read db; do
echo "[*] Database: $db"
sqlite3 "$db" ".tables" 2>/dev/null || echo " [!] Not a valid SQLite database"
echo " Size: $(ls -lh "$db" | awk '{print $5}')"
echo
done
# 6. Identify encrypted/obfuscated files:
find . -type f -exec file {} \; | grep -i "encrypted\|data"
# 7. Look for backup files (potential data leaks):
find . -type f \( -name "*.bak" -o -name "*.backup" -o -name "*~" -o -name "*.old" \)
# 8. Check for development/debug artifacts:
find . -type f \( \
-name "*.log" -o \
-name "*.txt" -o \
-name "*.md" -o \
-name "README*" -o \
-name "TODO*" -o \
-name ".DS_Store" \
\)
2. Search for Hardcoded Secrets:
## 1. Search for common secret patterns in all text files:
grep -r -n -i -E "(password|passwd|pwd)[ ]*[:=][ ]*['\"][^'\"]{3,}" . 2>/dev/null | \
grep -v ".png\|.jpg\|.jpeg\|.gif\|.ttf\|.otf"
# 2. API Keys and Tokens (comprehensive patterns):
cat > search_secrets.sh << 'SCRIPT'
#!/bin/bash
# Modern secret pattern detection
SEARCH_DIR="${1:-.}"
OUTPUT="secrets_found.txt"
echo "[*] Searching for hardcoded secrets in: $SEARCH_DIR"
echo "[*] Results will be saved to: $OUTPUT"
echo
> "$OUTPUT" # Clear output file
# AWS Keys
echo "[*] Searching for AWS keys..."
grep -r -n -E "AKIA[0-9A-Z]{16}" "$SEARCH_DIR" 2>/dev/null | tee -a "$OUTPUT"
# Generic API Keys (various formats)
echo "[*] Searching for generic API keys..."
grep -r -n -i -E "(api[_-]?key|apikey|api[_-]?secret)[ ]*[:=][ ]*['\"][a-zA-Z0-9_\-]{20,}['\"]" "$SEARCH_DIR" 2>/dev/null | tee -a "$OUTPUT"
# Firebase
echo "[*] Searching for Firebase credentials..."
grep -r -n -i -E "firebase[_-]?(api|key|secret|url|database)" "$SEARCH_DIR" 2>/dev/null | tee -a "$OUTPUT"
find "$SEARCH_DIR" -name "GoogleService-Info.plist" -o -name "google-services.json" | tee -a "$OUTPUT"
# OAuth/JWT Secrets
echo "[*] Searching for OAuth/JWT secrets..."
grep -r -n -i -E "(client[_-]?secret|oauth[_-]?secret|jwt[_-]?secret)[ ]*[:=]" "$SEARCH_DIR" 2>/dev/null | tee -a "$OUTPUT"
# Private Keys
echo "[*] Searching for private keys..."
grep -r -n "-----BEGIN.*PRIVATE KEY-----" "$SEARCH_DIR" 2>/dev/null | tee -a "$OUTPUT"
grep -r -n "-----BEGIN RSA PRIVATE KEY-----" "$SEARCH_DIR" 2>/dev/null | tee -a "$OUTPUT"
# Database Credentials
echo "[*] Searching for database credentials..."
grep -r -n -i -E "(db[_-]?password|database[_-]?password|mysql[_-]?password|postgres[_-]?password)[ ]*[:=]" "$SEARCH_DIR" 2>/dev/null | tee -a "$OUTPUT"
# Connection Strings
echo "[*] Searching for connection strings..."
grep -r -n -E "(mongodb://|postgresql://|mysql://|jdbc:)" "$SEARCH_DIR" 2>/dev/null | tee -a "$OUTPUT"
# Slack Tokens
echo "[*] Searching for Slack tokens..."
grep -r -n -E "xox[baprs]-[0-9a-zA-Z]{10,}" "$SEARCH_DIR" 2>/dev/null | tee -a "$OUTPUT"
# Stripe Keys
echo "[*] Searching for Stripe keys..."
grep -r -n -E "(sk|pk)_(test|live)_[0-9a-zA-Z]{24,}" "$SEARCH_DIR" 2>/dev/null | tee -a "$OUTPUT"
# GitHub Tokens
echo "[*] Searching for GitHub tokens..."
grep -r -n -E "gh[pousr]_[A-Za-z0-9_]{36,}" "$SEARCH_DIR" 2>/dev/null | tee -a "$OUTPUT"
# Twilio
echo "[*] Searching for Twilio credentials..."
grep -r -n -E "AC[a-z0-9]{32}" "$SEARCH_DIR" 2>/dev/null | tee -a "$OUTPUT"
# Passwords (various formats)
echo "[*] Searching for hardcoded passwords..."
grep -r -n -i -E "(password|passwd|pwd)[ ]*[:=][ ]*['\"][^'\"]{3,}['\"]" "$SEARCH_DIR" 2>/dev/null | tee -a "$OUTPUT"
# Bearer Tokens
echo "[*] Searching for bearer tokens..."
grep -r -n -i "bearer [a-zA-Z0-9_\-\.]{20,}" "$SEARCH_DIR" 2>/dev/null | tee -a "$OUTPUT"
# Generic Base64 Secrets (potential encoded credentials)
echo "[*] Searching for Base64 encoded data (potential secrets)..."
grep -r -n -E "['\"][A-Za-z0-9+/]{40,}={0,2}['\"]" "$SEARCH_DIR" 2>/dev/null | \
head -20 | tee -a "$OUTPUT"
# Hex-encoded keys (32+ chars)
echo "[*] Searching for hex-encoded keys..."
grep -r -n -E "['\"][0-9a-fA-F]{32,}['\"]" "$SEARCH_DIR" 2>/dev/null | \
head -20 | tee -a "$OUTPUT"
echo
echo "[+] Search complete! Results in: $OUTPUT"
echo "[*] Total findings: $(wc -l < "$OUTPUT")"
SCRIPT
chmod +x search_secrets.sh
./search_secrets.sh .
3. URL and Endpoint Discovery:
## Find all HTTP/HTTPS URLs:
grep -r -h -o -E "https?://[a-zA-Z0-9./?=_&%-]+" . 2>/dev/null | \
sort -u > discovered_urls.txt
# Find API endpoints:
grep -r -h -o -E "https?://[a-zA-Z0-9.-]+/api/[a-zA-Z0-9./?=_&%-]+" . 2>/dev/null | \
sort -u > api_endpoints.txt
# Find internal/development URLs:
grep -r -i -E "(localhost|127\.0\.0\.1|192\.168\.|10\.|172\.16\.|dev\.|staging\.|test\.)" . 2>/dev/null | \
grep -E "https?://" > internal_urls.txt
# Extract unique domains:
cat discovered_urls.txt | \
sed -E 's|https?://([^/]+).*|\1|' | \
sort -u > domains.txt
# Check for development/debug endpoints:
grep -i -E "(debug|test|staging|dev|admin|internal)" discovered_urls.txt
# URL discovery with categorization:
cat > analyze_urls.sh << 'SCRIPT'
#!/bin/bash
SEARCH_DIR="${1:-.}"
echo "[*] Discovering URLs and endpoints..."
# Extract all URLs
grep -r -h -o -E "https?://[a-zA-Z0-9./?=_&%-]+" "$SEARCH_DIR" 2>/dev/null | \
sort -u > all_urls.txt
# Categorize URLs
echo "[*] Categorizing URLs..."
grep -i "api" all_urls.txt > api_urls.txt
grep -E "(localhost|127\.0\.0\.1|192\.168\.|10\.|172\.(1[6-9]|2[0-9]|3[01])\.)" all_urls.txt > internal_urls.txt
grep -i -E "(dev|staging|test|debug)" all_urls.txt > dev_urls.txt
grep -i -E "(admin|console|dashboard|panel)" all_urls.txt > admin_urls.txt
grep "http://" all_urls.txt > http_urls.txt # Insecure HTTP
echo "[+] URL Discovery Results:"
echo " Total URLs: $(wc -l < all_urls.txt)"
echo " API endpoints: $(wc -l < api_urls.txt)"
echo " Internal URLs: $(wc -l < internal_urls.txt)"
echo " Dev/Test URLs: $(wc -l < dev_urls.txt)"
echo " Admin URLs: $(wc -l < admin_urls.txt)"
echo " Insecure HTTP: $(wc -l < http_urls.txt)"
# Extract unique domains
sed -E 's|https?://([^/:]+).*|\1|' all_urls.txt | sort -u > domains.txt
echo " Unique domains: $(wc -l < domains.txt)"
echo
echo "[*] Files created: all_urls.txt, api_urls.txt, internal_urls.txt, domains.txt"
SCRIPT
chmod +x analyze_urls.sh
./analyze_urls.sh .
4. Email Address Discovery:
## Extract email addresses:
grep -r -h -o -E "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}" . 2>/dev/null | \
sort -u > emails.txt
# Categorize emails:
grep -E "@(gmail|yahoo|hotmail|outlook)\.com" emails.txt > personal_emails.txt
grep -v -E "@(gmail|yahoo|hotmail|outlook)\.com" emails.txt > company_emails.txt
echo "[*] Email Discovery:"
echo " Total emails: $(wc -l < emails.txt)"
echo " Personal: $(wc -l < personal_emails.txt)"
echo " Company: $(wc -l < company_emails.txt)"
5. Cryptographic Material Search:
## Search for crypto-related terms and potential keys:
grep -r -n -i -E "(encrypt|decrypt|cipher|crypto|aes|des|rsa|sha|md5|hmac)" . 2>/dev/null | \
grep -v ".png\|.jpg\|Binary" | \
head -50 > crypto_references.txt
# Search for initialization vectors (IVs):
grep -r -n -i "iv[ ]*[:=]" . 2>/dev/null
# Search for encryption keys:
grep -r -n -i -E "(encryption[_-]?key|cipher[_-]?key|secret[_-]?key)[ ]*[:=]" . 2>/dev/null
# Search for key derivation:
grep -r -n -i -E "pbkdf2|scrypt|argon2|bcrypt" . 2>/dev/null
# Find certificate files:
find . -type f \( -name "*.pem" -o -name "*.crt" -o -name "*.cer" -o -name "*.p12" -o -name "*.pfx" \) -exec ls -lh {} \;
6. Database Query Pattern Search (SQL Injection vectors):
## Search for SQL queries:
grep -r -n -i -E "(select|insert|update|delete|drop|create table)[ ]+.*(from|into|set|where)" . 2>/dev/null | \
grep -v ".png\|Binary" | \
head -30 > sql_queries.txt
# Search for string concatenation in queries (potential SQL injection):
grep -r -n -E "\\+.*['\"].*SELECT|SELECT.*\\+|stringWithFormat.*SELECT" . 2>/dev/null
# Search for dynamic query construction:
grep -r -n -i "executeQuery\|rawQuery\|execSQL" . 2>/dev/null
Plist Files Analysis
#Analyze All Plist Files:
## Find all plist files:
find . -name "*.plist" -type f > plist_files.txt
# Analyze each plist:
cat > analyze_plists.sh << 'SCRIPT'
#!/bin/bash
echo "[*] Analyzing all plist files..."
echo
find . -name "*.plist" -type f | while read plist; do
echo "=== $plist ==="
# Check if binary or XML
if file "$plist" | grep -q "binary"; then
echo "[*] Binary plist - converting to XML"
plutil -convert xml1 "$plist" -o "${plist}.xml" 2>/dev/null
PLIST_TO_READ="${plist}.xml"
else
PLIST_TO_READ="$plist"
fi
# Display contents
plutil -p "$PLIST_TO_READ" 2>/dev/null || cat "$PLIST_TO_READ"
# Check for sensitive data
if grep -i -q "password\|secret\|key\|token\|api" "$PLIST_TO_READ" 2>/dev/null; then
echo "[!] ALERT: Potential sensitive data found!"
fi
echo
done
SCRIPT
chmod +x analyze_plists.sh
./analyze_plists.sh | tee plist_analysis.txt
Common Plist Files to Examine:
## 1. Main Info.plist (already covered)
cat Info.plist
# 2. Preferences plist (app settings):
find . -path "*/Library/Preferences/*.plist"
# 3. UserDefaults plist:
# At runtime: /var/mobile/Containers/Data/Application/<UUID>/Library/Preferences/<bundle-id>.plist
# 4. Configuration plists:
find . -name "*config*.plist" -o -name "*settings*.plist"
# 5. Localization plists:
find . -name "Localizable.strings" -o -name "InfoPlist.strings"
# 6. Firebase configuration (common in modern apps):
find . -name "GoogleService-Info.plist"
if [ -f "GoogleService-Info.plist" ]; then
echo "[!] Firebase configuration found - check for sensitive data:"
plutil -p GoogleService-Info.plist | grep -i -E "api_key|project_id|database_url"
fi
React Native Bundle Analysis
#Detect React Native Applications:
## Check for React Native indicators:
find . -name "main.jsbundle" -o -name "*.bundle" -o -name "index.*.bundle"
# Check for React Native frameworks:
find . -path "*/Frameworks/React.framework" -o -path "*/Frameworks/React-Core.framework"
# Verify if React Native:
if [ -f "main.jsbundle" ] || [ -d "Frameworks/React.framework" ]; then
echo "[+] React Native app detected"
else
echo "[-] Not a React Native app"
fi
Decompile React Native Bundle:
## Method 1: Using react-native-decompiler (Modern, Recommended)
# Install:
npm install -g @react-native-community/cli react-native-decompiler
# Decompile bundle:
npx react-native-decompiler -i main.jsbundle -o ./decompiled_js
# Alternative with specific options:
npx react-native-decompiler \
--input main.jsbundle \
--output ./decompiled_js \
--verbose
# Method 2: Manual extraction for Hermes bytecode (newer RN versions)
# Hermes is React Native's optimized JavaScript engine
# Check if bundle is Hermes bytecode:
file main.jsbundle
# If shows "Hermes JavaScript bytecode", need different approach
# Decompile Hermes bytecode:
# Install hermes-dec:
npm install -g hermes-dec
# Decompile:
hermes-dec main.jsbundle -o decompiled_hermes.js
# Method 3: Using hbctool (Hermes Bytecode Toolkit)
git clone https://github.com/bongtrop/hbctool.git
cd hbctool
pip3 install -r requirements.txt
# Disassemble Hermes bytecode:
python3 hbctool.py disasm ../main.jsbundle ../disassembled.hasm
# Decompile (experimental):
python3 hbctool.py decompile ../main.jsbundle ../decompiled_output/
# Method 4: Using react-native-bundle-visualizer (analyze, not decompile)
npx react-native-bundle-visualizer main.jsbundle
# Opens browser with bundle composition analysis
Analyze Decompiled React Native Code:
#cd decompiled_js/
# 1. Find sensitive data in decompiled JS:
grep -r -n -i -E "(api[_-]?key|secret|password|token)[ ]*[:=]" . | \
head -30 > rn_secrets.txt
# 2. Find API endpoints:
grep -r -h -o -E "https?://[a-zA-Z0-9./?=_&%-]+" . | \
sort -u > rn_api_endpoints.txt
# 3. Find AsyncStorage usage (React Native's local storage):
grep -r -n "AsyncStorage\.\(setItem\|getItem\|multiSet\)" . | \
head -20 > rn_async_storage.txt
# 4. Find fetch/network calls:
grep -r -n -E "fetch\(|axios\.|XMLHttpRequest" . | \
head -30 > rn_network_calls.txt
# 5. Find authentication/auth patterns:
grep -r -n -i -E "(login|authenticate|auth[^a-z]|token|bearer)" . | \
head -30 > rn_auth_patterns.txt
# 6. Find navigation/routing (potential for deep link issues):
grep -r -n "NavigationContainer\|createStackNavigator\|navigate\(" . | \
head -20
# 7. Search for crypto operations:
grep -r -n -i -E "crypto|encrypt|decrypt|cipher|hash" . | \
head -20
# 8. Find environment configs:
grep -r -n -E "process\.env\|__DEV__|Config\." . | \
head -20 > rn_config.txt
# Comprehensive React Native analysis script:
cat > analyze_react_native.sh << 'SCRIPT'
#!/bin/bash
RN_DIR="${1:-.}"
echo "[*] Analyzing React Native code in: $RN_DIR"
echo
# API endpoints
echo "[*] Extracting API endpoints..."
grep -r -h -o -E "https?://[a-zA-Z0-9./?=_&%-]+" "$RN_DIR" 2>/dev/null | \
sort -u > rn_endpoints.txt
echo " Found $(wc -l < rn_endpoints.txt) unique endpoints"
# Secrets
echo "[*] Searching for secrets..."
grep -r -n -i -E "(api[_-]?key|apikey|secret|password|token)[ ]*[:=]" "$RN_DIR" 2>/dev/null | \
head -50 > rn_secrets.txt
echo " Found $(wc -l < rn_secrets.txt) potential secrets"
# AsyncStorage usage
echo "[*] Finding AsyncStorage usage..."
grep -r -n "AsyncStorage\." "$RN_DIR" 2>/dev/null > rn_storage.txt
echo " Found $(wc -l < rn_storage.txt) AsyncStorage references"
# Network calls
echo "[*] Finding network requests..."
grep -r -n -E "fetch\(|axios\.|XMLHttpRequest|HttpClient" "$RN_DIR" 2>/dev/null > rn_network.txt
echo " Found $(wc -l < rn_network.txt) network call references"
# Authentication patterns
echo "[*] Finding authentication patterns..."
grep -r -n -i -E "login|authenticate|authorization|bearer|jwt" "$RN_DIR" 2>/dev/null | \
head -30 > rn_auth.txt
echo " Found $(wc -l < rn_auth.txt) auth-related references"
# Deep links / navigation
echo "[*] Finding navigation and deep links..."
grep -r -n -E "Linking\.(openURL|getInitialURL)|navigate\(|createStackNavigator" "$RN_DIR" 2>/dev/null > rn_navigation.txt
echo " Found $(wc -l < rn_navigation.txt) navigation references"
echo
echo "[+] Analysis complete! Check generated files:"
echo " - rn_endpoints.txt"
echo " - rn_secrets.txt"
echo " - rn_storage.txt"
echo " - rn_network.txt"
echo " - rn_auth.txt"
echo " - rn_navigation.txt"
SCRIPT
chmod +x analyze_react_native.sh
./analyze_react_native.sh decompiled_js/
Swift/SwiftUI Specific Analysis
#Analyze Swift Code (Modern iOS Development):
## Swift apps may have different structure than Objective-C
# 1. Check for Swift usage:
otool -L Payload/*.app/* | grep -i swift
# Or:
nm Payload/*.app/* | grep -i swift | head -20
# 2. Extract Swift class names (Swift uses name mangling):
nm Payload/*.app/* | grep "^_\$s" | head -50 > swift_symbols.txt
# 3. Demangle Swift symbols for readability:
# Install swift-demangle (part of Swift toolchain)
# macOS with Xcode: /usr/bin/swift-demangle
cat swift_symbols.txt | swift-demangle > demangled_swift_symbols.txt
# 4. Look for SwiftUI indicators:
nm Payload/*.app/* | grep -i "swiftui"
# 5. Extract Swift metadata:
otool -s __TEXT __swift5_fieldmd Payload/*.app/* | strings
# 6. Modern Swift string analysis:
# Swift 5.7+ uses new string representation
strings Payload/*.app/* | grep -E "^[a-zA-Z0-9/_.-]{10,}" | \
sort -u > extracted_strings.txt
# Check for sensitive strings:
grep -i -E "password|secret|key|token|api" extracted_strings.txt
Swift-Specific Security Patterns:
## 1. Search for UserDefaults (Swift equivalent of NSUserDefaults):
nm Payload/*.app/* | grep -i "userdefaults"
# 2. Search for Keychain access:
nm Payload/*.app/* | grep -i "keychain"
# 3. Search for Combine framework (reactive programming):
nm Payload/*.app/* | grep -i "combine"
# 4. Search for async/await patterns (Swift 5.5+):
nm Payload/*.app/* | grep -i "async"
# 5. Check for Swift Concurrency:
nm Payload/*.app/* | grep -i "task\|actor"
Advanced Pattern Matching with Ripgrep
## Install ripgrep (faster than grep for large codebases):
# macOS: brew install ripgrep
# Linux: sudo apt install ripgrep
# Or download from: https://github.com/BurntSushi/ripgrep/releases
# Ripgrep advantages: faster, better Unicode support, respects .gitignore
# 1. Search for API keys with context:
rg -i "api[_-]?key" --context 2
# 2. Search for secrets with file type filtering:
rg -i "(password|secret|token)" -t plist -t json
# 3. Search for URLs:
rg -o "https?://[a-zA-Z0-9./?=_&%-]+" | sort -u
# 4. Search with regex patterns (more powerful):
rg "AKIA[0-9A-Z]{16}" # AWS keys
rg "xox[baprs]-[0-9]{10,}" # Slack tokens
rg "sk_live_[0-9a-zA-Z]{24,}" # Stripe keys
# 5. Search excluding binary files:
rg -t txt -t json -t plist "password"
# 6. Case-insensitive search with line numbers:
rg -i -n "firebase"
# 7. Search for multiple patterns:
rg -e "api_key" -e "api_secret" -e "access_token"
# 8. Search with custom file types:
rg --type-add 'ios:*.{m,mm,swift,h}' -t ios "NSUserDefaults"
Automated Secret Scanning with Modern Tools
#Using TruffleHog (Git Secret Scanner):
## Install TruffleHog:
pip3 install truffleHog
# Scan extracted IPA directory:
trufflehog --regex --entropy=True file://Payload/Instagram.app/ > trufflehog_results.json
# With custom regexes:
cat > custom_regexes.json << 'JSON'
{
"Firebase API Key": "AIza[0-9A-Za-z\\-_]{35}",
"AWS Access Key": "AKIA[0-9A-Z]{16}",
"Slack Token": "xox[baprs]-[0-9]{10,}",
"Generic API Key": "[a|A][p|P][i|I][_]?[k|K][e|E][y|Y].*['|\"][0-9a-zA-Z]{32,45}['|\"]"
}
JSON
trufflehog --regex --rules custom_regexes.json file://Payload/Instagram.app/
Using Gitleaks:
## Install Gitleaks:
# macOS: brew install gitleaks
# Linux: Download from https://github.com/zricethezav/gitleaks/releases
# Scan directory:
gitleaks detect --source Payload/Instagram.app/ --report-path gitleaks_report.json --verbose
# With custom rules:
cat > gitleaks.toml << 'TOML'
title = "iOS App Secret Detection"
[[rules]]
id = "firebase-api-key"
description = "Firebase API Key"
regex = '''AIza[0-9A-Za-z\-_]{35}'''
[[rules]]
id = "aws-access-key"
description = "AWS Access Key"
regex = '''AKIA[0-9A-Z]{16}'''
[[rules]]
id = "generic-api-key"
description = "Generic API Key"
regex = '''[a|A][p|P][i|I][_-]?[k|K][e|E][y|Y].*['"][0-9a-zA-Z]{20,}['"]'''
[[rules]]
id = "stripe-key"
description = "Stripe API Key"
regex = '''(sk|pk)_(test|live)_[0-9a-zA-Z]{24,}'''
TOML
gitleaks detect --config gitleaks.toml --source Payload/Instagram.app/ --report-path report.json
Using Semgrep (Semantic Code Analysis):
## Install Semgrep:
pip3 install semgrep
# Scan for iOS-specific patterns:
semgrep --config "p/mobsf" Payload/Instagram.app/
# Custom iOS security rules:
cat > ios_security_rules.yaml << 'YAML'
rules:
- id: hardcoded-api-key
pattern: |
let $KEY = "$VALUE"
pattern-where:
- metavariable: $KEY
regex: (api[_-]?key|apikey)
message: "Hardcoded API key detected"
severity: ERROR
languages:
- swift
- id: nsuserdefaults-sensitive
pattern: |
UserDefaults.standard.set($VALUE, forKey: $KEY)
pattern-where:
- metavariable: $KEY
regex: (password|token|secret)
message: "Sensitive data stored in UserDefaults"
severity: WARNING
languages:
- swift
- id: insecure-http-url
pattern: |
URL(string: "http://$URL")
message: "Insecure HTTP URL detected"
severity: WARNING
languages:
- swift
YAML
semgrep --config ios_security_rules.yaml Payload/Instagram.app/
Framework and Library Analysis
#Identify Third-Party Frameworks:
## List all frameworks:
find . -name "*.framework" -type d
# For each framework, get info:
find . -name "*.framework" -type d | while read fw; do
echo "=== $(basename "$fw") ==="
# Framework version (if available):
INFO_PLIST="$fw/Info.plist"
if [ -f "$INFO_PLIST" ]; then
echo " Version: $(plutil -extract CFBundleShortVersionString raw "$INFO_PLIST" 2>/dev/null || echo 'N/A')"
echo " Bundle ID: $(plutil -extract CFBundleIdentifier raw "$INFO_PLIST" 2>/dev/null || echo 'N/A')"
fi
# Framework binary (if exists):
FW_BINARY="$fw/$(basename "$fw" .framework)"
if [ -f "$FW_BINARY" ]; then
echo " Architecture: $(lipo -info "$FW_BINARY" 2>/dev/null | cut -d: -f3 || echo 'N/A')"
fi
echo
done > framework_inventory.txt
cat framework_inventory.txt
Check for Known Vulnerable Libraries:
## Common vulnerable iOS libraries to check:
# 1. AFNetworking (check version)
if find . -name "AFNetworking" -type d | grep -q .; then
echo "[!] AFNetworking detected - check version for CVEs"
# Versions < 4.0 have known vulnerabilities
fi
# 2. Alamofire (check version)
if find . -name "Alamofire" -type d | grep -q .; then
echo "[!] Alamofire detected - check version"
fi
# 3. Firebase SDK (check version)
if find . -name "Firebase*" -type d | grep -q .; then
echo "[!] Firebase SDK detected"
find . -name "Firebase*" -type d | while read fw; do
INFO="$fw/Info.plist"
if [ -f "$INFO" ]; then
VERSION=$(plutil -extract CFBundleShortVersionString raw "$INFO" 2>/dev/null)
echo " - $(basename "$fw"): $VERSION"
fi
done
fi
# 4. Facebook SDK (privacy concerns)
if find . -name "Facebook*" -type d | grep -q .; then
echo "[!] Facebook SDK detected - potential privacy concerns"
fi
# 5. Realm (check version)
if find . -name "Realm*" -type d | grep -q .; then
echo "[!] Realm database detected"
fi
# 6. OpenSSL (check for Heartbleed and other CVEs)
if find . -name "*OpenSSL*" -type d | grep -q .; then
echo "[!] OpenSSL detected - check for vulnerabilities"
fi
# Create comprehensive framework report:
cat > analyze_frameworks.sh << 'SCRIPT'
#!/bin/bash
echo "iOS Framework Security Analysis"
echo "================================"
echo
# Find all frameworks
FRAMEWORKS=$(find . -name "*.framework" -type d)
if [ -z "$FRAMEWORKS" ]; then
echo "No frameworks found"
exit 0
fi
echo "$FRAMEWORKS" | while read fw; do
FW_NAME=$(basename "$fw" .framework)
echo "Framework: $FW_NAME"
INFO="$fw/Info.plist"
if [ -f "$INFO" ]; then
VERSION=$(plutil -extract CFBundleShortVersionString raw "$INFO" 2>/dev/null || echo "Unknown")
BUNDLE_ID=$(plutil -extract CFBundleIdentifier raw "$INFO" 2>/dev/null || echo "Unknown")
echo " Version: $VERSION"
echo " Bundle ID: $BUNDLE_ID"
# Check for known vulnerable frameworks
case "$FW_NAME" in
"AFNetworking")
echo " [!] Check CVEs for AFNetworking $VERSION"
echo " Known vulnerabilities in versions < 4.0"
;;
"OpenSSL"|"libssl")
echo " [!] Check for Heartbleed and other OpenSSL CVEs"
;;
"Facebook"*)
echo " [!] Privacy concerns - Facebook SDK tracks user data"
;;
"Firebase"*)
echo " [!] Ensure Firebase credentials are not exposed"
;;
esac
fi
# Check binary
BINARY="$fw/$FW_NAME"
if [ -f "$BINARY" ]; then
ARCH=$(lipo -info "$BINARY" 2>/dev/null | cut -d: -f3)
echo " Architectures: $ARCH"
# Check for symbols that might indicate vulnerabilities
if nm "$BINARY" 2>/dev/null | grep -q -i "strcpy\|strcat\|sprintf"; then
echo " [!] WARNING: Unsafe string functions detected"
fi
fi
echo
done
SCRIPT
chmod +x analyze_frameworks.sh
./analyze_frameworks.sh
Asset Analysis
#Analyze Assets.car (Compiled Asset Catalog):
## Assets.car contains all images, colors, and other resources
# Extract using acextract (part of iOS-artwork-extractor)
# Method 1: Using acextract
# Install: brew install acextract
acextract -i Assets.car -o extracted_assets/
# Method 2: Using Asset Catalog Tinkerer (GUI, macOS only)
# Download from: https://github.com/insidegui/AssetCatalogTinkerer
# Method 3: Manual with cartool
git clone https://github.com/steventroughtonsmith/cartool.git
cd cartool
make
./cartool ../Assets.car ../extracted_assets/
# Analyze extracted assets:
cd extracted_assets/
# Look for interesting images:
ls -lh *.png | head -20
# Search for screenshots (may contain sensitive data):
find . -name "*screenshot*" -o -name "*demo*" -o -name "*test*"
# Search for logos/branding:
find . -name "*logo*" -o -name "*icon*" -o -name "*brand*"
# Check metadata in images:
exiftool *.png | grep -E "(Author|Creator|Copyright|Software)"
Analyze Storyboards and XIBs:
## Storyboards contain UI layout information
# Can reveal app flow, features, hidden screens
# Find all storyboards:
find . -name "*.storyboard" -o -name "*.xib"
# Storyboards are XML, can be analyzed directly:
cat > analyze_storyboards.sh << 'SCRIPT'
#!/bin/bash
echo "[*] Analyzing storyboards..."
find . -name "*.storyboard" | while read sb; do
echo "=== $(basename "$sb") ==="
# Extract view controller names:
grep "customClass=" "$sb" | sed 's/.*customClass="\([^"]*\)".*/\1/' | sort -u
# Look for interesting UI elements:
if grep -q "textField" "$sb"; then
echo " [*] Contains text fields (potential input fields)"
fi
if grep -q "webView" "$sb"; then
echo " [*] Contains web view (potential web content)"
fi
if grep -q -i "password" "$sb"; then
echo " [!] Contains password field"
fi
echo
done
SCRIPT
chmod +x analyze_storyboards.sh
./analyze_storyboards.sh
Strings Analysis
#Extract and Analyze All Strings:
## Extract strings from main binary:
strings Payload/*.app/YourApp > all_strings.txt
# Categorize strings:
# 1. URLs and endpoints:
grep -E "https?://" all_strings.txt | sort -u > string_urls.txt
# 2. File paths:
grep -E "^(/[a-zA-Z0-9_/-]+|~/|\.\./).*" all_strings.txt | sort -u > string_paths.txt
# 3. Potential secrets (uppercase alphanumeric 20+ chars):
grep -E "^[A-Z0-9]{20,}$" all_strings.txt > string_potential_keys.txt
# 4. Email-like strings:
grep -E "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}" all_strings.txt | sort -u > string_emails.txt
# 5. SQL-like strings:
grep -i -E "select|insert|update|delete|from|where" all_strings.txt | head -30 > string_sql.txt
# 6. Crypto-related:
grep -i -E "encrypt|decrypt|cipher|aes|rsa|sha|md5|key|iv|salt" all_strings.txt > string_crypto.txt
# 7. Class/method names (camelCase):
grep -E "^[a-z]+[A-Z][a-zA-Z0-9]*$" all_strings.txt | sort -u > string_methods.txt