macOS Process Abuse
Last updated
Last updated
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Процес — це екземпляр виконуваного файлу, однак процеси не виконують код, це потоки. Тому процеси є лише контейнерами для виконуваних потоків, які забезпечують пам'ять, дескриптори, порти, дозволи...
Традиційно, процеси запускалися в межах інших процесів (за винятком 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:
Використовувати Nano аллокатор libmalloc
_POSIX_SPAWN_ALLOW_DATA_EXEC:
Дозволити rwx
на сегментах даних
POSIX_SPAWN_CLOEXEC_DEFAULT
: Закрити всі файлові дескриптори при exec(2) за замовчуванням
_POSIX_SPAWN_HIGH_BITS_ASLR:
Рандомізувати високі біти слайду ASLR
Більше того, posix_spawn
дозволяє вказати масив posix_spawnattr
, який контролює деякі аспекти створеного процесу, та posix_spawn_file_actions
для зміни стану дескрипторів.
Коли процес завершує свою роботу, він надсилає код повернення батьківському процесу (якщо батьківський процес завершив роботу, новим батьком є PID 1) з сигналом SIGCHLD
. Батьківський процес повинен отримати це значення, викликавши wait4()
або waitid()
, і до того часу дочірній процес залишається в зомбі-стані, де він все ще вказується, але не споживає ресурси.
PID, ідентифікатори процесів, ідентифікують унікальний процес. У XNU PID є 64-бітними, з монотонним збільшенням і ніколи не обертаються (щоб уникнути зловживань).
Процеси можуть бути об'єднані в групи, щоб полегшити їх обробку. Наприклад, команди в сценарії оболонки будуть в одній групі процесів, тому їх можна сигналізувати разом, використовуючи kill, наприклад.
Також можливо групувати процеси в сесії. Коли процес починає сесію (setsid(2)
), дочірні процеси потрапляють у цю сесію, якщо вони не починають свою власну сесію.
Коаліція — це ще один спосіб групувати процеси в Darwin. Процес, що приєднується до коаліції, отримує доступ до ресурсів пулу, ділиться реєстром або стикається з Jetsam. Коаліції мають різні ролі: Лідер, XPC служба, Розширення.
Кожен процес має облікові дані, які ідентифікують його привілеї в системі. Кожен процес матиме один основний uid
та один основний gid
(хоча може належати до кількох груп).
Також можливо змінити ідентифікатор користувача та групи, якщо двійковий файл має біт setuid/setgid
.
Існує кілька функцій для встановлення нових uid/gid.
Системний виклик persona
надає альтернативний набір облікових даних. Прийняття персони передбачає її uid
, gid
та членство в групах одразу. У джерельному коді можна знайти структуру:
POSIX потоки (pthreads): macOS підтримує POSIX потоки (pthreads
), які є частиною стандартного API потоків для C/C++. Реалізація pthreads в macOS знаходиться в /usr/lib/system/libsystem_pthread.dylib
, яка походить з публічно доступного проекту libpthread
. Ця бібліотека надає необхідні функції для створення та управління потоками.
Створення потоків: Функція pthread_create()
використовується для створення нових потоків. Внутрішньо ця функція викликає bsdthread_create()
, яка є системним викликом нижчого рівня, специфічним для ядра XNU (ядро, на якому базується macOS). Цей системний виклик приймає різні прапори, отримані з pthread_attr
(атрибути), які вказують на поведінку потоку, включаючи політики планування та розмір стеку.
Розмір стеку за замовчуванням: Розмір стеку за замовчуванням для нових потоків становить 512 КБ, що є достатнім для типових операцій, але може бути відкориговано через атрибути потоку, якщо потрібно більше або менше місця.
Ініціалізація потоків: Функція __pthread_init()
є критично важливою під час налаштування потоку, використовуючи аргумент env[]
для парсингу змінних середовища, які можуть включати деталі про місцезнаходження та розмір стеку.
Вихід з потоків: Потоки зазвичай завершуються викликом pthread_exit()
. Ця функція дозволяє потоку вийти коректно, виконуючи необхідні дії з очищення та дозволяючи потоку надіслати значення повернення назад до будь-яких приєднувачів.
Очищення потоків: Після виклику pthread_exit()
викликається функція pthread_terminate()
, яка обробляє видалення всіх асоційованих структур потоку. Вона деалоковує порти потоків Mach (Mach є підсистемою зв'язку в ядрі XNU) і викликає bsdthread_terminate
, системний виклик, який видаляє структури на рівні ядра, пов'язані з потоком.
Для управління доступом до спільних ресурсів та уникнення станів гонки macOS надає кілька примітивів синхронізації. Вони є критично важливими в середовищах з багатьма потоками для забезпечення цілісності даних та стабільності системи:
М'ютекси:
Звичайний м'ютекс (Signature: 0x4D555458): Стандартний м'ютекс з обсягом пам'яті 60 байт (56 байт для м'ютекса та 4 байти для підпису).
Швидкий м'ютекс (Signature: 0x4d55545A): Схожий на звичайний м'ютекс, але оптимізований для швидших операцій, також 60 байт в розмірі.
Змінні умов:
Використовуються для очікування настання певних умов, з розміром 44 байти (40 байт плюс 4-байтовий підпис).
Атрибути змінних умов (Signature: 0x434e4441): Атрибути конфігурації для змінних умов, розміром 12 байт.
Змінна один раз (Signature: 0x4f4e4345):
Забезпечує виконання частини коду ініціалізації лише один раз. Її розмір становить 12 байт.
Замки читання-запису:
Дозволяє одночасно кільком читачам або одному записувачу, що сприяє ефективному доступу до спільних даних.
Замок читання-запису (Signature: 0x52574c4b): Розміром 196 байт.
Атрибути замка читання-запису (Signature: 0x52574c41): Атрибути для замків читання-запису, 20 байт в розмірі.
Останні 4 байти цих об'єктів використовуються для виявлення переповнень.
Локальні змінні потоків (TLV) в контексті файлів Mach-O (формат для виконуваних файлів в macOS) використовуються для оголошення змінних, які є специфічними для кожного потоку в багатопоточному додатку. Це забезпечує, що кожен потік має свій власний окремий екземпляр змінної, що дозволяє уникати конфліктів і підтримувати цілісність даних без необхідності в явних механізмах синхронізації, таких як м'ютекси.
У C та пов'язаних мовах ви можете оголосити локальну змінну потоку, використовуючи ключове слово __thread
. Ось як це працює у вашому прикладі:
Цей фрагмент визначає 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:
Значення nice
процесу — це число, яке впливає на його пріоритет. Кожен процес має значення nice в діапазоні від -20 (найвищий пріоритет) до 19 (найнижчий пріоритет). Значення nice за замовчуванням, коли процес створюється, зазвичай становить 0.
Нижче значення nice (ближче до -20) робить процес більш "егоїстичним", надаючи йому більше часу ЦП у порівнянні з іншими процесами з вищими значеннями nice.
Renice:
renice
— це команда, яка використовується для зміни значення nice вже запущеного процесу. Це можна використовувати для динамічного коригування пріоритету процесів, або збільшуючи, або зменшуючи їх виділення часу ЦП на основі нових значень nice.
Наприклад, якщо процесу тимчасово потрібно більше ресурсів ЦП, ви можете знизити його значення nice за допомогою renice
.
Класи QoS є більш сучасним підходом до управління пріоритетами потоків, особливо в системах, таких як macOS, які підтримують Grand Central Dispatch (GCD). Класи QoS дозволяють розробникам категоризувати роботу на різні рівні залежно від їх важливості або терміновості. macOS автоматично управляє пріоритетом потоків на основі цих класів QoS:
Користувацький інтерактивний:
Цей клас призначений для завдань, які в даний момент взаємодіють з користувачем або вимагають негайних результатів для забезпечення хорошого користувацького досвіду. Цим завданням надається найвищий пріоритет, щоб інтерфейс залишався чутливим (наприклад, анімації або обробка подій).
Ініційований користувачем:
Завдання, які ініціює користувач і очікує негайних результатів, такі як відкриття документа або натискання кнопки, що вимагає обчислень. Це високий пріоритет, але нижче, ніж користувацький інтерактивний.
Утиліта:
Ці завдання є тривалими і зазвичай показують індикатор прогресу (наприклад, завантаження файлів, імпорт даних). Вони мають нижчий пріоритет, ніж ініційовані користувачем завдання, і не потребують негайного завершення.
Фонові:
Цей клас призначений для завдань, які працюють у фоновому режимі і не видимі для користувача. Це можуть бути завдання, такі як індексація, синхронізація або резервне копіювання. Вони мають найнижчий пріоритет і мінімальний вплив на продуктивність системи.
Використовуючи класи QoS, розробники не повинні управляти точними номерами пріоритету, а скоріше зосереджуватися на природі завдання, а система оптимізує ресурси ЦП відповідно.
Більше того, існують різні політики планування потоків, які визначають набір параметрів планування, які планувальник враховуватиме. Це можна зробити за допомогою thread_policy_[set/get]
. Це може бути корисно в атаках на умови гонки.
MacOS, як і будь-яка інша операційна система, надає різноманітні методи та механізми для взаємодії, комунікації та обміну даними між процесами. Хоча ці техніки є важливими для ефективного функціонування системи, їх також можуть зловживати зловмисники для вчинення шкідливих дій.
Ін'єкція бібліотек — це техніка, при якій зловмисник примушує процес завантажити шкідливу бібліотеку. Після ін'єкції бібліотека виконується в контексті цільового процесу, надаючи зловмиснику ті ж дозволи та доступ, що й процес.
macOS Library InjectionХук функцій передбачає перехоплення викликів функцій або повідомлень у програмному коді. Перехоплюючи функції, зловмисник може модифікувати поведінку процесу, спостерігати за чутливими даними або навіть отримати контроль над потоком виконання.
macOS Function HookingМіжпроцесна комунікація (IPC) відноситься до різних методів, за допомогою яких окремі процеси діляться та обмінюються даними. Хоча IPC є основоположним для багатьох легітимних застосувань, його також можна зловживати для підриву ізоляції процесів, витоку чутливої інформації або виконання несанкціонованих дій.
macOS IPC - Inter Process CommunicationElectron-додатки, виконувані з певними змінними середовища, можуть бути вразливими до ін'єкції процесів:
macOS Electron Applications InjectionМожливо використовувати прапори --load-extension
та --use-fake-ui-for-media-stream
для виконання атаки "людина в браузері", що дозволяє красти натискання клавіш, трафік, куки, ін'єктувати скрипти на сторінках...:
Файли NIB визначають елементи інтерфейсу користувача (UI) та їх взаємодії в додатку. Однак вони можуть виконувати довільні команди, і Gatekeeper не зупиняє вже виконуваний додаток від повторного виконання, якщо файл NIB модифіковано. Тому їх можна використовувати для виконання довільних команд:
macOS Dirty NIBМожливо зловживати певними можливостями Java (такими як змінна середовища _JAVA_OPTS
) для виконання довільного коду/команд.
Можливо ін'єктувати код у .Net-додатки, зловживаючи функціональністю налагодження .Net (яка не захищена захистами macOS, такими як посилене виконання).
macOS .Net Applications InjectionПеревірте різні варіанти, щоб змусити Perl-скрипт виконати довільний код у:
macOS Perl Applications InjectionТакож можливо зловживати змінними середовища Ruby, щоб змусити довільні скрипти виконати довільний код:
macOS Ruby Applications InjectionЯкщо змінна середовища PYTHONINSPECT
встановлена, процес Python перейде в CLI Python після завершення. Також можливо використовувати PYTHONSTARTUP
, щоб вказати скрипт Python для виконання на початку інтерактивної сесії.
Однак зверніть увагу, що скрипт PYTHONSTARTUP
не буде виконаний, коли PYTHONINSPECT
створює інтерактивну сесію.
Інші змінні середовища, такі як PYTHONPATH
та PYTHONHOME
, також можуть бути корисними для виконання довільного коду Python.
Зверніть увагу, що виконувані файли, скомпільовані за допомогою pyinstaller
, не використовуватимуть ці змінні середовища, навіть якщо вони виконуються за допомогою вбудованого Python.
В цілому, я не зміг знайти спосіб змусити Python виконати довільний код, зловживаючи змінними середовища. Однак більшість людей встановлюють Python за допомогою Homebrew, що встановить Python у записуване місце для користувача за замовчуванням. Ви можете перехопити його чимось на зразок:
Навіть root запустить цей код під час виконання python.
Shield (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 у режимі налагодження, і таким чином ін'єктувати код у нього.
Використовуючи символьні посилання або жорсткі посилання: Зазвичай найпоширеніше зловживання - це розміщення посилання з нашими привілеями та вказівка на місце з вищими привілеями. Виявлення дуже просте як для жорстких, так і для символьних посилань. Якщо процес, що створює посилання, має інший рівень привілеїв, ніж цільовий файл, ми створюємо попередження. На жаль, у випадку символьних посилань блокування неможливе, оскільки ми не маємо інформації про призначення посилання до його створення. Це обмеження фреймворку EndpointSecurity від Apple.
У цьому блозі ви можете дізнатися, як можна використовувати функцію task_name_for_pid
для отримання інформації про інші процеси, що ін'єктують код у процес і потім отримувати інформацію про той інший процес.
Зверніть увагу, що для виклику цієї функції вам потрібно бути тим же uid, що й той, хто виконує процес, або root (і вона повертає інформацію про процес, а не спосіб ін'єкції коду).
Вчіться та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Вчіться та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)