Sandbox (Seatbelt)
App Sandbox is a mandatory access control framework that restricts each process to only access permitted resources. Sandbox escape is a required step in most exploit chains from an app context.
Why You Need to Learn This
- App Store apps are sandboxed, so exploits from an app must escape the sandbox before attacking the kernel
- System daemons are also sandboxed but with different profiles (broader)
- Understanding the sandbox = knowing which processes can access which attack surfaces (IOKit, Mach ports, …)
- Sandbox escape CVEs are an important component of commercial exploit chains (NSO, Predator, …)
Sandbox Architecture
Components
Userspace Kernel
┌──────────────┐ ┌─────────────────────┐
│ App Process │ ─── syscall ───→ │ Sandbox.kext │
│ (sandboxed) │ │ ├── Check policy │
│ │ │ ├── Allow/Deny │
│ │ │ └── Log violation │
└──────────────┘ └─────────────────────┘
│
┌───────┴───────┐
│ Compiled SBPL │
│ (sandbox │
│ profile │
│ bytecode) │
└───────────────┘
Sandbox Profile Language (SBPL)
Sandbox profiles are written in a Scheme-like language:
;; Default: deny everything
(version 1)
(deny default)
;; Allow reading files in the container
(allow file-read*
(subpath (param "CONTAINER_PATH")))
;; Allow writing to the tmp directory
(allow file-write*
(subpath (param "TMPDIR")))
;; Allow outbound network
(allow network-outbound
(remote tcp "*:80")
(remote tcp "*:443"))
;; Allow looking up specific Mach services
(allow mach-lookup
(global-name "com.apple.frontboard.systemappservices"))
;; Allow opening specific IOKit UserClients
(allow iokit-open
(iokit-user-client-class "IOSurfaceRootUserClient"))
;; Deny with logging (for debugging)
(deny file-write*
(with report)
(subpath "/private/var/db"))
Profile Types
| Type | Applied to | Restrictiveness |
|---|---|---|
Container (container) |
App Store apps | Very strict: container access only, limited IPC |
| System profiles | System daemons | Varies by daemon: some are quite broad |
| No sandbox | Kernel, launchd | Unrestricted |
Controlled Operations
| Category | Operations | Examples |
|---|---|---|
| file | read, write, ioctl, mount | File system access |
| network | inbound, outbound, bind | Socket operations |
| mach | lookup, register, priv-host-port | Mach port operations |
| iokit | open, set-properties, get-properties | IOKit driver access |
| process | exec, fork, signal | Process operations |
| sysctl | read, write | Kernel parameter access |
| ipc-posix-shm | read, write, create | Shared memory |
| nvram | get, set, delete | NVRAM access |
Sandbox Internals
Kernel Implementation
Sandbox.kext hooks into XNU’s MAC (Mandatory Access Control) framework:
- Each syscall goes through a MAC policy check
- The
sandbox_check()function in the kernel evaluates the compiled profile - Profiles are compiled into bytecode (binary format, not text SBPL)
Sandbox Container
Each sandboxed app has:
/var/mobile/Containers/
├── Bundle/{UUID}/ ← App bundle (read-only)
│ └── MyApp.app/
├── Data/{UUID}/ ← App data (read-write)
│ ├── Documents/
│ ├── Library/
│ │ ├── Caches/
│ │ └── Preferences/
│ └── tmp/
└── Shared/AppGroup/{GROUP_UUID}/ ← Shared data (app groups)
Extension Points
Sandbox profiles can:
(param "KEY")– receive parameters at apply time(extension "com.apple.app-sandbox.read" "/path")– dynamic extensions granted at runtime- System services (e.g., Photos, Contacts) grant extensions via XPC
Sandbox Escape Techniques
1. IPC Service Exploitation
Most common. A sandboxed app communicates with an unsandboxed (or less-sandboxed) daemon via:
- XPC services: serialize/deserialize bugs, logic errors
- Mach messages: type confusion, memory corruption in message handlers
- IOKit: driver bugs reachable from the sandbox
App (sandboxed) → XPC → mediaserverd (less sandbox) → IOKit → kernel
↑
Sandbox escape here
Real-world examples:
mediaplaybackd– accessible from WebContent sandboxGPU process– accessible from WebContent sandboxCommCenter– telephony service
2. NSPredicate / NSExpression Injection
- Many system services accept NSPredicate from sandboxed clients
- NSPredicate can evaluate arbitrary expressions
- Bug class discovered by Trellix: most NSPredicateVisitor implementations can be bypassed
- Allows code execution in the context of the target service (outside the sandbox)
3. File System Confusion
- Symlink/hardlink attacks: trick a privileged process into reading/writing files outside the sandbox
- Container boundary violations
4. Mach Port Theft / Injection
- Exploit Mach port lifecycle bugs to gain send rights to a privileged port
mach_port_insert_rightinto the target process
5. Logic Bugs in Sandbox Profiles
- Sandbox profiles sometimes allow too broadly
- System profiles may have exceptions that can be exploited
Analyzing Sandbox Profiles
Using sandblaster
# sandblaster — extract and decompile sandbox profiles
git clone https://github.com/nicklasb/sandblaster
python3 sandblaster/reverse_sandbox.py \
-r sandbox_profiles_dir \
-o output_dir \
-t profile_name
Reading compiled profiles on device
# Profiles are located in:
/System/Library/Sandbox/Profiles/ # System daemon profiles
/usr/share/sandbox/ # Additional profiles
# App sandbox profile:
# Compiled into sandbox.kext, not a separate file
# Use sandblaster to extract from kernelcache
Important profiles to read
container– App Store app sandbox (most restrictive)com.apple.WebKit.WebContent– WebContent process (Safari renderer)com.apple.mediaserverd– Media daemon (common sandbox escape target)
Resources
- 8kSec – Reading iOS Sandbox Profiles
- Redfox Security – iOS Sandboxing Challenges
- Apple – Security of Runtime Process
- SSD Disclosure – 3 Sandbox Escape CVEs
- sandblaster on GitHub
Exercises
- Dump entitlements of 10 different system daemons, classify their privilege levels
- Extract the sandbox profile of
com.apple.WebKit.WebContent, list all allowed IOKit UserClients - Write a custom SBPL profile that denies network but allows file read/write, test on macOS (
sandbox-exec) - Identify sandbox-reachable services: from the container profile, list all
mach-lookupglobal-names - Research 1 sandbox escape CVE: find a write-up, trace the attack path from sandboxed app to unsandboxed code