Обход режима MODE_IGNORED в app-op

Подробное объяснение уязвимости CVE-2022-20551, исправленной в Android в феврале 2023 года.

Об AppOpsManager

Отслеживаем (логирование) и контроль доступа (разрешение, запрет) к критичным API системы происходит через механизм app-opов. App-opы (давайте просто app-ops во множественном числе и app-op в единственном) покрывают большой набор функциональности — от рантайм пермишенов до монитора состояния батарейки. Управление же всеми этими фичами, внутри, происходит через AppOpsManager

Что именно можно отслеживать и как этим управлять — это вы можете увидеть по ссылке выше. Здесь же нас интересуют именно режимы контроля.

Контроль доступа

Всего таких режимов четыре:

Разрешение и запрет с ошибкой выглядят прям очень знакомым, не так ли? Эти режимы доступны пользователю в интерфейсе Android, они позволяют понимать приложению, одобрил пользователь какой-то пермишен или отказал. Но это для пользователя. Для производителей и прошивок, и MDM решений, есть вот этот классный режим игнорирования. Если вы сами производитель какого-то MDM решения, то это разрешение ну очень полезно для вас.

В режиме игнорирования условный диктофон просто не узнает, что у него нет доступа к микрофону — ведь исключения SecurityException не вылетает. И будет считать, что запись идёт. То есть вам, как производителю MDM или защищённой прошивки, выгодно переводить app-ops приложений именно в игнор. Потому что очень наглые приложения начнут настаивать предоставить им доступ.

Кстати, пользователь тоже может управлять app-ops и у него есть полтора способа. Сначала я написал “обычный пользователь”, потому убрал это прилагательное, всё же пользователь должен быть подготовлен на столько, что способен использовать adb. Об этих способах расскажу ниже, когда опишу уязвимость.

Уязвимость CVE-2022-20551

История обнаружения

Мой коллега и руководитель обнаружил, что WhatsApp в режиме MODE_IGNORED продолжает записывать голосовые сообщения. Хоть они и выглядели как запись без звука (что было бы правильным поведением) — просто прямая линия, — но звук на самом деле записывался и голосовое можно было прослушать. Но полбеды в том, что запись выглядела как запись без звука. Индикатор Android о доступе к микрофону не включался и в истории доступа к микрофону WhatsApp не появлялся. Будто он микрофон никогда и не использовал. На меня упала задача посмотреть, что вообще не так.

Проверка на других мессенджерах, в т.ч. Telegram, показала, что такое поведение происходит только у WhatsApp. Проверял и на приложениях-диктофонах и они тоже работали правильно. Признаюсь, мы решили, что это не совпадение, что только WhatsApp себя так вёл. И наше предположение только усиливалось со временем. И, не знаю как другие члены команды, но я по-прежнему считаю, что эта уязвимость была для кого надо уязвимость.

Выяснив, что только WhatsApp ведёт себя так странно, решили передать информацию об уязвимости в Google. А до фикса — отказаться в своём решении от режима игнорирования, заменив на исключение. Лучше пусть приложения видят, что у них нет прав и требуют их предоставить, чем втихую получат доступ. Да, разумеется проверили, что при режиме исключения запись ломалась и у WhatsApp тоже.

Проталкивание проблемы

Aug 19, 2022 08:50PM — это точное время, когда я оформил баг 243152409 в багтрекере Google. Т.к. это проблема безопасности, то оформлял через специальную форму и полученный баг не публичный, попасть туда могу я и сотрудники Google. В этом баге было описано, как WhatsApp обходит режим игнорирования. Я приложил запись видео и сценарий воспроизведения. Ну и информацию о системе, разумеется — при оформлении проблем безопасности эти поля обязательны. Даже точную версию мессенджера указал, на случай, если WhatsApp резко изменят поведение. Это была последняя доступная версия на тот момент.

Казалось бы. Вот вам приложение, вот вам инструкция воспроизведения, как выставить режим игнорирования, вот вам даже видеозапись. Однако Aug 27, 2022 12:15AM получаю ответ: Status: Won't Fix (Infeasible). И объяснение, что мы не считаем это проблемой. Цитировать переписку не буду, ну мало ли. Можете поверить мне наслово. Но там была строка “The Resolution Notes label has been set to NSBC (Not Security Bulletin Class) to reflect this assessment”. Зафиксируем, что 27 августа 22 года воспроизведение на реальном ПО посчитали “working as intended”.

Сообщил нашей команде о том, что Google положил болт на проблему. Это подкинуло дровишек в топку “это дыра – для кого надо дыра, не лезьте”. Но дожать надо. Решили предоставить им PoC, который не имеет ничего лишнего, кроме эксплуатации уязвимости. Забегая вперёд скажу, что сценарий его использования такой же, как и WhatsApp. То есть мессенджера было совершенно точно достаточно.

Наш сотрудник Артём (фамилию не скажу, но лишний раз подчеркну наше всеобщее уважение к нему) разобрал WhatsApp и провёл исследование, как же мессенджеру удаётся обходить ограничение, тогда как все другие этого сделать не могут.

12 сентября Артём всё же докопался до истины. Оказалось, что при использовании OpenSLES режим игнорирования просто не работает. Далее Артём написал PoC, основанный прям на демке самого Google по работе с OpenSLES. Ну то есть Гугл буквально зажали в углу: демонстрация использования уязвимости была сделана на их собственном примере работы с технологией.

Sep 13, 2022 04:52PM я добавляю в ишую со статусом “вонт фикс” новое сообщение. Цитирую его целиком и прикрепляю PoC, чтобы вы могли проверить свои собственные прошивки. Если у вас установлены февральские (от февраля 23 года) обновления, то проблема не будет воспроизводится. Если же не установлены — словите описанное ниже поведение. И важно, проверять нужно на Android 12 и новее, потому что в версиях ниже не было визуального индикатора, который бы показывал, что сейчас идёт прослушивание через микрофон. То есть проблема есть и на 11 и ниже, просто пользователь в принципе не мог раньше понять, что что-то происходит.

Added PoC. It uses OpenSLES

  1. Install app
  2. Run app
  3. Tap on Record button
  4. Allow access while using the app
  5. Speak something during 5 seconds → We see the microphone access indicator
  6. Tap Play button → We hear ourself
  7. adb shell pm list packages -U | grep nativeaudio → package:com.example.nativeaudio uid:10060
  8. adb shell cmd appops set 10060 RECORD_AUDIO ignore
  9. Tap Record button
  10. Speak something during 5 seconds → We not see indicator
  11. Tap Play button

Expected: silent
Actual: we hear ourself

PoC можно скачать здесь.

Через час после этого Google отписал “спасибо за новую инфу, мы рассмотрим эти данные”.

Sep 23, 2022 01:04AM сотрудник Google написал новое сообщение, где признал проблему: “Based on our published severity assessment matrix (1) it was rated as Moderate severity”. Единичка – это ссылка на матрицу: “(1) Severity Matrix: https://source.android.com/security/overview/updates-resources#severity”.

Oct 8, 2022 06:50AM — гугловцы сообщают, что назначено такое-то вознаграждение.

Nov 10, 2022 08:48PM — гугловцы пишут, что мы всё ещё работаем над исправлением

Jan 6, 2023 09:31PM — новое обновление статуса. Уведомили, что деняк будет выплачено больше, потому что “After conducting additional review of the security issue in this report, we have revised the severity to High”. Я думаю, что у них из отпуска вернулся кто-то, у кого голова не только чтобы в неё есть. И он объяснил остальным, что вы чего вообще, это не какое-то приватное API. Это API мы даём специально для обеспечения безопасности и его используют в том числе Samsung.

Далее ещё несколько переписок по формальностям чистым. Типа, заполните вот эти документы, заполните вот эти. И, наконец, Feb 13, 2023 10:35PM происходит главное: Marked as fixed.

Эта ошибка для своих

Почему я считаю, что эта ошибка была кому надо ошибка. Вы вправе считать иначе и предлагать мне шапочку из фольги — дело ваше.

Возможно, конечно, я перегибаю палку. Вполне вероятно, что проверял человек, который увидел в WhatsApp прямую линию на записи и просто не прослушал запись, решив, что голосовое сообщение не записалась. А в PoC прямых линий не рисовали и они таки убедились, что всё работает. Но тогда получается, что Security Team в Google не тянули с исправлением, а просто забили болт на проверку.

Какой вариант выбираете: забили болт или тянули с фиксом, потому что уязвимость пока что нужна была?

App-opp у себя

Если вам нравится идея режима игнорирования, вам не обязательно (покупать?) и ставить MDM решение от стороннего производителя. У вас есть полтора пути. Полтора, потому что путь в итоге один, просто “второй” способ — это через GUI, но внутри тоже самое, что и “первый”.

Первый способ вы уже видели на PoC. Получаем UID приложения и выставляем ему режим через adb. Второй — использовать приложение, которому поднимете привилегии через тот же adb. Я сам проверял на Permission Manager X и что-то даже работало. Но я не ходил с ним. Просто проверил, что, прикольно, срабатывает и на этом всё.

Моя телега: https://t.me/mydaybug