diff --git a/src/macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-ipc-inter-process-communication/macos-thread-injection-via-task-port.md b/src/macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-ipc-inter-process-communication/macos-thread-injection-via-task-port.md index acce5b44a..0f333c621 100644 --- a/src/macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-ipc-inter-process-communication/macos-thread-injection-via-task-port.md +++ b/src/macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-ipc-inter-process-communication/macos-thread-injection-via-task-port.md @@ -7,49 +7,49 @@ - [https://github.com/bazad/threadexec](https://github.com/bazad/threadexec) - [https://gist.github.com/knightsc/bd6dfeccb02b77eb6409db5601dcef36](https://gist.github.com/knightsc/bd6dfeccb02b77eb6409db5601dcef36) -## 1. Захоплення потоку +## 1. Thread Hijacking -Спочатку функція **`task_threads()`** викликається на порту завдання для отримання списку потоків з віддаленого завдання. Один з потоків обирається для захоплення. Цей підхід відрізняється від звичайних методів ін'єкції коду, оскільки створення нового віддаленого потоку заборонено через нові заходи, що блокують `thread_create_running()`. +Спочатку викликається функція `task_threads()` на порту задачі для отримання списку потоків з віддаленої задачі. Вибирається потік для захоплення. Цей підхід відрізняється від звичайних методів ін'єкції коду, оскільки створення нового віддаленого потоку заборонено через міру, яка блокує `thread_create_running()`. -Для контролю потоку викликається **`thread_suspend()`**, що зупиняє його виконання. +Для контролю потоку викликається `thread_suspend()`, що зупиняє його виконання. -Єдині операції, дозволені на віддаленому потоці, включають **зупинку** та **початок** його, **отримання** та **модифікацію** значень його регістрів. Віддалені виклики функцій ініціюються шляхом налаштування регістрів `x0` до `x7` на **аргументи**, налаштування **`pc`** на цільову функцію та активації потоку. Забезпечення того, щоб потік не зламався після повернення, вимагає виявлення повернення. +Єдині операції, дозволені на віддаленому потоці, включають **зупинку** та **початок** його роботи, а також **отримання**/**модифікацію** значень його регістрів. Віддалені виклики функцій ініціюються шляхом встановлення регістрів `x0` до `x7` на **аргументи**, налаштування `pc` на цільову функцію та відновлення потоку. Забезпечення того, щоб потік не зламався після повернення, вимагає виявлення повернення. -Одна зі стратегій полягає в **реєстрації обробника виключень** для віддаленого потоку за допомогою `thread_set_exception_ports()`, налаштовуючи регістр `lr` на недійсну адресу перед викликом функції. Це викликає виключення після виконання функції, надсилаючи повідомлення на порт виключень, що дозволяє перевірити стан потоку для відновлення значення повернення. Альтернативно, як це було прийнято з експлойту Іана Біра triple_fetch, `lr` налаштовується на безкінечний цикл. Регістри потоку потім постійно моніторяться, поки **`pc` не вказує на цю інструкцію**. +Одна зі стратегій полягає в реєстрації **обробника виключень** для віддаленого потоку за допомогою `thread_set_exception_ports()`, встановлюючи регістр `lr` на недійсну адресу перед викликом функції. Це викликає виключення після виконання функції, надсилаючи повідомлення на порт виключень, що дозволяє перевірити стан потоку для відновлення значення повернення. Альтернативно, як це було прийнято з експлойту *triple_fetch* Іана Біра, `lr` встановлюється на безкінечний цикл; регістри потоку потім постійно моніторяться, поки `pc` не вказує на цю інструкцію. -## 2. Mach порти для зв'язку +## 2. Mach ports for communication -Наступний етап полягає в створенні Mach портів для полегшення зв'язку з віддаленим потоком. Ці порти є важливими для передачі довільних прав на відправлення та отримання між завданнями. +Наступний етап полягає в створенні Mach портів для полегшення зв'язку з віддаленим потоком. Ці порти є важливими для передачі довільних прав на відправлення/отримання між задачами. -Для двостороннього зв'язку створюються два права на отримання Mach: одне в локальному, а інше в віддаленому завданні. Потім право на відправлення для кожного порту передається до відповідного завдання, що дозволяє обмінюватися повідомленнями. +Для двостороннього зв'язку створюються два права на отримання Mach: одне в локальній, а інше в віддаленій задачі. Потім право на відправлення для кожного порту передається до відповідної задачі, що дозволяє обмінюватися повідомленнями. -Зосереджуючись на локальному порту, право на отримання утримується локальним завданням. Порт створюється за допомогою `mach_port_allocate()`. Виклик полягає в передачі права на відправлення до цього порту в віддалене завдання. +Зосереджуючись на локальному порту, право на отримання утримується локальною задачею. Порт створюється за допомогою `mach_port_allocate()`. Виклик виклику полягає в передачі права на відправлення до цього порту в віддалену задачу. -Одна зі стратегій полягає в використанні `thread_set_special_port()` для розміщення права на відправлення до локального порту в `THREAD_KERNEL_PORT` віддаленого потоку. Потім віддаленому потоку надається команда викликати `mach_thread_self()`, щоб отримати право на відправлення. +Стратегія полягає в використанні `thread_set_special_port()`, щоб помістити право на відправлення до локального порту в `THREAD_KERNEL_PORT` віддаленого потоку. Потім віддаленому потоку вказується викликати `mach_thread_self()`, щоб отримати право на відправлення. -Для віддаленого порту процес в основному обернений. Віддаленому потоку надається команда створити Mach порт за допомогою `mach_reply_port()` (оскільки `mach_port_allocate()` не підходить через свій механізм повернення). Після створення порту викликається `mach_port_insert_right()` в віддаленому потоці для встановлення права на відправлення. Це право потім зберігається в ядрі за допомогою `thread_set_special_port()`. Повертаючись до локального завдання, використовується `thread_get_special_port()` на віддаленому потоці для отримання права на відправлення до новоствореного Mach порту в віддаленому завданні. +Для віддаленого порту процес в основному обернений. Віддаленому потоку вказується створити Mach порт за допомогою `mach_reply_port()` (оскільки `mach_port_allocate()` не підходить через свій механізм повернення). Після створення порту викликається `mach_port_insert_right()` в віддаленому потоці для встановлення права на відправлення. Це право потім зберігається в ядрі за допомогою `thread_set_special_port()`. Повертаючись до локальної задачі, використовується `thread_get_special_port()` на віддаленому потоці, щоб отримати право на відправлення до новоствореного Mach порту в віддаленій задачі. Завершення цих кроків призводить до створення Mach портів, закладаючи основу для двостороннього зв'язку. -## 3. Основні примітиви читання/запису пам'яті +## 3. Basic Memory Read/Write Primitives -У цьому розділі увага зосереджена на використанні примітиву виконання для встановлення основних примітивів читання та запису пам'яті. Ці початкові кроки є вирішальними для отримання більшого контролю над віддаленим процесом, хоча примітиви на цьому етапі не виконуватимуть багато функцій. Незабаром вони будуть оновлені до більш просунутих версій. +У цьому розділі увага зосереджена на використанні примітиву виконання для встановлення базових примітивів читання/запису пам'яті. Ці початкові кроки є важливими для отримання більшого контролю над віддаленим процесом, хоча примітиви на цьому етапі не будуть мати багато застосувань. Незабаром вони будуть оновлені до більш просунутих версій. -### Читання та запис пам'яті за допомогою примітиву виконання +### Memory reading and writing using the execute primitive -Мета полягає в тому, щоб виконати читання та запис пам'яті за допомогою специфічних функцій. Для читання пам'яті використовуються функції, що нагадують наступну структуру: +Мета полягає в тому, щоб виконати читання та запис пам'яті за допомогою специфічних функцій. Для **читання пам'яті**: ```c uint64_t read_func(uint64_t *address) { return *address; } ``` -І для запису в пам'ять використовуються функції, подібні до цієї структури: +Для **запису пам'яті**: ```c void write_func(uint64_t *address, uint64_t value) { *address = value; } ``` -Ці функції відповідають наведеним асемблерним інструкціям: +Ці функції відповідають наступному асемблеру: ``` _read_func: ldr x0, [x0] @@ -62,100 +62,112 @@ ret Сканування загальних бібліотек виявило відповідні кандидати для цих операцій: -1. **Читання пам'яті:** -Функція `property_getName()` з [Objective-C runtime library](https://opensource.apple.com/source/objc4/objc4-723/runtime/objc-runtime-new.mm.auto.html) визначена як підходяща функція для читання пам'яті. Функція описана нижче: +1. **Читання пам'яті — `property_getName()`** (libobjc): ```c const char *property_getName(objc_property_t prop) { return prop->name; } ``` -Ця функція фактично діє як `read_func`, повертаючи перше поле `objc_property_t`. - -2. **Запис пам'яті:** -Знайти готову функцію для запису пам'яті складніше. Однак функція `_xpc_int64_set_value()` з libxpc є відповідним кандидатом з наступним дизасемблюванням: +2. **Запис пам'яті — `_xpc_int64_set_value()`** (libxpc): ```c __xpc_int64_set_value: str x1, [x0, #0x18] ret ``` -Щоб виконати запис 64-бітного значення за певною адресою, віддалений виклик структурований як: +Щоб виконати запис 64-бітного значення за довільною адресою: ```c -_xpc_int64_set_value(address - 0x18, value) +_xpc_int64_set_value(address - 0x18, value); ``` -З встановленими цими примітивами, сцена готова для створення спільної пам'яті, що є значним прогресом у контролі віддаленого процесу. +З цими примітивами встановленими, сцена готова для створення спільної пам'яті, що є значним прогресом у контролі над віддаленим процесом. ## 4. Налаштування спільної пам'яті -Мета полягає в тому, щоб встановити спільну пам'ять між локальними та віддаленими завданнями, спрощуючи передачу даних і полегшуючи виклик функцій з кількома аргументами. Підхід передбачає використання `libxpc` та його об'єктного типу `OS_xpc_shmem`, який побудований на основі записів пам'яті Mach. +Мета полягає в тому, щоб встановити спільну пам'ять між локальними та віддаленими завданнями, спрощуючи передачу даних і полегшуючи виклик функцій з кількома аргументами. Підхід використовує `libxpc` та його об'єкт типу `OS_xpc_shmem`, який побудований на основі записів пам'яті Mach. -### Огляд процесу: +### Огляд процесу -1. **Виділення пам'яті**: +1. **Виділення пам'яті** +* Виділити пам'ять для спільного використання за допомогою `mach_vm_allocate()`. +* Використати `xpc_shmem_create()` для створення об'єкта `OS_xpc_shmem` для виділеної області. +2. **Створення спільної пам'яті в віддаленому процесі** +* Виділити пам'ять для об'єкта `OS_xpc_shmem` у віддаленому процесі (`remote_malloc`). +* Скопіювати локальний шаблон об'єкта; виправлення вбудованого права на відправлення Mach за зміщенням `0x18` все ще необхідне. +3. **Виправлення запису пам'яті Mach** +* Вставити право на відправлення за допомогою `thread_set_special_port()` і перезаписати поле `0x18` ім'ям віддаленого запису. +4. **Завершення** +* Перевірити віддалений об'єкт і відобразити його за допомогою віддаленого виклику `xpc_shmem_remote()`. -- Виділіть пам'ять для спільного використання за допомогою `mach_vm_allocate()`. -- Використовуйте `xpc_shmem_create()` для створення об'єкта `OS_xpc_shmem` для виділеної області пам'яті. Ця функція керуватиме створенням запису пам'яті Mach і зберігатиме право на відправку Mach за зсувом `0x18` об'єкта `OS_xpc_shmem`. +## 5. Досягнення повного контролю -2. **Створення спільної пам'яті в віддаленому процесі**: +Якщо доступне довільне виконання та канал зворотного зв'язку зі спільною пам'яттю, ви ефективно володієте цільовим процесом: -- Виділіть пам'ять для об'єкта `OS_xpc_shmem` в віддаленому процесі за допомогою віддаленого виклику `malloc()`. -- Скопіюйте вміст локального об'єкта `OS_xpc_shmem` до віддаленого процесу. Однак ця початкова копія матиме неправильні імена записів пам'яті Mach за зсувом `0x18`. +* **Довільний R/W пам'яті** — використовуйте `memcpy()` між локальними та спільними регіонами. +* **Виклики функцій з > 8 аргументами** — розмістіть додаткові аргументи на стеку відповідно до виклику arm64. +* **Передача порту Mach** — передавайте права в повідомленнях Mach через встановлені порти. +* **Передача дескриптора файлу** — використовуйте fileports (див. *triple_fetch*). -3. **Виправлення запису пам'яті Mach**: +Усе це обгорнуто в бібліотеці [`threadexec`](https://github.com/bazad/threadexec) для зручного повторного використання. -- Використовуйте метод `thread_set_special_port()` для вставки права на відправку для запису пам'яті Mach у віддалене завдання. -- Виправте поле запису пам'яті Mach за зсувом `0x18`, перезаписавши його іменем запису віддаленої пам'яті. +--- -4. **Завершення налаштування спільної пам'яті**: -- Перевірте віддалений об'єкт `OS_xpc_shmem`. -- Встановіть відображення спільної пам'яті за допомогою віддаленого виклику `xpc_shmem_remote()`. +## 6. Особливості Apple Silicon (arm64e) -Дотримуючись цих кроків, спільна пам'ять між локальними та віддаленими завданнями буде ефективно налаштована, що дозволить здійснювати прості передачі даних і виконувати функції, які потребують кількох аргументів. +На пристроях Apple Silicon (arm64e) **Коди автентифікації вказівників (PAC)** захищають всі адреси повернення та багато вказівників функцій. Техніки захоплення потоків, які *повторно використовують існуючий код*, продовжують працювати, оскільки оригінальні значення в `lr`/`pc` вже мають дійсні підписи PAC. Проблеми виникають, коли ви намагаєтеся стрибнути до пам'яті, контрольованої зловмисником: -## Додаткові фрагменти коду - -Для виділення пам'яті та створення об'єкта спільної пам'яті: +1. Виділити виконувану пам'ять всередині цілі (віддалений `mach_vm_allocate` + `mprotect(PROT_EXEC)`). +2. Скопіювати ваш вантаж. +3. Всередині *віддаленого* процесу підписати вказівник: ```c -mach_vm_allocate(); -xpc_shmem_create(); +uint64_t ptr = (uint64_t)payload; +ptr = ptrauth_sign_unauthenticated((void*)ptr, ptrauth_key_asia, 0); ``` -Для створення та виправлення об'єкта спільної пам'яті в віддаленому процесі: -```c -malloc(); // for allocating memory remotely -thread_set_special_port(); // for inserting send right +4. Встановіть `pc = ptr` у стані захопленого потоку. + +Альтернативно, дотримуйтесь стандарту PAC, з'єднуючи існуючі гаджети/функції (традиційний ROP). + +## 7. Виявлення та зміцнення з EndpointSecurity + +Фреймворк **EndpointSecurity (ES)** відкриває події ядра, які дозволяють захисникам спостерігати або блокувати спроби ін'єкції потоків: + +* `ES_EVENT_TYPE_AUTH_GET_TASK` – спрацьовує, коли процес запитує порт іншого завдання (наприклад, `task_for_pid()`). +* `ES_EVENT_TYPE_NOTIFY_REMOTE_THREAD_CREATE` – виводиться щоразу, коли створюється потік у *іншому* завданні. +* `ES_EVENT_TYPE_NOTIFY_THREAD_SET_STATE` (додано в macOS 14 Sonoma) – вказує на маніпуляцію реєстрами існуючого потоку. + +Мінімальний клієнт Swift, який виводить події віддалених потоків: +```swift +import EndpointSecurity + +let client = try! ESClient(subscriptions: [.notifyRemoteThreadCreate]) { +(_, msg) in +if let evt = msg.remoteThreadCreate { +print("[ALERT] remote thread in pid \(evt.target.pid) by pid \(evt.thread.pid)") +} +} +RunLoop.main.run() ``` -Пам'ятайте, щоб правильно обробляти деталі Mach портів та імен записів пам'яті, щоб забезпечити правильну роботу налаштування спільної пам'яті. +Запит з **osquery** ≥ 5.8: +```sql +SELECT target_pid, source_pid, target_path +FROM es_process_events +WHERE event_type = 'REMOTE_THREAD_CREATE'; +``` +### Розгляди щодо захищеного виконання -## 5. Досягнення Повного Контролю +Розповсюдження вашого додатку **без** права `com.apple.security.get-task-allow` запобігає не-root зловмисникам від отримання його task-port. Захист цілісності системи (SIP) все ще блокує доступ до багатьох бінарних файлів Apple, але стороннє програмне забезпечення повинно явно відмовитися від цього. -Після успішного встановлення спільної пам'яті та отримання можливостей довільного виконання, ми фактично отримали повний контроль над цільовим процесом. Ключові функціональні можливості, що забезпечують цей контроль, це: +## 8. Останні публічні інструменти (2023-2025) -1. **Довільні Операції з Пам'яттю**: +| Інструмент | Рік | Зауваження | +|------------|-----|------------| +| [`task_vaccine`](https://github.com/rodionovd/task_vaccine) | 2023 | Компактний PoC, що демонструє захоплення потоків з урахуванням PAC на Ventura/Sonoma | +| `remote_thread_es` | 2024 | Допоміжний засіб EndpointSecurity, що використовується кількома постачальниками EDR для відображення подій `REMOTE_THREAD_CREATE` | -- Виконувати довільні читання пам'яті, викликаючи `memcpy()`, щоб копіювати дані з спільної області. -- Виконувати довільні записи пам'яті, використовуючи `memcpy()`, щоб передавати дані до спільної області. - -2. **Обробка Викликів Функцій з Багатьма Аргументами**: - -- Для функцій, які вимагають більше 8 аргументів, розмістіть додаткові аргументи на стеку відповідно до конвенції виклику. - -3. **Передача Mach Портів**: - -- Передача Mach портів між задачами через Mach повідомлення через раніше встановлені порти. - -4. **Передача Дескрипторів Файлів**: -- Передача дескрипторів файлів між процесами за допомогою fileports, техніки, підкресленої Іаном Бірем у `triple_fetch`. - -Цей всебічний контроль закріплений у бібліотеці [threadexec](https://github.com/bazad/threadexec), що надає детальну реалізацію та зручний API для взаємодії з жертвою процесом. - -## Важливі Міркування: - -- Забезпечте правильне використання `memcpy()` для операцій читання/запису пам'яті, щоб підтримувати стабільність системи та цілісність даних. -- При передачі Mach портів або дескрипторів файлів дотримуйтесь належних протоколів і відповідально обробляйте ресурси, щоб запобігти витокам або ненавмисному доступу. - -Дотримуючись цих рекомендацій та використовуючи бібліотеку `threadexec`, можна ефективно керувати та взаємодіяти з процесами на детальному рівні, досягаючи повного контролю над цільовим процесом. +> Читання вихідного коду цих проектів корисне для розуміння змін API, введених в macOS 13/14, і для підтримки сумісності між Intel ↔ Apple Silicon. ## Посилання - [https://bazad.github.io/2018/10/bypassing-platform-binary-task-threads/](https://bazad.github.io/2018/10/bypassing-platform-binary-task-threads/) +- [https://github.com/rodionovd/task_vaccine](https://github.com/rodionovd/task_vaccine) +- [https://developer.apple.com/documentation/endpointsecurity/es_event_type_notify_remote_thread_create](https://developer.apple.com/documentation/endpointsecurity/es_event_type_notify_remote_thread_create) {{#include ../../../../banners/hacktricks-training.md}}