EnglishРусский Map

Незаметная подмена исполняемых файлов доверенных приложений в macOS

title
Незаметная подмена исполняемых файлов доверенных приложений в macOS
type
summary
summary
Mysk: архивация и распаковка позволяют коду пользователя подменить бинарник скачанного приложения; Apple отказалась это чинить
tags
macos, security, code-signing, gatekeeper
created
2026-07-29
updated
2026-07-29
lang
ru
source_updated
2026-07-29
translated
2026-09-01
translator
lllm/antigravity/gemini-3.7-flash-medium

Талал Хадж Бакри и Томми Мыск обнаружили, что любой код, запущенный от имени текущего пользователя, может заменить основной исполняемый файл приложения, скачанного из веба. После этого подменённое приложение перезапускается без каких-либо предупреждений и может выдавать себя за оригинал в системных запросах разрешений. Apple воспроизвела отчёт и закрыла его со статусом, не требующим исправления безопасности. Эта последняя деталь попала в статью не случайно - именно ради неё статья и написана.

Подтверждено на macOS Tahoe от 26.0.0 до 26.5.2 и Golden Gate 27 бета с 1 по 4. Более ранние версии, скорее всего, также уязвимы, но не тестировались.

Защита, которая должна работать

macOS поставляет приложения в виде bundle'ов - каталогов, которые Finder отображает как единый .app. При первом запуске скачанного приложения macOS проверяет подпись кода, нотаризацию и применяет политики Gatekeeper. Как только приложение установлено и открыто, содержимое bundle'а становится доступным только для чтения для всех остальных процессов, а при попытке записи macOS выдаёт предупреждение. Сквозь эту защиту не может пройти даже root:

% sudo touch /Applications/Signal.app/Contents/MacOS/Signal
touch: /Applications/Signal.app/Contents/MacOS/Signal: Operation not permitted

Три команды, которые её отменяют

% cd /Applications/
% tar cf .Signal.tar Signal.app
% rm -rf Signal.app
% tar xf .Signal.tar -C /Applications

Восстановленный bundle запускается как обычно. При этом он становится доступен для записи:

% touch /Applications/Signal.app/Contents/MacOS/Signal
%

После этого для подмены исполняемого файла достаточно обычной cp. В своей демонстрации авторы компилируют программу на Swift, которая открывает окно с заголовком "Hi! I'm Signal!", копируют её поверх Signal.app/Contents/MacOS/Signal и выполняют open /Applications/Signal.app. Никаких предупреждений Gatekeeper, никаких признаков изменения bundle'а.

Здесь есть три предварительных условия. Приложение должно быть скачано из веба, а не из Mac App Store, поскольку приложения из App Store принадлежат root'у, тогда как скачанные из веба обычно принадлежат текущему пользователю. Приложение должно быть запущено хотя бы один раз, чтобы начальная проверка Gatekeeper осталась позади. И атакующий уже должен иметь возможность выполнять код от имени этого пользователя - никакого повышения привилегий здесь нет, что относит этот вектор строго к последствиям компрометаций, описанных в supply-chain-security, где вредоносная зависимость или скрипт установки получают ровно такие права и не более того.

Signal выбран в качестве демонстрационной цели, поскольку пользуется широким доверием и распространяется вне App Store; авторы прямо подчёркивают, что это не баг самого Signal. Такое же поведение затрагивает Brave Browser, Cursor, Mullvad Browser, Proton Mail, Slack, Visual Studio Code, Xcode и другие приложения.

Почему это работает

Ресурсы bundle'а запечатаны хэшами, записанными в _CodeSignature/CodeResources. Основной исполняемый файл к этим ресурсам не относится; он несёт собственную встроенную подпись. Архивация и восстановление оставляют все ресурсы побайтово идентичными, поэтому цифровая печать по-прежнему проходит проверку. Новый исполняемый файл подписан ad-hoc подписью, а macOS разрешает запуск исполняемых файлов с ad-hoc подписью. В итоге bundle успешно проходит все выполняемые проверки, содержа внутри бинарник, за который не ручается ни один сертификат разработчика.

Требование о первом запуске вытекает из той же структуры. Если заменить исполняемый файл до первого запуска, первичная проверка завершится ошибкой: macOS сообщит, что приложение повреждено, и предложит отправить его в корзину. Если же заменить его после, bundle продолжит запускаться под идентификатором исходного приложения.

Что получает атакующий

Меньше, чем полную компрометацию, и авторы говорят об этом прямо: это не обход TCC, не обход защиты Keychain и не обход подписи кода. Подменённый бинарник с ad-hoc подписью не наследует никаких entitlement'ов исходного приложения и никаких ранее выданных ему разрешений, поэтому каждое обращение к защищённому ресурсу всё так же вызывает настоящий системный запрос на авторизацию.

Эти запросы и есть атака. Поскольку исполняемый файл находится внутри Signal.app, macOS снабжает запросы именем и иконкой Signal, и они визуально неотличимы от тех, что сгенерировало бы настоящее приложение. Proof of concept запрашивает запись Keychain самого Signal, где хранится ключ шифрования, затем защищённые TCC папки ~/Desktop и ~/Documents, после чего завершает работу и перезапускает подлинный исполняемый файл Signal, чтобы пользователь не заметил ничего подозрительного. Пользователь, доверяющий Signal, подтверждает запрос, в котором написано Signal.

Оценка Apple

Аргументация Apple, переданная в статье:

  • Proof of concept заменяет весь application bundle целиком, а не модифицирует существующий подписанный исполняемый файл.
  • Атака требует выполнения кода от имени текущего пользователя и затрагивает только приложения, принадлежащие этому пользователю.
  • Замена не наследует entitlement'ы или ранее выданные разрешения TCC, поэтому пользователь должен подтвердить новые запросы.
  • Убедить пользователя одобрить эти запросы - это социальная инженерия, а не обход TCC.
  • Gatekeeper предназначен для проверки скачанных приложений перед первым запуском и не рассчитан на защиту файлов, которые уже принадлежат текущему пользователю и были им изменены.

Ни Gatekeeper, ни TCC обойдены не были, следовательно, исправление безопасности не требуется. Каждый из этих пунктов по отдельности верен, и вместе они определяют модель угроз так, что наблюдаемое поведение оказывается за её рамками.

Встречные предложения Mysk направлены на две точки, где архитектура расходится с ментальной моделью пользователя. Повторно проверять подпись кода приложения перед запуском, если его bundle изменился, - короткая проверка, которую macOS отображает после модификации, указывает на то, что изменение уже детектируется. И показывать в запросах авторизации идентификатор подписи кода запрашивающего бинарника (разработчика или Team ID), а не только имя и иконку приложения. Второе предложение устранило бы возможность выдавать себя за другое приложение вообще без изменения зоны ответственности Gatekeeper.

Хронология

Сообщено 4 июня 2026 года. 9 июня Apple запросила дополнительную информацию; 11 июня был отправлен исходный код proof-of-concept. 13 июля Mysk запросил статус, упомянув планируемое раскрытие для Proton, Signal, Brave и Mullvad. 14 июля Apple ответила: "We've taken an initial pass at reproducing this report" и в тот же день закрыла отчёт.

Паттерн знаком по macos-tcp-time-bomb, где сторонние исследователи описали дефект macOS подробнее, чем было признано в официальном ответе вендора. Разница в том, что переполнение tcp_now через 49 дней - это однозначный баг, тогда как здесь спор идёт о том, где проходит граница безопасности: позиция Apple состоит в том, что атакующий, уже работающий от вашего имени, находится за её пределами, а позиция Mysk - в том, что запрос с иконкой Signal находится внутри неё.