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 sandbox
  • GPU process – accessible from WebContent sandbox
  • CommCenter – 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_right into 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


Exercises

  1. Dump entitlements of 10 different system daemons, classify their privilege levels
  2. Extract the sandbox profile of com.apple.WebKit.WebContent, list all allowed IOKit UserClients
  3. Write a custom SBPL profile that denies network but allows file read/write, test on macOS (sandbox-exec)
  4. Identify sandbox-reachable services: from the container profile, list all mach-lookup global-names
  5. Research 1 sandbox escape CVE: find a write-up, trace the attack path from sandboxed app to unsandboxed code