Як я знайшов вразливість у macOS та потрапив до Release Notes від Apple
Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті
Вітаю, я Роман Міщенко, Software Engineer в MacPaw. Ми в компанії використовуємо HackerOne для збору фідбеку ентузіастів, що шукають вразливості в програмному коді. Такий підхід вимагає від інженерів більш заглибленого розуміння особливостей системи, аби зробити продукт захищеним від потенційних атак.
Під час розв’язання однієї задачі, пов’язаної з потенційною вразливістю, я наткнувся на неочікувану поведінку одного з бінарних файлів у системі, що наштовхнуло мене на думку розібрати його детальніше.
Initial Search
У macOS є доволі багато системних утиліт. Частину з них розробникам доволі часто доводиться використовувати у роботі, наприклад otool, man, bundle та інші. Ці утиліти становлять собою бінарні файли, що знаходяться у директорії /usr/bin/
. Ця директорія є захищеною системою, тому навіть маючи привілеї адміністратора, її не можна модифікувати.
Думаю, більшості розробників відомо, що варто бути обережними, використовуючи системні утиліти. Напевно, найголовніше правило —— це прописувати повний шлях до бажаної утиліти. Це робиться для того, аби унеможливити підміну бінарних файлів які викликаються. Звісно, це — не срібна куля від усіх проблем, але перший крок до захисту застосунків від binnary injection.
Як я згадував на початку, під час розв’язання задачі я звернув увагу на утиліту whereis
. Вона призначена для перевірки стандартного бінарного файлу і manual page directories для вказаних програм, друкуючи шляхи будь-яких знайдених програм. Цікавим виявилось те, що виклик цієї утиліти призводив до використання іншого бінарного файлу — xcode-select
. Здавалося б, що нічого дивного, одна утиліта викликає іншу, але саме виклик xcode-select
мав вразливість, оскільки його можна було підмінити на будь-який інший бінарний файл.
Deep Dive
Отже, що я мав на початку? Системна утиліта whereis
десь «під капотом» використовує xcode-select
, до того ж це використання призводить до можливості binary injection. В чому може виникнути проблема? Будь-яка програма, яка буде використовувати whereis
, стає так само вразливою. Проблемне місце є, але ще залишалось знайти причину.
Першим варіантом пошуків було дослідити whereis
через disassembler, але цей варіант мені здався довшим, оскільки прямих викликів xcode-select
всередині whereis
не було.
Другим варіантом був пошук pid (Process ID) всіх процесів, що є у дереві викликів від whereis
до xcode-select
. І тут сама вразливість зіграла мені на руку, оскільки я міг створити свій бінарний файл, який би робив все що мені треба, назвати його xcode-select і згодувати whereis
. Фінальний код всередині мого новоствореного бінаря виглядав ось так:
function get_parent_info { pid=$1 ps -f -p $pid >> "${outfile}" if [[ $pid -ne 0 ]] && [[ $pid -ne 1 ]] ; then parent_pid=$(ps -o ppid= -p $pid) get_parent_info $parent_pid fi }
Для симуляції вразливого застосунку я також створив тестовий проєкт GoodProject.app, в якому додав виклик whereis
. З важливого, я також прописав повний шлях до whereis
, аби упевнитись, що вразливість не на стороні застосунку.
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification { // Insert code here to initialize your application NSArray *arguments = [NSArray arrayWithObjects:@"-c", @"/usr/bin/whereis Safari.app", nil]; NSTask *task = [[NSTask alloc] init]; NSPipe *outputPipe = [[NSPipe alloc] init]; // setup binary and arguments task.launchPath = @"/bin/bash"; task.standardOutput = outputPipe; task.arguments = arguments; // launch task [task launch]; }
Я запустив свій «шкідливий» скрипт, який би підміняв xcode-select
через Enviroment та запускав GoodProject.app. В результаті, я зміг дістати повне дерево виклику. GoodProject запустив whereis
, той викликає manpath
, а вже той викликає підмінений бінарний файл xcode-select
. Отже, проблема дійсно полягає не у whereis
, а, як виявилось, у manpath
.
Утиліта manpath
призначена для визначення шляху пошуку користувача вручну зі шляху користувача та файлів локальної конфігурації. Якщо зазирнути всередину manpath
, то стає зрозуміла причина виникнення всієї вразливості. Apple напряму викликають xcode-select
без повного шляху і через це була можливість підмінити бінарний файл.
#ifdef __APPLE__ xcode_path() { local mpath xmanpaths xmanpaths=$(xcode-select --show-manpaths 2>/dev/null) if [ -n "$xmanpaths" ]; then for mpath in $xmanpaths; do add_to_manpath "$mpath" done fi } #endif
Отже, першопричина знайдена, тепер у нас є можливість запускати неавторизований код через інші застосунки. А це означає, що всі доступи, що має застосунок, буде також мати й наш шкідливий бінарник.
Ще більш цікаво: коли ми спробуємо зробити щось, на що у застосунку немає доступу від системи, то запит на доступ буде йти саме від застосунку. Це відкриває можливість до запиту нових прав, які користувач може дати через довіру до основного застосунку.
Apple Security Research
Apple вже давно має спеціальну програму для дослідників, що шукають вразливості. Apple Security Research сфокусований на проблемах в системному коді iOS, macOS та інших. Як і в усіх програмах Bug Bounty, за підтверджену вразливість дослідник отримує винагороду від компанії.
Що цікаво, в Apple — одні з найбільших винагород на ринку, а мінімальна починається з $5000. Щоправда, це не означає, що кожна знайдена вразливість гідна винагороди. Окрім цього, всі дослідники, хто знайшов підтверджену, вразливість потрапляють у Release Notes до нової версії системи.
Отже, я зібрав результати дослідження та відправив їх до Apple. Варто зазначити, що час відповіді для security-репортів доволі швидкий і зазвичай складав не більше доби. Але все ще довелося детально аргументувати, чому знайдена вразливість є важливою, потенційний вектор атаки та кількість користувачів, що можуть бути у зоні небезпеки. Уся ця інформація важлива для пріоритезації розв’язання проблеми та оцінки її важливості.
За кілька місяців після того, як я зарепортив знайдену проблему, Apple пофіксили її в новому релізі macOS. Тепер manpath
виглядає так:
XCSELECT=/usr/bin/xcode-select #ifdef __APPLE__ xcode_path() { local mpath xmanpaths xmanpaths=$($XCSELECT --show-manpaths 2>/dev/null) if [ -n "$xmanpaths" ]; then for mpath in $xmanpaths; do add_to_manpath "$mpath" done fi } #endif
На момент написання цієї статті, Bounty все ще був у статусі розгляду, що доволі часта ситуація, але Release Notes з визнанням внеску вже були опубліковані.
Висновки
З цієї історії для себе я виніс, що, по-перше, не варто наосліп покладатися на захищеність системи. По-друге, вразливості в системі дуже часто можуть лежати на поверхні. Тож нові випадки знаходяться і виправляються з кожним релізом. Але хто знає які ще лазівки та баги приховані всередині системи.
Якщо ви побачите незадокументовану або просто дивну поведінку, це може сигналізувати про внутрішні проблеми безпеки. Тож кому як не нам, розробникам, які найкраще розбираються в цьому, допомогти Apple покращити захищеність та стабільність iOS та macOS. Оскільки це прямо впливає на безпеку наших продуктів та користувачів.
5 коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарів