OSMR (EXP-312) exam strategy

OSMR (EXP-312) exam strategy

TL;DR: OSMR (EXP-312, “macOS Control Bypasses”) is Offensive Security’s 48-hour practical that tests whether you can chain real macOS primitives — XPC service audit, IOKit driver bugs, sandbox escape, TCC pivot, codesigning/entitlement abuse — into useful exploits on a modern macOS host. Treat it as an applied audit exam, not a shellcoding marathon: read code, model trust boundaries, prove the chain works under SIP and AMFI. Anchor your prep on macos-architecture, mach-and-xpc, macos-xpc-internals, macos-sandbox-escape, macos-tcc, macos-sip-deep, macos-amfi-and-codesigning-deep, iokit-attack-surface, macos-kernel-heap-zone, macos-kernel-debugging, and the broader osee-roadmap mindset for kernel work.

Why this matters

OSMR fills a niche that OSED (osee-roadmap precursor) and OSEE do not: macOS-specific control bypasses. On Windows you spend most of the cert chasing mitigations (DEP/ASLR/CFG/CET). On macOS the interesting bugs almost always live at trust boundaries enforced by Apple userland — XPC peers, entitlements, sandbox profiles, TCC consent, codesigning — backed by kernel surfaces like IOKit and Mach IPC.

If your background is Windows-heavy (hevd-stack-overflow-walkthrough, windows-kernel-debugging-deep) the muscle memory partially transfers, but the what-to-look-for changes:

What the exam actually looks like

Public syllabus and student write-ups converge on this shape — treat specifics as guidance, not gospel:

Format

  • Duration: 47 hours 45 minutes of exam time plus a 24-hour reporting window.
  • Environment: a single dedicated macOS VM (or remote host) with several discrete objectives, each carrying point values that sum past the pass threshold (typically 60/100, but check current Offensive Security exam rules).
  • Objectives mix: vulnerable third-party-style apps shipped by Offensive Security plus tasks that exercise platform features (XPC service, IOKit-style kext or driver, sandboxed binary, TCC-protected resource).
  • No internet during the practical except to OffSec’s proctoring/portal. Bring an offline notes workspace.

What “solving” looks like

You’re rarely asked to drop a calc.exe equivalent. You’re asked to:

Prep checklist

Hardware

  • One Apple Silicon Mac (M1 or newer) running a recent macOS. PAC and pointer-auth specifics matter (pac-arm64e-bypass).
  • One Intel Mac if you can swing it. Some kernel exploitation primitives still teach more cleanly on x86_64 because of richer public material; differences with arm64e are non-trivial.
  • Old jailbroken iOS device or a vintage macOS install for kernel research without the full hardened-runtime / KTRR / PPL friction. Useful for understanding XNU internals you can then map onto current targets.
  • A separate workstation for note-taking and report drafting. You do not want LLDB and Obsidian fighting for RAM on exam day.

Software / tooling fluency

  • lldb with Apple’s kdp-remote, image lookup, memory read, and kernel debugging stubs (macos-kernel-debugging).
  • xcrun + Xcode command-line tools: codesign, spctl, pkgutil, xcodebuild, sandbox-exec.
  • class-dump / class-dump-z for Objective-C runtime introspection.
  • Hopper or Ghidra for static analysis; IDA is fine if licensed. Practice loading dyld_shared_cache extractions.
  • frida for runtime hooking when LLDB is overkill.
  • procexp, fs_usage, lsof, launchctl print for system tracing.
  • jtool2 / ldid for entitlement and codesign inspection.
  • xpcspy / xpc_object dumper for XPC traffic.

Reading

Public OffSec syllabus PDF, Apple’s Kernel Programming Guide (legacy but still accurate on Mach), Patrick Wardle’s The Art of Mac Malware vols 1-2, Jonathan Levin’s MacOS and iOS Internals (vol III on security is the gold standard), and the Project Zero macOS issue tracker entries. Cross-link your notes back to macos-architecture so the abstractions stay grounded.

Focus topics — what to drill

XPC audit

Most points-per-hour come from auditing XPC services. Workflow:

  1. launchctl print system | grep <bundle> — enumerate services and their endpoints.
  2. codesign -d --entitlements - <binary> — note com.apple.security.* keys and whether the service runs as root.
  3. Decompile the service binary; look for xpc_connection_set_event_handler, then trace what messages it accepts.
  4. Check peer validation: does it call SecCodeCopyGuestWithAttributes / audit_token_to_pid / csops? Many CVEs are missing or weak peer checks.
  5. Confirm in macos-xpc-internals how entitlement strings get parsed; off-by-one matches and prefix mistakes are common.

IOKit driver vulns

  • Get familiar with IOUserClient::externalMethod, IOExternalMethodDispatch, scalar vs structure inputs.
  • Practice writing a user-client client in Swift/ObjC that calls IOConnectCallMethod with crafted arguments.
  • Triage TOCTOU between getAsyncTargetAndMethodForIndex and dispatch.
  • Pair with macos-kernel-heap-zone for shaping the kalloc zones used by IOKit objects.

Sandbox escape

  • Map app sandbox profile (sandbox-exec -f, sbtool style traces).
  • Identify which Mach services are reachable from the sandbox.
  • Hunt for entitled helpers reachable via xpc_connection_create_mach_service that perform privileged work on behalf of the sandboxed peer.
  • Cross-reference macos-sandbox-escape for the standard patterns: file-extension brokering, login-item registration, Mach service reachability mismatches.

TCC bypass

  • Understand tccd’s database schema and which entitlements grant blanket access (e.g. com.apple.private.tcc.allow).
  • Look for binaries that already hold the access you need and can be coerced into acting on attacker-controlled paths (classic FullDiskAccess pivot).
  • See macos-tcc for current bypass classes — most exam-relevant ones are logic bugs, not crypto bugs.

Mach port primitives

  • Send rights, receive rights, port sets, mach_msg OOL descriptors.
  • Practice porting one public Mach exploit primitive to a new target so you don’t freeze when faced with the unfamiliar.
  • mach-port-exploitation covers fakeport and zone-cross techniques you may need.

Codesigning / entitlement abuse

  • amfid, taskgated, csr_check — know who enforces what.
  • Restricted entitlements (com.apple.private.*) require Apple platform binaries; abuse paths usually involve loading attacker code into one of those processes.
  • Refresh on macos-amfi-and-codesigning-deep and macos-sip-deep for the boundary you must respect or bypass.

Pacing — a realistic 48-hour plan

These are guidelines; adjust based on which objective looks softest first.

  • Hours 0-1: read every objective, verify VM access, pull binaries, run codesign -d --entitlements - on everything, enumerate launchd services. Build a target inventory.
  • Hours 1-6: attack the lowest-friction objective first to bank points and confidence — usually a userland app with an obvious bug.
  • Hours 6-14: XPC and TCC objectives. These reward methodical reading.
  • Hours 14-22: IOKit / kernel objective. Save kernel debugging for when you’ve already secured pass-line points.
  • Hours 22-30: sleep. Six hours minimum. Tired you will misread audit_token_to_pid and lose four hours.
  • Hours 30-40: finish remaining objectives, sanity-check shell stability, take screenshots with timestamps and command output.
  • Hours 40-46: start drafting the report inside the exam window; pull command output while the box is live.
  • Hours 46-48: stop attacking, finalize evidence, shut down cleanly.

Do not burn 30 hours on one objective. If you have not made a measurable foothold in 6 hours, rotate.

Report quality

OffSec graders weight the report. Common ways students fail an exam they technically solved:

  • Missing precise command output (timestamps + hostname + uid).
  • “It worked on my machine” — no reproduction steps from a clean state.
  • Skipping the root-cause analysis. For an XPC bug, name the unchecked peer entitlement and the message id.
  • For IOKit, name the user-client class, selector index, and which argument index was unchecked.
  • For kernel objectives, include a clean PoC C file, build command, and observed kernel panic / privilege change.

Write the report assuming a grader who knows macOS but has not seen your specific chain. Use osee-roadmap style report discipline.

How OSMR differs from OSED and OSEE

  • OSED is Windows user-mode classical exploitation: SEH, egghunters, ROP (stack-buffer-overflow, seh-overwrite, egghunters, rop-chains). OSMR has some memory-corruption work but most points are logic.
  • OSEE is Windows kernel + browser + hypervisor extremes. OSMR is narrower and more applied: less novel mitigation bypass, more “use macOS the way Apple intended and find the gap.”
  • OSEP (osep-roadmap) is red-team payload work; almost no overlap with OSMR except mindset around code review and trust boundaries.

If you’ve already done OSEE, OSMR will feel less brutal on raw exploitation but will punish you for not knowing Apple’s userland model. If you came from OSEP, expect to spend most of prep on kernel and userland-trust topics that OSEP skipped.

Workflow to study

  1. Build one XPC service from scratch with a deliberate bug, then audit it as if you’d never seen it. Repeat for IOKit user clients.
  2. Reproduce 3-5 published macOS CVEs end-to-end. Project Zero issues with PoCs are ideal training. Map each to macos-xpc-internals / iokit-attack-surface patterns.
  3. Set up two-machine kernel debugging early — figuring out kdp-remote at hour 14 of the exam is a tax you cannot afford (macos-kernel-debugging).
  4. Write a personal cheat-sheet of one-liners: codesign dump, entitlement parse, launchctl enumerate, IORegistryExplorer queries, sysctl kern.bootargs, sandbox profile dump.
  5. Practice the report template on a non-exam target so the structure is muscle memory.

Defensive baseline

Even though OSMR is offensive, defenders reading this should note:

  • Always validate XPC peers with full codesign requirements, not just bundle id strings.
  • Never trust client-supplied paths; canonicalize after the privilege boundary.
  • Keep TCC-relevant entitlements off helpers that take attacker-influenced input.
  • For IOKit, validate every IOExternalMethodArguments field and refuse unexpected scalar/structure mixes.

References