macOS Thread Injection via Task port

Вивчайте хакінг AWS від нуля до героя з htARTE (HackTricks AWS Red Team Expert)!

Інші способи підтримки HackTricks:

Код

1. Перехоплення потоку

Спочатку функція task_threads() викликається на порт завдання для отримання списку потоків з віддаленого завдання. Вибирається потік для перехоплення. Цей підхід відрізняється від традиційних методів впровадження коду, оскільки створення нового віддаленого потоку заборонено через новий захист, який блокує thread_create_running().

Для управління потоком викликається thread_suspend(), зупиняючи його виконання.

Єдині дії, дозволені на віддаленому потоці, полягають у зупинці та запуску його, отриманні та зміні його значень регістрів. Віддалені виклики функцій ініціюються шляхом встановлення регістрів x0 до x7 на аргументи, налаштування pc на цільову функцію та активації потоку. Для забезпечення того, що потік не впаде після повернення, необхідно виявлення повернення.

Одна з стратегій передбачає реєстрацію обробника винятків для віддаленого потоку за допомогою thread_set_exception_ports(), встановлення регістру lr на недійсну адресу перед викликом функції. Це викликає виняток після виконання функції, надсилаючи повідомлення на порт винятків, що дозволяє перевірити стан потоку для відновлення значення повернення. Альтернативно, як у вразливості triple_fetch від Іана Біра, lr встановлюється на нескінченний цикл. Потім регістри потоку безперервно моніторяться, поки pc вказує на цю інструкцію.

2. Mach-порти для зв'язку

Наступна фаза передбачає створення Mach-портів для сприяння зв'язку з віддаленим потоком. Ці порти є інструментальними для передачі довільних прав на відправку та отримання між завданнями.

Для двостороннього зв'язку створюються два Mach-права отримання: одне в локальному, інше в віддаленому завданні. Подальше право на відправку для кожного порту передається відповідному завданню, що дозволяє обмін повідомленнями.

Зосереджуючись на локальному порті, право отримання утримується локальним завданням. Порт створюється за допомогою mach_port_allocate(). Викликано викликано встановлення права на відправку до цього порту в віддаленому потоці за допомогою thread_set_special_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-портів, вкладаючи основу для двостороннього зв'язку.

3. Основні примітиви читання/запису пам'яті

У цьому розділі акцентується на використанні виконавчого примітиву для встановлення основних примітивів читання та запису пам'яті. Ці початкові кроки є важливими для отримання більшого контролю над віддаленим процесом, хоча примітиви на цьому етапі не будуть виконувати багато цілей. Незабаром вони будуть оновлені до більш розширених версій.

Читання та запис пам'яті за допомогою виконавчого примітива

Мета полягає в виконанні читання та запису пам'яті за допомогою конкретних функцій. Для читання пам'яті використовуються функції зі структурою, подібною наступній:

uint64_t read_func(uint64_t *address) {
return *address;
}

І для запису в пам'ять використовуються функції, подібні до цієї структури:

void write_func(uint64_t *address, uint64_t value) {
*address = value;
}

Ці функції відповідають заданим інструкціям збірки:

_read_func:
ldr x0, [x0]
ret
_write_func:
str x1, [x0]
ret

Визначення підходящих функцій

Сканування загальних бібліотек виявило відповідні кандидати для цих операцій:

  1. Читання пам'яті: Функція property_getName() з бібліотеки об'єктно-орієнтованого програмування Objective-C визначена як підходяща функція для читання пам'яті. Нижче наведено опис функції:

const char *property_getName(objc_property_t prop) {
return prop->name;
}

Ця функція ефективно діє, як read_func, повертаючи перше поле objc_property_t.

  1. Запис у пам'ять: Знаходження готової функції для запису в пам'ять є складнішим завданням. Однак функція _xpc_int64_set_value() з libxpc є відповідним кандидатом з наступним розкладом:

__xpc_int64_set_value:
str x1, [x0, #0x18]
ret

Для виконання запису 64-бітного значення за конкретною адресою, віддалений виклик структурований наступним чином:

_xpc_int64_set_value(address - 0x18, value)

З цими примітивами встановлено, що сцена готова для створення спільної пам'яті, що є значним кроком у контролі над віддаленим процесом.

4. Налаштування Спільної Пам'яті

Мета полягає в установленні спільної пам'яті між локальними та віддаленими задачами, спрощуючи передачу даних та полегшуючи виклик функцій з кількома аргументами. Підхід передбачає використання libxpc та його об'єкту типу OS_xpc_shmem, який побудований на основі записів пам'яті Mach.

Огляд Процесу:

  1. Виділення Пам'яті:

  • Виділіть пам'ять для обміну за допомогою mach_vm_allocate().

  • Використовуйте xpc_shmem_create() для створення об'єкту OS_xpc_shmem для виділеної області пам'яті. Ця функція буде керувати створенням запису пам'яті Mach та зберігати право на відправку Mach на зміщенні 0x18 об'єкта OS_xpc_shmem.

  1. Створення Спільної Пам'яті в Віддаленому Процесі:

  • Виділіть пам'ять для об'єкту OS_xpc_shmem в віддаленому процесі за допомогою віддаленого виклику до malloc().

  • Скопіюйте вміст локального об'єкту OS_xpc_shmem в віддалений процес. Однак ця початкова копія матиме неправильні назви записів пам'яті Mach на зміщенні 0x18.

  1. Виправлення Запису Пам'яті Mach:

  • Використовуйте метод thread_set_special_port() для вставки права на відправку для запису пам'яті Mach у віддалену задачу.

  • Виправте поле запису пам'яті Mach на зміщенні 0x18, перезаписавши його ім'ям віддаленого запису пам'яті.

  1. Завершення Налаштування Спільної Пам'яті:

  • Перевірте віддалений об'єкт OS_xpc_shmem.

  • Встановіть спільне відображення пам'яті за допомогою віддаленого виклику до xpc_shmem_remote().

Дотримуючись цих кроків, спільна пам'ять між локальними та віддаленими задачами буде ефективно налаштована, що дозволить просту передачу даних та виконання функцій, які потребують кількох аргументів.

Додаткові Фрагменти Коду

Для виділення пам'яті та створення об'єкту спільної пам'яті:

mach_vm_allocate();
xpc_shmem_create();

Для створення та коригування об'єкта спільної пам'яті в віддаленому процесі:

malloc(); // for allocating memory remotely
thread_set_special_port(); // for inserting send right

5. Досягнення повного контролю

Після успішного встановлення спільної пам'яті та отримання можливостей довільного виконання ми фактично отримали повний контроль над цільовим процесом. Основні функціональні можливості, що забезпечують цей контроль, включають:

  1. Довільні операції з пам'яттю:

    • Виконання довільних читань пам'яті, викликаючи memcpy() для копіювання даних зі спільної області.

    • Виконання довільних записів у пам'ять, використовуючи memcpy() для передачі даних у спільну область.

  2. Обробка викликів функцій з кількома аргументами:

    • Для функцій, які потребують більше 8 аргументів, розмістіть додаткові аргументи на стеку відповідно до конвенції виклику.

  3. Передача портів Mach:

    • Передача портів Mach між завданнями через повідомлення Mach через раніше встановлені порти.

  4. Передача дескрипторів файлів:

    • Передача дескрипторів файлів між процесами за допомогою файлових портів, техніка, виділена Іаном Біром у triple_fetch.

Цей всебічний контроль увібрався в бібліотеку threadexec, яка надає детальну реалізацію та зручний API для взаємодії з цільовим процесом.

Важливі розгляди:

  • Переконайтеся в правильному використанні memcpy() для операцій читання/запису в пам'ять для збереження стабільності системи та цілісності даних.

  • При передачі портів Mach або дескрипторів файлів дотримуйтесь належних протоколів та відповідально керуйте ресурсами, щоб уникнути витоків або ненавмисного доступу.

Дотримуючись цих вказівок та використовуючи бібліотеку threadexec, можна ефективно керувати та взаємодіяти з процесами на дуже детальному рівні, досягаючи повного контролю над цільовим процесом.

Посилання

Last updated