macOS Process Abuse
Основна інформація про процеси
Процес є екземпляром запущеного виконуваного файлу, однак процеси не виконують код, це потоки. Тому процеси є лише контейнерами для виконання потоків, які забезпечують пам'ять, дескриптори, порти, дозволи...
Традиційно процеси запускалися всередині інших процесів (крім 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 та членство в групах одночасно. У вихідному коді можна знайти структуру:
Основна інформація про потоки
Потоки 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[]
для розбору змінних середовища, які можуть містити деталі щодо розміру та місця стеку.
Завершення потоку в macOS
Завершення потоків: Потоки зазвичай завершуються за допомогою виклику
pthread_exit()
. Ця функція дозволяє потоці завершитися чисто, виконуючи необхідне прибирання та дозволяючи потоці повернути значення назад всім приєднаним потокам.Прибирання потоку: Після виклику
pthread_exit()
викликається функціяpthread_terminate()
, яка відповідає за видалення всіх пов'язаних структур потоку. Вона вивільняє порти потоку Mach (Mach - це підсистема зв'язку в ядрі XNU) та викликаєbsdthread_terminate
, системний виклик, який видаляє структури на рівні ядра, пов'язані з потоком.
Механізми синхронізації
Для управління доступом до спільних ресурсів та уникнення гонок даних macOS надає кілька примітивів синхронізації. Вони є критичними в середовищах з багатьма потоками для забезпечення цілісності даних та стабільності системи:
Мютекси:
Звичайний мютекс (Підпис: 0x4D555458): Стандартний мютекс з обсягом пам'яті 60 байтів (56 байтів для мютексу та 4 байти для підпису).
Швидкий мютекс (Підпис: 0x4d55545A): Схожий на звичайний мютекс, але оптимізований для швидших операцій, також розміром 60 байтів.
Умовні змінні:
Використовуються для очікування виникнення певних умов, розміром 44 байти (40 байтів плюс 4-байтовий підпис).
Атрибути умовної змінної (Підпис: 0x434e4441): Конфігураційні атрибути для умовних змінних, розміром 12 байтів.
Змінна одноразового використання (Підпис: 0x4f4e4345):
Забезпечує виконання коду ініціалізації лише один раз. Розмір - 12 байтів.
Блокування читання-запису:
Дозволяє одночасно багатьом читачам або одному письменнику, полегшуючи ефективний доступ до спільних даних.
Блокування читання-запису (Підпис: 0x52574c4b): Розмір - 196 байтів.
Атрибути блокування читання-запису (Підпис: 0x52574c41): Атрибути для блокування читання-запису, розміром 20 байтів.
Останні 4 байти цих об'єктів використовуються для виявлення переповнень.
Локальні змінні потоку (TLV)
Локальні змінні потоку (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 та Renice
Nice:
Значення
nice
процесу - це число, яке впливає на його пріоритет. У кожного процесу є значення nice від -20 (найвищий пріоритет) до 19 (найнижчий пріоритет). Значення nice за замовчуванням при створенні процесу зазвичай дорівнює 0.Нижче значення nice (ближче до -20) робить процес більш "себеційним", надаючи йому більше часу ЦП порівняно з іншими процесами з вищими значеннями nice.
Renice:
renice
- це команда, яка використовується для зміни значення nice вже запущеного процесу. Це може бути використано для динамічного налаштування пріоритету процесів, збільшення або зменшення їх виділення часу ЦП на основі нових значень nice.Наприклад, якщо процесу тимчасово потрібні більше ресурсів ЦП, ви можете знизити його значення nice за допомогою
renice
.
Класи якості обслуговування (QoS)
Класи якості обслуговування - це більш сучасний підхід до керування пріоритетами потоків, особливо в системах, які підтримують Grand Central Dispatch (GCD), такі як macOS. Класи якості обслуговування дозволяють розробникам категоризувати роботу на різні рівні на основі їх важливості або терміновості. macOS автоматично керує пріоритетами потоків на основі цих класів якості обслуговування:
Користувацький інтерактивний:
Цей клас призначений для завдань, які в даний момент взаємодіють з користувачем або потребують негайних результатів для забезпечення гарного досвіду користувача. Цим завданням надається найвищий пріоритет для збереження реактивності інтерфейсу (наприклад, анімації або обробка подій).
Користувацький ініційований:
Завдання, які користувач ініціює та очікує негайних результатів, такі як відкриття документа або натискання кнопки, що вимагає обчислень. Це високий пріоритет, але нижче за користувацький інтерактивний.
Допоміжний:
Ці завдання тривалі й зазвичай показують індикатор прогресу (наприклад, завантаження файлів, імпорт даних). Вони мають нижчий пріоритет, ніж завдання, ініційовані користувачем, і не повинні завершуватися негайно.
Фоновий:
Цей клас призначений для завдань, які працюють в фоновому режимі і не є видимими для користувача. Це можуть бути завдання, такі як індексація, синхронізація або резервне копіювання. Вони мають найнижчий пріоритет і мінімальний вплив на продуктивність системи.
Використовуючи класи якості обслуговування, розробники не повинні керувати точними номерами пріоритетів, а зосереджуватися на характері завдання, і система оптимізує використання ресурсів ЦП відповідно.
Крім того, існують різні політики планування потоків, які дозволяють вказати набір параметрів планування, які планувальник буде враховувати. Це можна зробити за допомогою thread_policy_[set/get]
. Це може бути корисно при атаках на умови гонки.
Зловживання процесами MacOS
macOS, як і будь-яка інша операційна система, надає різноманітні методи та механізми для взаємодії, комунікації та обміну даними між процесами. Хоча ці техніки є важливими для ефективної роботи системи, їх також можна зловживати зловмисниками для виконання зловмисних дій.
Впровадження бібліотек
Впровадження бібліотек - це техніка, при якій зловмисник змушує процес завантажити зловісну бібліотеку. Після впровадження бібліотека працює в контексті цільового процесу, надаючи зловмиснику ті самі дозволи та доступ, що й процес.
Перехоплення функцій
Перехоплення функцій передбачає перехоплення викликів функцій або повідомлень у програмному коді. Перехоплюючи функції, зловмисник може змінювати поведінку процесу, спостерігати за чутливими даними або навіть отримувати контроль над потоком виконання.
Міжпроцесна комунікація
Міжпроцесна комунікація (IPC) відноситься до різних методів, за допомогою яких окремі процеси обмінюються даними. Хоча IPC є фундаментальним для багатьох законних додатків, його також можна зловживати для обхіду ізоляції процесів, витоку чутливої інформації або виконання несанкціонованих дій.
Впровадження додатків на основі Electron
Додатки на основі Electron, виконані з конкретними змінними середовища, можуть бути вразливі до впровадження процесів:
Впровадження Chromium
Можливо використовувати прапорці --load-extension
та --use-fake-ui-for-media-stream
для виконання атаки людини в браузері, що дозволяє крадіжку натискань клавіш, трафіку, файлів cookie, впровадження скриптів на сторінках...:
Брудний NIB
Файли NIB визначають елементи користувацького інтерфейсу (UI) та їх взаємодії в додатку. Однак вони можуть виконувати довільні команди і Gatekeeper не зупиняє вже виконане додаток від виконання, якщо файл NIB змінено. Тому їх можна використовувати для виконання довільних програм довільних команд:
Впровадження додатків Java
Можливо зловживати деякими можливостями Java (наприклад, змінна середовища _JAVA_OPTS
) для виконання довільного коду/команд у додатку Java.
Впровадження додатків .Net
Можливо впроваджувати код у додатки .Net, зловживаючи функціональністю налагодження .Net (не захищеною від захисту macOS, такого як жорстке виконання).
Впровадження Perl
Перевірте різні варіанти, як зробити сценарій Perl виконати довільний код у:
Впровадження Ruby
Також можливо зловживати змінними середовища Ruby для виконання довільних сценаріїв:
Внедрення Python
Якщо змінна середовища PYTHONINSPECT
встановлена, процес Python перейде до Python CLI після завершення. Також можна використовувати PYTHONSTARTUP
, щоб вказати сценарій Python для виконання на початку інтерактивної сесії.
Проте слід зауважити, що сценарій PYTHONSTARTUP
не буде виконаний, коли PYTHONINSPECT
створює інтерактивну сесію.
Інші змінні середовища, такі як PYTHONPATH
та PYTHONHOME
, також можуть бути корисними для виконання довільного коду за допомогою команди Python.
Зверніть увагу, що виконувані файли, скомпільовані за допомогою pyinstaller
, не будуть використовувати ці змінні середовища, навіть якщо вони виконуються за допомогою вбудованого Python.
Загалом я не зміг знайти способу виконання довільного коду Python, зловживаючи змінними середовища. Проте більшість людей встановлюють Python за допомогою Hombrew, який встановлює Python в записуване місце для типового адміністратора. Ви можете захопити його щось на зразок:
Навіть 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 (і вона повертає інформацію про процес, а не спосіб внесення коду).
Посилання
Last updated