
Запись в блоге, исследующая macOS App Sandbox, энтайтлменты через codesign и техники выхода из песочницы с использованием launchd, LaunchAgents и атрибутов карантина.
Продолжая серию постов о моём переходе на macOS, я хотел бы немного обсудить песочницу приложений macOS.
Настоятельно рекомендуется сначала прочитать пост о структуре приложений macOS — я буду предполагать, что читатель знает разницу между приложениями и процессами (задачами), немного разбирается в launchd и его связи с запуском приложений.
Когда я впервые узнал о песочнице macOS, я наивно попытался создать вредоносный макрос Word.
Это (до сих пор) очень распространённый вектор атак в экосистеме Windows, поэтому я хотел проверить, смогу ли я просто запускать процессы и в целом сеять хаос.
Что ж, на macOS всё не так просто — например, процессы я запускать мог, но, похоже, они мало что могли сделать.
При попытке записать файлы я постоянно получал загадочную ошибку Operation not permitted — что происходит?
Я начал читать о macOS и Word и наткнулся на этот отличный пост от Адама Честера (работает в MDSec). Я очень рекомендую прочитать его, но здесь я кратко изложу выводы:
В macOS раньше была рабочая утилита sandbox-exec, которая выполняла команды в песочнице. Хотя она устарела, она могла многое прояснить. На её странице руководства видно, что она принимает profile, поэтому можно заключить, что правила песочницы хранятся в профилях. Эти профили могут быть разных видов и форм — файлы, предопределённые имена или даже строковые литералы.
На страницах руководства также сказано, что разработчикам следует использовать функцию App Sandbox. Читая дальше, я понял, что правила песочницы вшиты в бинарник; в нашем случае он находится по пути /Application/Microsoft Word.app/Contents/MacOS/Microsoft Word (если это кажется вам незнакомым, загляните в мой пост о структуре приложений macOS).
Хотя их можно легко извлечь вручную, лучше использовать инструмент codesign:
```jbo@McJbo ~ % codesign -dv --entitlements - /Applications/Microsoft\ Word.app/Contents/MacOS/Microsoft\ Word
Executable=/Applications/Microsoft Word.app/Contents/MacOS/Microsoft Word
Identifier=com.microsoft.Word
Format=app bundle with Mach-O universal (x86_64 arm64)
CodeDirectory v=20500 size=351454 flags=0x10000(runtime) hashes=10972+7 location=embedded
Signature size=8980
Timestamp=Apr 10, 2023 at 8:09:50 AM
Info.plist entries=52
TeamIdentifier=UBF8T346G9
Runtime Version=13.1.0
Sealed Resources version=2 rules=13 files=28766
Internal requirements count=1 size=180
[Dict]
[Key] com.apple.application-identifier
[Value]
[String] UBF8T346G9.com.microsoft.Word
[Key] com.apple.developer.aps-environment
[Value]
[String] production
[Key] com.apple.developer.team-identifier
[Value]
[String] UBF8T346G9
[Key] com.apple.security.app-sandbox
[Value]
[Bool] true
...
[Key] com.apple.security.temporary-exception.files.absolute-path.read-only
[Value]
[Array]
[String] /Library/Preferences/com.microsoft.office.licensingV2.plist
[String] /Library/Application Support/Microsoft/
...
[Key] com.apple.security.temporary-exception.sbpl
[Value]
[Array]
[String] (allow file-read* file-write* (require-all (vnode-type REGULAR-FILE) (regex #"(^|/)~\$[^/]+$")) )
[String] (deny file-write* (subpath (string-append (param "_HOME") "/Library/Application Scripts")) (subpath (string-append (param "_HOME") "/Library/LaunchAgents")) )
[Key] com.apple.security.temporary-exception.shared-preference.read-only
[Value]
[Array]
[String] com.ThomsonResearchSoft.EndNote
...
Тут нужно многое распаковать, поэтому давайте сделаем несколько заметок высокого уровня:
-dv, который означает display и verbose. Затем --entitlements показывает entitlements (права), связанные с приложением или бинарником (да, codesign может работать с обоими). Мы углубимся в entitlements в отдельном посте, а пока скажем, что они отражают возможности приложения, и одно из них указывает, что приложение находится в песочнице (com.apple.security.app-sandbox имеет логическое значение True).plist (опять же, в моём [посте о структуре приложений macOS]) возможно, подозревают, что словарь «ключ-значение» является представлением некоего property list, и они будут правы.com.apple.security.temporary-exception.files.absolute-path.read-only содержит массив абсолютных путей, из которых приложению разрешено читать.com.apple.security.temporary-exception.sbpl — оно нужно для создания тех печально известных временных файлов , которые так любит Word.В посте MDSec от 2018 года, который я упоминал ранее, части deny file-write* в com.apple.security.temporary-exception.sbpl не существовало, что позволяло макросам создавать файлы с произвольным содержимым, например /Library/LaunchAgents/~$evil.plist. Почему это приводит к побегу из песочницы?
LaunchAgents и LaunchDaemons — хорошо известный (легитимный) механизм персистентности в macOS. Я упоминал их раньше, но вы можете думать о них как о службах (если вы пришли из мира Windows): LaunchDaemons запускаются при загрузке ОС (и поэтому работают вне пользовательской сессии), а LaunchAgents запускаются при входе пользователя в систему.
Интересно, что оба описываются в простых plist-файлах. Вот пример для моего обновлятора OneDrive:
jbo@McJbo ~ % plutil -p /Library/LaunchAgents/com.microsoft.OneDriveStandaloneUpdater.plist
{
"Label" => "com.microsoft.OneDriveStandaloneUpdater"
"Program" => "/Applications/OneDrive.app/Contents/StandaloneUpdater.app/Contents/MacOS/OneDriveStandaloneUpdater"
"ProgramArguments" => [
]
"RunAtLoad" => 1
"StartInterval" => 86400
}
Эти LaunchAgents и LaunchDaemons запускаются launchd (помните этот процесс?), и поэтому это приводит к побегу из песочницы, поскольку launchd не знал, был ли plist записан из процесса, находящегося в песочнице, или нет (а даже если бы знал — как бы он понял, какие правила песочницы применять?).
Эта концепция использования launchd для побега из песочницы macOS широко применялась, и, по сути, я сам использовал её в прошлом.
Экономя вам пару кликов — вот идея:
launchd запускает приложения macOS. Эти приложения могут запускаться двойным щелчком или другими способами — например, при щелчке по zip-файлу будет использоваться Archive Utility, поскольку он ассоциирован с zip-файлами.launchd — команда open.open очень богатая — можно использовать некоторые её интересные возможности, например выбрать приложение, выбрать имя файла для открытия или даже передать полные аргументы командной строки.Python (которого больше нет на новых чистых устройствах macOS), чтобы запустить Python с аргументом stdin, который по сути перенаправляет стандартный ввод из файла, который я сохранил (этот файл был ~$evil.py из-за ограничений Word).launchd запустил экземпляр приложения Python вне песочницы, который начал читать , содержащий произвольные Python-команды, что по сути обеспечило побег из песочницы.Похожие идеи были и в других публикациях (один хороший пример — здесь), но идея остаётся той же. Я почти уверен, что их гораздо больше, и они прямо на виду!
Особого упоминания заслуживает отличный пост от Войцеха Регулы — на этот раз основное внимание уделяется приложению Terminal и манипулированию переменными окружения. Обязательно прочитайте!
Проблема, найденная MDSec, была специфична для Office — и была исправлена более строгими правилами.
Атаки, злоупотребляющие LaunchServices (так называется фреймворк для запуска приложений через launchd), носят более общий характер — и поэтому Apple пришлось их исправлять.
Одна из вещей, которые я заметил, — файлы, сохраняемые Word, теперь создаются с расширенным атрибутом com.apple.quarantine, да, тем самым, о котором я упоминал в своём посте введение в Gatekeeper.
Как оказалось, этот атрибут quarantine — своего рода усиление защиты от определённых атак. Например, приложение Terminal отказывалось запускать shell-скрипты, созданные с этим атрибутом. Кстати, именно поэтому мне пришлось использовать опцию --stdin для Python.
Как указал Гергей Кальман, Apple добавила дополнительные проверки в бинарник open, чтобы усилить защиту от подобных эксплойтов. Похоже, что --stdin, --args и другие флаги командной строки игнорируются, если вызывающий процесс находится в песочнице. Однако open просто обращается к LaunchServices (в launchd) через IPC, и для этого удобно существуют API, например LSOpenURLsWithRole.
Я не проверял, усилен ли сам LaunchServices тоже; если нет, то, полагаю, аналогичные побеги из песочницы можно легко осуществить.
Мы кратко обсудили ещё одну технологию macOS — песочницу. Мы увидели, насколько она мощная и настраиваемая, и как её можно обойти.
Мы также связали некоторые вещи воедино: как приложения работают с правилами песочницы, как запуск приложений через launchd нарушает не только деревья процессов, и как plist-файлы можно использовать во благо или во зло — в этот раз для персистентности (LaunchAgents и LaunchDaemons).
К счастью, мы даже связали расширенный атрибут com.apple.quarantine из поста введение в Gatekeeper и объяснили, как он может использоваться в качестве дополнительной защиты от побегов из песочницы. Неплохо!
В следующих нескольких постах мы рассмотрим другие механизмы безопасности в macOS и, возможно, поговорим о стратегиях их обхода.
Оставайтесь на связи!
Jonathan Bar Or (https://jonathanbaror.com)
~$whatever.docx~$evil.py