macOS Process Abuse

Підтримайте HackTricks

Основна інформація про процеси

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

Традиційно процеси запускалися всередині інших процесів (крім PID 1), викликаючи fork, який створював точну копію поточного процесу, а потім дочірній процес, як правило, викликав би execve, щоб завантажити новий виконуваний файл і виконати його. Потім був введений vfork, щоб зробити цей процес швидшим без копіювання пам'яті. Потім було введено posix_spawn, яке поєднувало vfork та execve в один виклик і приймало прапорці:

  • POSIX_SPAWN_RESETIDS: Скинути ефективні ідентифікатори на реальні ідентифікатори

  • POSIX_SPAWN_SETPGROUP: Встановити приналежність до групи процесу

  • POSUX_SPAWN_SETSIGDEF: Встановити стандартну поведінку сигналу

  • POSIX_SPAWN_SETSIGMASK: Встановити маску сигналу

  • POSIX_SPAWN_SETEXEC: Виконати в тому ж процесі (схоже на execve з більшими опціями)

  • POSIX_SPAWN_START_SUSPENDED: Почати призупинено

  • _POSIX_SPAWN_DISABLE_ASLR: Почати без ASLR

  • _POSIX_SPAWN_NANO_ALLOCATOR: Використовувати нано-алокатор libmalloc

  • _POSIX_SPAWN_ALLOW_DATA_EXEC: Дозволити rwx на сегментах даних

  • POSIX_SPAWN_CLOEXEC_DEFAULT: Закрити всі описи файлів під час exec(2) за замовчуванням

  • _POSIX_SPAWN_HIGH_BITS_ASLR: Випадкове розташування високих бітів ASLR slide

Крім того, posix_spawn дозволяє вказати масив posix_spawnattr, який контролює деякі аспекти породженого процесу, та posix_spawn_file_actions, щоб змінити стан дескрипторів.

Коли процес помирає, він надсилає код повернення батьківському процесу (якщо батьківський процес помер, новий батько - це PID 1) з сигналом SIGCHLD. Батько повинен отримати це значення, викликавши wait4() або waitid(), і до того часу дитина залишається в зомбі-стані, де вона все ще перераховується, але не використовує ресурси.

PID

PID, ідентифікатори процесів, ідентифікують унікальний процес. У XNU PID складають 64 біти, що зростають монотонно і ніколи не обгортаються (щоб уникнути зловживань).

Групи процесів, сесії та коаліції

Процеси можуть бути включені в групи, щоб легше керувати ними. Наприклад, команди в сценарії оболонки будуть у тій же групі процесів, тому можна сигналізувати їх разом, використовуючи, наприклад, kill. Також можна групувати процеси в сесії. Коли процес запускає сесію (setsid(2)), дочірні процеси розміщуються всередині сесії, якщо вони не запускають власну сесію.

Коаліція - це ще один спосіб групування процесів в Darwin. Процес, який приєднується до коаліції, може отримати доступ до спільних ресурсів, спільного журналу або стикатися з Jetsam. У коаліціях є різні ролі: Лідер, Служба XPC, Розширення.

Облікові дані та Персонажі

Кожен процес має облікові дані, які ідентифікують його привілеї в системі. У кожного процесу є один основний uid та один основний gid (хоча він може належати до кількох груп). Також можливо змінити ідентифікатор користувача та групи, якщо у виконуваного файлу є біт setuid/setgid. Є кілька функцій для встановлення нових uid/gid.

Системний виклик persona надає альтернативний набір облікових даних. Прийняття персонажа передбачає його uid, gid та членство в групах одночасно. У вихідному коді можна знайти структуру:

struct kpersona_info { uint32_t persona_info_version;
uid_t    persona_id; /* overlaps with UID */
int      persona_type;
gid_t    persona_gid;
uint32_t persona_ngroups;
gid_t    persona_groups[NGROUPS];
uid_t    persona_gmuid;
char     persona_name[MAXLOGNAME + 1];

/* TODO: MAC policies?! */
}

Основна інформація про потоки

  1. Потоки POSIX (pthreads): macOS підтримує POSIX-потоки (pthreads), які є частиною стандартного API для роботи з потоками у мовах C/C++. Реалізація pthreads в macOS знаходиться в /usr/lib/system/libsystem_pthread.dylib і походить з проекту libpthread, який є загальнодоступним. Ця бібліотека надає необхідні функції для створення та управління потоками.

  2. Створення потоків: Функція pthread_create() використовується для створення нових потоків. Внутрішньо ця функція викликає bsdthread_create(), яка є системним викликом нижчого рівня, специфічним для ядра XNU (ядро, на якому базується macOS). Цей системний виклик приймає різні прапорці, що походять від pthread_attr (атрибути), які вказують поведінку потоку, включаючи політику планування та розмір стеку.

  • Розмір стеку за замовчуванням: Розмір стеку для нових потоків становить 512 КБ, що достатньо для типових операцій, але може бути налаштований через атрибути потоку, якщо потрібно більше або менше місця.

  1. Ініціалізація потоку: Функція __pthread_init() є ключовою під час налаштування потоку, використовуючи аргумент env[] для розбору змінних середовища, які можуть містити деталі щодо розміру та місця стеку.

Завершення потоку в macOS

  1. Завершення потоків: Потоки зазвичай завершуються за допомогою виклику pthread_exit(). Ця функція дозволяє потоці завершитися чисто, виконуючи необхідне прибирання та дозволяючи потоці повернути значення назад всім приєднаним потокам.

  2. Прибирання потоку: Після виклику pthread_exit() викликається функція pthread_terminate(), яка відповідає за видалення всіх пов'язаних структур потоку. Вона вивільняє порти потоку Mach (Mach - це підсистема зв'язку в ядрі XNU) та викликає bsdthread_terminate, системний виклик, який видаляє структури на рівні ядра, пов'язані з потоком.

Механізми синхронізації

Для управління доступом до спільних ресурсів та уникнення гонок даних macOS надає кілька примітивів синхронізації. Вони є критичними в середовищах з багатьма потоками для забезпечення цілісності даних та стабільності системи:

  1. Мютекси:

  • Звичайний мютекс (Підпис: 0x4D555458): Стандартний мютекс з обсягом пам'яті 60 байтів (56 байтів для мютексу та 4 байти для підпису).

  • Швидкий мютекс (Підпис: 0x4d55545A): Схожий на звичайний мютекс, але оптимізований для швидших операцій, також розміром 60 байтів.

  1. Умовні змінні:

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

  • Атрибути умовної змінної (Підпис: 0x434e4441): Конфігураційні атрибути для умовних змінних, розміром 12 байтів.

  1. Змінна одноразового використання (Підпис: 0x4f4e4345):

  • Забезпечує виконання коду ініціалізації лише один раз. Розмір - 12 байтів.

  1. Блокування читання-запису:

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

  • Блокування читання-запису (Підпис: 0x52574c4b): Розмір - 196 байтів.

  • Атрибути блокування читання-запису (Підпис: 0x52574c41): Атрибути для блокування читання-запису, розміром 20 байтів.

Останні 4 байти цих об'єктів використовуються для виявлення переповнень.

Локальні змінні потоку (TLV)

Локальні змінні потоку (TLV) в контексті файлів Mach-O (формат для виконуваних файлів в macOS) використовуються для оголошення змінних, які є специфічними для кожного потоку в багатопотоковому додатку. Це забезпечує кожному потоці окремий екземпляр змінної, надаючи спосіб уникнути конфліктів та збереження цілісності даних без необхідності явних механізмів синхронізації, таких як мютекси.

У мові C та пов'язаних мовах можна оголосити локальну змінну потоку, використовуючи ключове слово __thread. Ось як це працює у вашому прикладі:

cCopy code__thread int tlv_var;

void main (int argc, char **argv){
tlv_var = 10;
}

Цей уривок визначає tlv_var як змінну локального потоку. Кожен потік, що виконує цей код, матиме свій власний tlv_var, і зміни, які вносить один потік до tlv_var, не впливатимуть на tlv_var в іншому потоці.

У бінарному файлі Mach-O дані, що стосуються локальних змінних потоку, організовані в конкретні розділи:

  • __DATA.__thread_vars: Цей розділ містить метадані про локальні змінні потоку, такі як їх типи та статус ініціалізації.

  • __DATA.__thread_bss: Цей розділ використовується для локальних змінних потоку, які не є явно ініціалізованими. Це частина пам'яті, виділена для даних, ініціалізованих нулями.

Крім того, Mach-O надає конкретний API під назвою tlv_atexit для керування локальними змінними потоку при завершенні потоку. Цей API дозволяє вам реєструвати деструктори - спеціальні функції, які очищають локальні дані потоку при завершенні потоку.

Пріоритети потоків

Розуміння пріоритетів потоків включає розгляд того, як операційна система вирішує, які потоки запускати і коли. Це рішення впливає на рівень пріоритету, призначений кожному потоку. У macOS та подібних системах Unix це вирішується за допомогою концепцій, таких як nice, renice та класи якості обслуговування (QoS).

Nice та Renice

  1. Nice:

  • Значення nice процесу - це число, яке впливає на його пріоритет. У кожного процесу є значення nice від -20 (найвищий пріоритет) до 19 (найнижчий пріоритет). Значення nice за замовчуванням при створенні процесу зазвичай дорівнює 0.

  • Нижче значення nice (ближче до -20) робить процес більш "себеційним", надаючи йому більше часу ЦП порівняно з іншими процесами з вищими значеннями nice.

  1. Renice:

  • renice - це команда, яка використовується для зміни значення nice вже запущеного процесу. Це може бути використано для динамічного налаштування пріоритету процесів, збільшення або зменшення їх виділення часу ЦП на основі нових значень nice.

  • Наприклад, якщо процесу тимчасово потрібні більше ресурсів ЦП, ви можете знизити його значення nice за допомогою renice.

Класи якості обслуговування (QoS)

Класи якості обслуговування - це більш сучасний підхід до керування пріоритетами потоків, особливо в системах, які підтримують Grand Central Dispatch (GCD), такі як macOS. Класи якості обслуговування дозволяють розробникам категоризувати роботу на різні рівні на основі їх важливості або терміновості. macOS автоматично керує пріоритетами потоків на основі цих класів якості обслуговування:

  1. Користувацький інтерактивний:

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

  1. Користувацький ініційований:

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

  1. Допоміжний:

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

  1. Фоновий:

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

Використовуючи класи якості обслуговування, розробники не повинні керувати точними номерами пріоритетів, а зосереджуватися на характері завдання, і система оптимізує використання ресурсів ЦП відповідно.

Крім того, існують різні політики планування потоків, які дозволяють вказати набір параметрів планування, які планувальник буде враховувати. Це можна зробити за допомогою thread_policy_[set/get]. Це може бути корисно при атаках на умови гонки.

Зловживання процесами MacOS

macOS, як і будь-яка інша операційна система, надає різноманітні методи та механізми для взаємодії, комунікації та обміну даними між процесами. Хоча ці техніки є важливими для ефективної роботи системи, їх також можна зловживати зловмисниками для виконання зловмисних дій.

Впровадження бібліотек

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

macOS Library Injection

Перехоплення функцій

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

macOS Function Hooking

Міжпроцесна комунікація

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

macOS IPC - Inter Process Communication

Впровадження додатків на основі Electron

Додатки на основі Electron, виконані з конкретними змінними середовища, можуть бути вразливі до впровадження процесів:

macOS Electron Applications Injection

Впровадження Chromium

Можливо використовувати прапорці --load-extension та --use-fake-ui-for-media-stream для виконання атаки людини в браузері, що дозволяє крадіжку натискань клавіш, трафіку, файлів cookie, впровадження скриптів на сторінках...:

macOS Chromium Injection

Брудний NIB

Файли NIB визначають елементи користувацького інтерфейсу (UI) та їх взаємодії в додатку. Однак вони можуть виконувати довільні команди і Gatekeeper не зупиняє вже виконане додаток від виконання, якщо файл NIB змінено. Тому їх можна використовувати для виконання довільних програм довільних команд:

macOS Dirty NIB

Впровадження додатків Java

Можливо зловживати деякими можливостями Java (наприклад, змінна середовища _JAVA_OPTS) для виконання довільного коду/команд у додатку Java.

macOS Java Applications Injection

Впровадження додатків .Net

Можливо впроваджувати код у додатки .Net, зловживаючи функціональністю налагодження .Net (не захищеною від захисту macOS, такого як жорстке виконання).

macOS .Net Applications Injection

Впровадження Perl

Перевірте різні варіанти, як зробити сценарій Perl виконати довільний код у:

macOS Perl Applications Injection

Впровадження Ruby

Також можливо зловживати змінними середовища Ruby для виконання довільних сценаріїв:

macOS Ruby Applications Injection

Внедрення Python

Якщо змінна середовища PYTHONINSPECT встановлена, процес Python перейде до Python CLI після завершення. Також можна використовувати PYTHONSTARTUP, щоб вказати сценарій Python для виконання на початку інтерактивної сесії. Проте слід зауважити, що сценарій PYTHONSTARTUP не буде виконаний, коли PYTHONINSPECT створює інтерактивну сесію.

Інші змінні середовища, такі як PYTHONPATH та PYTHONHOME, також можуть бути корисними для виконання довільного коду за допомогою команди Python.

Зверніть увагу, що виконувані файли, скомпільовані за допомогою pyinstaller, не будуть використовувати ці змінні середовища, навіть якщо вони виконуються за допомогою вбудованого Python.

Загалом я не зміг знайти способу виконання довільного коду Python, зловживаючи змінними середовища. Проте більшість людей встановлюють Python за допомогою Hombrew, який встановлює Python в записуване місце для типового адміністратора. Ви можете захопити його щось на зразок:

mv /opt/homebrew/bin/python3 /opt/homebrew/bin/python3.old
cat > /opt/homebrew/bin/python3 <<EOF
#!/bin/bash
# Extra hijack code
/opt/homebrew/bin/python3.old "$@"
EOF
chmod +x /opt/homebrew/bin/python3

Навіть root виконає цей код при запуску python.

Виявлення

Щит

Щит (Github) - це відкрите додаток, який може виявляти та блокувати дії з ін'єкцією процесів:

  • Використання змінних середовища: Він буде відстежувати наявність будь-яких з наступних змінних середовища: DYLD_INSERT_LIBRARIES, CFNETWORK_LIBRARY_PATH, RAWCAMERA_BUNDLE_PATH та ELECTRON_RUN_AS_NODE

  • Використання викликів task_for_pid: Щоб знайти, коли один процес хоче отримати порт завдання іншого, що дозволяє внести код у процес.

  • Параметри програм Electron: Хтось може використовувати командний рядок --inspect, --inspect-brk та --remote-debugging-port для запуску програми Electron у режимі налагодження, та таким чином внести код до неї.

  • Використання символічних посилань або жорстких посилань: Зазвичай найпоширенішим зловживанням є розміщення посилання з нашими привілеями користувача, та вказування на місце з вищими привілеями. Виявлення дуже просте як для жорстких, так і для символічних посилань. Якщо процес, який створює посилання, має інший рівень привілеїв, ніж цільовий файл, ми створюємо попередження. Нажаль, у випадку символічних посилань блокування неможливе, оскільки ми не маємо інформації про призначення посилання перед створенням. Це обмеження фреймворку Apple для безпеки кінцевих точок.

Виклики, здійснені іншими процесами

У цьому дописі в блозі ви можете дізнатися, як можна використовувати функцію task_name_for_pid для отримання інформації про інші процеси, що внесли код у процес, а потім отримати інформацію про цей інший процес.

Зверніть увагу, що для виклику цієї функції вам потрібно бути тим самим uid, що і той, що запускає процес, або root (і вона повертає інформацію про процес, а не спосіб внесення коду).

Посилання

Підтримайте HackTricks

Last updated