Hacktricks-skills macos-ipc-analysis
Analyze macOS Mach IPC communications, port rights, task ports, and inter-process communication mechanisms. Use this skill whenever the user needs to understand Mach ports, debug IPC messages, analyze port permissions, work with task/thread ports, investigate code injection via task ports, or understand macOS IPC internals for security research, debugging, or privilege escalation analysis. Trigger on any mention of Mach ports, IPC, task_for_pid, bootstrap server, port rights, or macOS inter-process communication.
git clone https://github.com/abelrguezr/hacktricks-skills
skills/macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-ipc-inter-process-communication/macos-ipc-inter-process-communication/SKILL.MDmacOS IPC Analysis
A skill for analyzing and working with macOS Mach Inter-Process Communication (IPC) mechanisms, including ports, rights, task ports, and related security implications.
When to Use This Skill
Use this skill when you need to:
- Understand Mach port concepts and IPC mechanisms on macOS
- Debug or analyze Mach message communications
- Investigate port rights and permissions
- Work with task ports, thread ports, or special ports
- Analyze code injection techniques via task ports
- Understand bootstrap server and service registration
- Investigate privilege escalation via IPC mechanisms
- Debug XPC or MIG-based communications
Core Concepts
Mach Ports Overview
Mach uses tasks as the smallest unit for sharing resources. Each task maps 1:1 to POSIX processes and can contain multiple threads.
Key concepts:
- Ports: Basic IPC elements acting as message queues managed by the kernel
- IPC Table: Each process has an IPC table containing its Mach ports
- Port Names: Numbers (pointers to kernel objects)
- Communication: One-way channels between ports
Port Rights
Port rights define what operations a task can perform:
| Right | Description | Clonable |
|---|---|---|
| Receive | Receive messages; can create Send rights | No (single per port) |
| Send | Send messages to the port | Yes |
| Send-once | Send one message, then disappears | No |
| Port set | Listen on multiple ports simultaneously | N/A |
| Dead name | Placeholder when port is destroyed | N/A |
Important:
- Receive rights are MPSC (multiple-producer, single-consumer)
- Send rights can be cloned and transferred to other tasks
- Port rights can be passed through Mach messages
- If the Receive right owner dies, Send rights become dead names
Bootstrap Server
The bootstrap server (launchd on macOS) enables initial communication:
- Task A creates a port with RECEIVE right
- Task A generates a SEND right for the port
- Task A sends the SEND right to the bootstrap server
- Task A registers the port with a name (e.g.,
)com.apple.taska - Task B looks up the service name via bootstrap server
- Bootstrap server duplicates Task A's SEND right and sends to Task B
- Task B can now send messages to Task A
Security note: The bootstrap server cannot authenticate service names claimed by tasks. System services are protected via SIP-protected directories (
/System/Library/LaunchDaemons, /System/Library/LaunchAgents).
Port Enumeration and Analysis
Using lsmp
# List ports for a specific process lsmp -p <pid> # List ports for launchd (requires sudo) sudo lsmp -p 1
Output columns:
: Default port name (increasing in first 3 bytes)name
: Obfuscated unique identifieripc-object
: Port rights (send, recv, send+recv)rights
: Indicates other tasks connected to the same port+
Using procexp
# List all host special ports procexp all ports | grep "HSP" # List ports for a specific process (requires SIP disabled for some info) procexp 1 ports
Task Ports
Task ports are critical for process control and memory manipulation.
Key Functions
| Function | Purpose |
|---|---|
| Get SEND right for task of specified PID |
| Get PID from task port |
| Get task port for current task |
Task Port Capabilities
With SEND right over a task port, you can:
: Get SEND rights to all threadstask_threads
: Get task informationtask_info
: Control task executiontask_suspend/resume
: Read/write task memoryvm_read/vm_write
: Create new threadsthread_create
: Control task statetask_get/set_state
Security implications:
- SEND right over another task's port enables code injection
requires specific entitlements or roottask_for_pid
: Same-user access (debugging)com.apple.security.get-task-allow
: Any process access (Apple binaries only)com.apple.system-task-ports- Root can access non-hardened runtime applications
Task Port Restrictions
| Entitlement | Access Level |
|---|---|
| Same user processes |
| Any process (except kernel) |
| Root | Non-hardened runtime apps |
Thread Ports
Threads have associated ports visible via
task_threads.
Thread Port Capabilities
With SEND right over a thread port:
: Terminate the threadthread_terminate
: Control thread statethread_get/set_state
: Pause/resume executionthread_suspend/resume
: Get thread informationthread_info
Getting Thread Port
mach_thread_self() // Get thread port for current thread
Mach Message Structure
Message Header
typedef struct { mach_msg_bits_t msgh_bits; // Bitmap flags mach_msg_size_t msgh_size; // Total packet size mach_port_t msgh_remote_port; // Destination port mach_port_t msgh_local_port; // Reply port mach_port_name_t msgh_voucher_port; // Voucher port mach_msg_id_t msgh_id; // Message ID } mach_msg_header_t;
msgh_bits Bitmap
| Byte | Bits | Purpose |
|---|---|---|
| 1st | Bit 0 | Complex message flag |
| 1st | Bits 1-2 | Kernel use |
| 2nd | Bits 0-4 | Voucher port type |
| 3rd | Bits 0-4 | Local port type |
| 4th | Bits 0-4 | Remote port type |
Port Type Constants
#define MACH_MSG_TYPE_MOVE_RECEIVE 16 #define MACH_MSG_TYPE_MOVE_SEND 17 #define MACH_MSG_TYPE_MOVE_SEND_ONCE 18 #define MACH_MSG_TYPE_COPY_SEND 19 #define MACH_MSG_TYPE_MAKE_SEND 20 #define MACH_MSG_TYPE_MAKE_SEND_ONCE 21 #define MACH_MSG_TYPE_DISPOSE_RECEIVE 24 #define MACH_MSG_TYPE_DISPOSE_SEND 25 #define MACH_MSG_TYPE_DISPOSE_SEND_ONCE 26
Debugging Mach Messages
Setting Breakpoints
# In lldb (lldb) b mach_msg (lldb) r
Inspecting Arguments
# Read registers (ARM64 calling convention) (lldb) reg read $x0 $x1 $x2 $x3 $x4 $x5 $x6 # Inspect message header (lldb) x/6w $x0
Register mapping:
:$x0mach_msg_header_t *msg
:$x1mach_msg_option_t option
:$x2mach_msg_size_t send_size
:$x3mach_msg_size_t rcv_size
:$x4mach_port_name_t rcv_name
:$x5mach_msg_timeout_t timeout
:$x6mach_port_name_t notify
Special Ports
Host Special Ports
| Port | Number | Owner | Purpose |
|---|---|---|---|
| HOST_PORT | 1 | Kernel | System information |
| HOST_PRIV_PORT | 2 | Kernel | Privileged actions |
| HOST_IO_MASTER_PORT | 3 | Kernel | I/O master |
| HOST_MAX_SPECIAL_KERNEL_PORT | 7 | Kernel | Max kernel port |
| 8+ | 8+ | System daemons | Various services |
Access:
: Get SEND rights (requires host_priv)host_get_special_port
: Set RECEIVE rights (requires host_priv)host_set_special_port
Task Special Ports
#define TASK_KERNEL_PORT 1 // Task control port #define TASK_HOST_PORT 2 // Host port for task #define TASK_BOOTSTRAP_PORT 4 // Bootstrap environment #define TASK_WIRED_LEDGER_PORT 5 // Wired memory ledger #define TASK_PAGED_LEDGER_PORT 6 // Paged memory ledger
Code Injection Techniques
Shellcode Injection via Task Port
Requirements:
- SEND right to target task port (via
)task_for_pid - Target process with
entitlement (same user)com.apple.security.get-task-allow - Or root access to non-hardened runtime apps
Steps:
- Get task port via
task_for_pid(mach_task_self(), pid, &remoteTask) - Allocate memory:
mach_vm_allocate(remoteTask, &address, size, VM_FLAGS_ANYWHERE) - Write shellcode:
mach_vm_write(remoteTask, address, shellcode, length) - Set permissions:
vm_protect(remoteTask, address, size, FALSE, VM_PROT_READ | VM_PROT_EXECUTE) - Create thread:
thread_create_running(remoteTask, ARM_THREAD_STATE64, &state, count, &thread)
Dylib Injection via Task Port
For POSIX-compliant injections:
- Inject shellcode that calls
pthread_create_from_mach_thread - The new pthread can call
to load custom librariesdlopen - This enables more complex injections using system APIs
Thread Hijacking
Instead of creating new threads, hijack existing threads:
- Get task port and enumerate threads via
task_threads - Suspend target thread:
thread_suspend(thread_port) - Modify thread state (PC, SP) to point to injected code
- Resume thread:
thread_resume(thread_port)
Detection and Evasion
Task Port Injection Detection
The kernel increments a counter in the task struct when:
is calledtask_for_pid
is calledthread_create_*
Detection:
task_info(task, TASK_EXTMOD_INFO, ...)
Exception Ports
Exception triage flow:
- Thread exception port
- Task exception ports
- Host port (launchd)
- ReportCrash daemon
Note: Crash reporting tools like
PLCrashReporter handle exceptions within the same task.
Common APIs Reference
Port Management
| API | Purpose |
|---|---|
| Create a port |
| Create a port (alternative) |
| Change port name |
| Get port names from target |
| Get rights over a name |
| Rename a port |
| Create new right in port |
Message Operations
| API | Purpose |
|---|---|
| Send/receive messages |
| Send/receive with different receive buffer |
Complex Messages
For messages with port rights or shared memory:
- Set MSB of
msgh_bits - Use descriptors:
,MACH_MSG_PORT_DESCRIPTOR
, etc.MACH_MSG_OOL_DESCRIPTOR - Kernel copies descriptors to kernel memory first (Feng Shui technique)
Security Considerations
Privilege Escalation Vectors
- Task port access: SEND right enables full process control
- Exception port hijacking: Handle exceptions to gain control
- Bootstrap impersonation: Register fake service names (non-system tasks)
- Port right transfer: Send rights to vulnerable processes
Mitigations
- SIP (System Integrity Protection): Protects system directories and ports
- Hardened Runtime: Restricts task port access
- Entitlements: Control access to sensitive APIs
- Code Signing: Validates binary authenticity
Practical Examples
Basic Port Communication
See the
scripts/ directory for working examples:
: Register a port and receive messagesreceiver.c
: Look up a port and send messagessender.c
Enumerating System Ports
# List all ports for launchd sudo lsmp -p 1 # Find host special ports procexp all ports | grep "HSP" # Check specific process ports lsmp -p <pid>
Debugging IPC
# Start lldb with target application lldb /path/to/app # Set breakpoint on mach_msg (lldb) b mach_msg # Run and inspect (lldb) r (lldb) reg read $x0 $x1 $x2 $x3 $x4 $x5 $x6 (lldb) x/6w $x0
Related Topics
- XPC: Higher-level IPC framework (see
skill)macos-xpc - MIG: Mach Interface Generator for RPC code generation
- Sandbox: macOS sandboxing and entitlements
- Code Signing: Binary signing and verification
References
- Darling Mach Ports Documentation
- Apple XNU Source - mach/message.h
- Apple XNU Source - host_special_ports.h
- [OS Internals, Volume I, User Mode by Jonathan Levin
- Project Zero - Sound Barrier 2
- Sector7 - XPC Audit Token Spoofing