You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-ipc-inter-process-communication/README.md
+74-10Lines changed: 74 additions & 10 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -439,18 +439,75 @@ int main() {
439
439
{% endtab %}
440
440
{% endtabs %}
441
441
442
-
###Privileged Ports
442
+
## Privileged Ports
443
443
444
-
***Host port**: If a process has **Send** privilege over this port he can get **information** about the **system** (e.g. `host_processor_info`).
445
-
***Host priv port**: A process with **Send** right over this port can perform **privileged actions** like loading a kernel extension. The **process need to be root** to get this permission.
444
+
There are some special ports that allows to **perform certain sensitive actions or access certain sensitive data** in case a tasks have the **SEND** permissions over them. This makes these ports very interesting from an attackers perspective not only because of the capabilities but because it's possible to **share SEND permissions across tasks**.
445
+
446
+
### Host Special Ports
447
+
448
+
These ports are represented by a number.
449
+
450
+
**SEND** rights can be obtained by calling **`host_get_special_port`** and **RECEIVE** rights calling **`host_set_special_port`**. However, both calls require the **`host_priv`** port which only root can access. Moreover, in the past root was able to call **`host_set_special_port`** and hijack arbitrary that allowed for example to bypass code signatures by hijacking `HOST_KEXTD_PORT` (SIP now prevents this).
451
+
452
+
These are divided in 2 groups: The **first 7 ports are owned by the kernel** being the 1 `HOST_PORT`, the 2 `HOST_PRIV_PORT` , the 3 `HOST_IO_MASTER_PORT` and the 7 is `HOST_MAX_SPECIAL_KERNEL_PORT`.\
453
+
The ones starting **from** the number **8** are **owned by system daemons** and they can be found declared in [**`host_special_ports.h`**](https://opensource.apple.com/source/xnu/xnu-4570.1.46/osfmk/mach/host\_special\_ports.h.auto.html).
454
+
455
+
***Host port**: If a process has **SEND** privilege over this port he can get **information** about the **system** calling its routines like:
***Host Priv port**: A process with **SEND** right over this port can perform **privileged actions** like showing boot data or trying to load a kernel extension. The **process need to be root** to get this permission.
446
462
* Moreover, in order to call **`kext_request`** API it's needed to have other entitlements **`com.apple.private.kext*`** which are only given to Apple binaries.
447
-
***Task name port:** An unprivileged version of the _task port_. It references the task, but does not allow controlling it. The only thing that seems to be available through it is `task_info()`.
448
-
***Task port** (aka kernel port)**:** With Send permission over this port it's possible to control the task (read/write memory, create threads...).
449
-
* Call `mach_task_self()` to **get the name** for this port for the caller task. This port is only **inherited** across **`exec()`**; a new task created with `fork()` gets a new task port (as a special case, a task also gets a new task port after `exec()`in a suid binary). The only way to spawn a task and get its port is to perform the ["port swap dance"](https://robert.sesek.com/2014/1/changes\_to\_xnu\_mach\_ipc.html) while doing a `fork()`.
450
-
* These are the restrictions to access the port (from `macos_task_policy` from the binary `AppleMobileFileIntegrity`):
451
-
* If the app has **`com.apple.security.get-task-allow` entitlement** processes from the **same user can access the task port** (commonly added by Xcode for debugging). The **notarization** process won't allow it to production releases.
452
-
* Apps with the **`com.apple.system-task-ports`** entitlement can get the **task port for any** process, except the kernel. In older versions it was called **`task_for_pid-allow`**. This is only granted to Apple applications.
453
-
***Root can access task ports** of applications **not** compiled with a **hardened** runtime (and not from Apple).
463
+
* Other routines that can be called are:
464
+
*`host_get_boot_info`: Get `machine_boot_info()`
465
+
*`host_priv_statistics`: Get privileged statistics
* As **root** can access this permission, it could call `host_set_[special/exception]_port[s]` to **hijack host special or exception ports**.
470
+
471
+
It's possible to **see all the host special ports** by running:
472
+
473
+
```bash
474
+
procexp all ports | grep "HSP"
475
+
```
476
+
477
+
### Task Ports
478
+
479
+
Originally Mach didn't have "processes" it had "tasks" which was considered more like a container of threads. When Mach was merged with BSD **each task was correlated with a BSD process**. Therefore every BSD process has the details it needs to be a process and every Mach task also have its inner workings (except for the inexistent pid 0 which is the `kernel_task`).
480
+
481
+
There are two very interesting functions related to this:
482
+
483
+
*`task_for_pid(target_task_port, pid, &task_port_of_pid)`: Get a SEND right for the task por of the task related to the specified by the `pid` and give it to the indicated `target_task_port` (which is usually the caller task which has used `mach_task_self()`, but could be a SEND port over a different task.)
484
+
*`pid_for_task(task, &pid)`: Given a SEND right to a task, find to which PID this task is related to.
485
+
486
+
In order to perform actions within the task, the task needed a `SEND` right to itself calling `mach_task_self()` (which uses the `task_self_trap` (28)). With this permission a task can perform several actions like:
487
+
488
+
*`task_threads`: Get SEND right over all task ports of the threads of the task
489
+
*`task_info`: Get info about a task
490
+
*`task_suspend/resume`: Suspend or resume a task
491
+
*`task_[get/set]_special_port`
492
+
*`thread_create`: Create a thread
493
+
*`task_[get/set]_state`: Control task state
494
+
* and more can be found in [**mach/task.h**](https://github.com/phracker/MacOSX-SDKs/blob/master/MacOSX11.3.sdk/System/Library/Frameworks/Kernel.framework/Versions/A/Headers/mach/task.h)
495
+
496
+
{% hint style="danger" %}
497
+
Notice that with a SEND right over a task port of a **different task**, it's possible to perform such actions over a different task.
498
+
{% endhint %}
499
+
500
+
Moreover, the task\_port is also the **`vm_map`** port which allows to **read an manipulate memory** inside a task with functions such as `vm_read()` and `vm_write()`. This basically means that a task with SEND rights over the task\_port of a different task is going to be able to **inject code into that task**.
501
+
502
+
Remember that because the **kernel is also a task**, if someone manages to get a **SEND permissions** over the **`kernel_task`**, it'll be able to make the kernel execute anything (jailbreaks).
503
+
504
+
* Call `mach_task_self()` to **get the name** for this port for the caller task. This port is only **inherited** across **`exec()`**; a new task created with `fork()` gets a new task port (as a special case, a task also gets a new task port after `exec()`in a suid binary). The only way to spawn a task and get its port is to perform the ["port swap dance"](https://robert.sesek.com/2014/1/changes\_to\_xnu\_mach\_ipc.html) while doing a `fork()`.
505
+
* These are the restrictions to access the port (from `macos_task_policy` from the binary `AppleMobileFileIntegrity`):
506
+
* If the app has **`com.apple.security.get-task-allow` entitlement** processes from the **same user can access the task port** (commonly added by Xcode for debugging). The **notarization** process won't allow it to production releases.
507
+
* Apps with the **`com.apple.system-task-ports`** entitlement can get the **task port for any** process, except the kernel. In older versions it was called **`task_for_pid-allow`**. This is only granted to Apple applications.
508
+
***Root can access task ports** of applications **not** compiled with a **hardened** runtime (and not from Apple).
509
+
510
+
**The task name port:** An unprivileged version of the _task port_. It references the task, but does not allow controlling it. The only thing that seems to be available through it is `task_info()`.
454
511
455
512
### Shellcode Injection in thread via Task port
456
513
@@ -514,6 +571,9 @@ processIdentifier]);
514
571
515
572
```objectivec
516
573
// gcc -framework Foundation -framework Appkit sc_injector.m -o sc_injector
574
+
// Based on https://gist.github.com/knightsc/45edfc4903a9d2fa9f5905f60b02ce5a?permalink_comment_id=2981669
575
+
// and on https://newosxbook.com/src.jl?tree=listings&file=inject.c
For this to work on iOS you need the entitlement `dynamic-codesigning` in order to be able to make a writable memory executable.
781
+
{% endhint %}
782
+
719
783
### Dylib Injection in thread via Task port
720
784
721
785
In macOS **threads** might be manipulated via **Mach** or using **posix `pthread` api**. The thread we generated in the previos injection, was generated using Mach api, so **it's not posix compliant**.
0 commit comments