Например, если SIM-карта формирует на экране устройства сообщение с подтверждением действий пользователя, оно будет содержать кнопку OK. Такие сообщения используются для подтверждения отправки USSD-запросов, транзакций, действий с хранящимися на карте контактами и так далее. Вредоносное приложение может вызвать действие android.intent.action.stk.command и отобразит на экране поверх настоящего поддельное окно, содержащее произвольный текст. При нажатии кнопки OK вызывается метод sendResponse() с флагом true, и это событие нажатие кнопки передается SIM-карте, ожидающей реакции пользователя. При этом событие будет обработано так, как если бы оно поступило от настоящего диалогового окна. Это открывает широчайшие возможности для создателей вредоносных программ.
Описанная выше ошибка в SDK Android далеко не единственная. Так, уязвимость Cloak and Dagger актуальна для Android вплоть до 7.1.2. Из-за ошибки в SDK вредоносное приложение, используя разрешения SYSTEM_ALERT_WINDOW и BIND_ACCESSIBILITY_SERVICE, может получить практически полный контроль над операционной системой и доступ к конфиденциальной информации пользователя, а также фиксировать нажатия клавиш. Вкратце суть сводится к тому, что разрешение SYSTEM_ALERT_WINDOW позволяет вывести на экран «системное окно» View-элемент, который отобразится поверх любого другого элемента интерфейса, даже если это будет Activity из стороннего приложения. При этом перекрытые Activity об этом не узнают и продолжат работать так, как будто ничего и не произошло. Это может сделать любое приложение, если разрешение SYSTEM_ALERT_WINDOW заявлено в его манифесте. Разместив несколько «невидимых» системных окон друг над другом и обрабатывая нажатия на них, злоумышленник может создать кейлоггер. А с помощью разрешения BIND_ACCESSIBILITY_SERVICE вредоносная программа способна получить доступ к другим объектам ОС и хранящимся на устройстве данным.
Описанная выше ошибка в SDK Android далеко не единственная. Так, уязвимость Cloak and Dagger актуальна для Android вплоть до 7.1.2. Из-за ошибки в SDK вредоносное приложение, используя разрешения SYSTEM_ALERT_WINDOW и BIND_ACCESSIBILITY_SERVICE, может получить практически полный контроль над операционной системой и доступ к конфиденциальной информации пользователя, а также фиксировать нажатия клавиш. Вкратце суть сводится к тому, что разрешение SYSTEM_ALERT_WINDOW позволяет вывести на экран «системное окно» View-элемент, который отобразится поверх любого другого элемента интерфейса, даже если это будет Activity из стороннего приложения. При этом перекрытые Activity об этом не узнают и продолжат работать так, как будто ничего и не произошло. Это может сделать любое приложение, если разрешение SYSTEM_ALERT_WINDOW заявлено в его манифесте. Разместив несколько «невидимых» системных окон друг над другом и обрабатывая нажатия на них, злоумышленник может создать кейлоггер. А с помощью разрешения BIND_ACCESSIBILITY_SERVICE вредоносная программа способна получить доступ к другим объектам ОС и хранящимся на устройстве данным.
Уязвимости встречаются и в программной прошивке аппаратных устройств. Благодаря одной такой ошибке существует возможность взломать практически любое мобильное устройство производство компании Apple начиная с iPhone 5 и заканчивая самыми современными версиями iPhone и iPad. Речь идет об известной уязвимости checkm8 (checkmate), самой «свежей» на сегодняшний день уязвимости в мобильной технике Apple, наделавшей много шума в конце 2019 начале 2020 года. Рассмотрим ее подробнее, чтобы понять, как работают и используются на практике подобные уязвимости.
Название «checkm8» произносится по-английски примерно как checkm-eight, что созвучно со словом checkmate «шах и мат», символизирующим окончание шахматной партии. Отсюда и характерный логотип одноименного эксплоита в виде опрокинутой фигуры шахматного короля. «Игра окончена, ребята из Купертино, как бы намекают нам авторы сплоита, you lose». Самое интересное во всей этой истории с checkm8 то, что уязвимость была обнаружена не на программном, а на аппаратном уровне яблочной техники, причем охватывает она очень большой диапазон моделей, начиная с самых древних устройств на чипе А5 вроде iPhone 4S и заканчивая вполне современным iPhone X. «Дыра» прячется в механизме BootROM, который играет ключевую роль в процессе загрузки айфонов и айпадов. Причем исправить ее программными заплатками невозможно: для того чтобы решить проблему, нужно пересмотреть аппаратную конфигурацию самого устройства, чего, как вы понимаете, за пару месяцев никак не сделать.
Для пользователя загрузка айфона выглядит крайне просто: нажал на кнопочку и спустя пару секунд на экране появляется привычный интерфейс iOS. С технической точки зрения все немного сложнее. За начальный этап запуска яблочного устройства отвечает так называемый SecureROM, он же BootROM. Это самый первый код, который запускается при холодной загрузке в Application Processor. Фактически он представляет собой урезанную и упрощенную версию загрузчика iBoot. Основная задача SecureROM получить образ загрузчика из энергонезависимой памяти и передать ему управление. Этот код хранится непосредственно в чипе на аппаратном уровне, доступен только на чтение и потому не может быть изменен никаким образом извне. SecureROM это самый доверенный код в Application Processor, который выполняется без каких-либо проверок. Он же отвечает за переход устройства в сервисный режим восстановления DFU (Device Firmware Update), активизируемый нажатием специальной комбинации кнопок при включении девайса. Для нас важно, что в режиме DFU доступна загрузка на устройство файлов через интерфейс USB.
Рис. 23.Так выглядят «этапы большого пути» загрузки устройства с iOS
Архитектурно SecureROM представляет собой первое звено цепочки безопасной загрузки, придуманной Apple для защиты от самого главного врага «яблочных» мобильных устройств вредоносных программ и джейлбрейков. В SecureROM вшит криптографический ключ Apple, используемый для расшифровки образов, которые задействованы на последующих этапах загрузки, а также имеется необходимый инструментарий для работы с криптоалгоритмами. Получив управление от SecureROM, загрузчик iBoot расшифровывает и запускает ядро операционной системы, после чего загружается образ самой iOS с графическим интерфейсом пользователя. Однако все эти этапы запуска iPhone или iPad выполняются, только если инициализация SecureROM прошла успешно.
Именно поэтому все существовавшие до открытия checkm8 джейлбрейки старались всячески обойти этот механизм. Ведь их первоочередная задача загрузить видоизмененный образ iOS, допускающий установку программ из сторонних источников, чего не должно происходить с использованием SecureROM, стоящего на страже безопасной загрузки. Именно полный контроль над процессом запуска операционной системы гарантирует невозможность проникновения на устройство всевозможных буткитов, руткитов и прочей подобной малвари, отсутствием которой всегда и славилась мобильная платформа от Apple.
Как уже упоминалось, режим восстановления яблочного девайса DFU используется, если невозможна штатная загрузка айфона или айпада, и допускает обмен данными между компьютером и устройством через интерфейс USB. Для организации этого обмена в Apple придумали специальный протокол DFU. С его помощью можно залить на «окирпиченный» айфон новую прошивку, восстановить телефон из резервной копии или обновить операционную систему. Протокол DFU загружает с компьютера на яблочный девайс блоки данных с образом прошивки по запросу 0×21, 1. Когда загрузка полностью завершается, запрашивается состояние устройства, после чего соединение по USB разрывается, устройство выходит из режима DFU, перезапускается и пытается загрузить полученный образ прошивки. Это если процесс протекает в штатном режиме. Однако исследователи заметили, что выйти из DFU можно и другими способами, например по запросу 0×21, 4 (DFU abort). В этом случае выполняется форсированное завершение режима восстановления устройства.
При передаче данных протокол DFU использует режим, который носит наименование USB Control Transfer. Соединение инициализируется с использованием установочного пакета (Setup Stage) длиной 8 байт, структура которого показана на иллюстрации 24.
Рис. 24.Структура установочного пакета USB Control Transfer
Назначение всех полей этого пакета нам сейчас не принципиально кроме самого последнего. Если значение wLength ненулевое, сразу за установочным пакетом следует стадия данных (Data Stage), то есть данные пойдут с компьютера на устройство или обратно (направление определяется значением bmRequest Type). Эти данные передаются последовательно фрагментами размером от 8 до 64 байт в зависимости от скорости USB-соединения. Сессия передачи данных завершается стадией проверки статуса транзакции (Status Stage), на которой стороны обмениваются пакетами нулевой длины.
В USB-стеке iBoot временный буфер выделяется в момент инициализации USB и пакеты, передаваемые в фазе данных, загружаются в него непосредственно «на входе». Важный момент состоит в том, что USB-стек включается сразу, как только устройство переходит в режим DFU Выделенный буфер используется для временного хранения информации на стадии данных. После передачи управления указатель на этот буфер (и размер ожидаемых данных) копируется в глобальную переменную, которую USB-стек использует как место назначения для пакетов, поступающих на устройство в фазе данных. Как только устройство выходит из режима DFU, USB-стек снова выключается. Однако глобальная переменная при этом не обнуляется! Таким образом исследователи нащупали классическую уязвимость типа Use-afer-Free (UaF).
В этом и кроется ошибка, лежащая в основе checkm8. Если отправить на устройство запрос Setup Stage, инициировать передачу данных, но, не начав эту самую передачу, отправить девайсу запрос DFU abort (0×21, 4) на форсированный выход из DFU, то устройство попытается снова запуститься в режиме DFU и завершить прерванную сессию. При этом состояние памяти останется инициализированным и мы получаем возможность передать на устройство, загрузить в память и выполнить произвольный код по адресу буфера, выделенного до момента предыдущего выхода устройства из DFU Поскольку вся программа, обеспечивающая выделение буфера, работу с кучей (heap) и структурами задач, хранится в SecureROM и исполняется на аппаратном уровне, исправить эту ошибку попросту невозможно. Шах и мат!
Примечательно, что на девайсах с 32-разрядным ROM (A7, A10, A10X, A11 и A11X) указанный механизм не работает, поскольку буфер там аллоцируется всякий раз в одном и том же месте при каждой инициализации USB-стека. Тем не менее, обнаруживший данную уязвимость хакер axi0mX нашел способ обойти такую предопределенность с использованием правильно подобранного сценария эксплуатации Use-afer-Free. Для этого он использовал то обстоятельство, что система одновременно может инициализировать несколько USB-передач. Например, в ответ на некоторые запросы устройство не сможет отправить данные, если получатель занят, до тех пор, пока конечная точка (endpoint) не освободится или не будет сброшен USB, то есть не будут устранены условия блокировки. Отправленные в таком состоянии запросы попадают в очередь. После устранения блокировки выполняется обход очереди и все запросы поочередно завершаются. Информация о конечной точке (endpoint) обнуляется, а запросы нулевой длины остаются в куче. Управляя запросами и тайм-аутами, теоретически можно создать такие условия формирования кучи, которые в итоге повлияют на следующее выделение памяти при создании буфера.