Пользователи айфонов прекрасно знают, зачем нужен джейлбрейк. Доступ к файловой системе в iOS позволяет устанавливать приложения из сторонних репозиториев и гибко менять настройки, которые обычно недоступны. До недавнего времени джейла для iOS 13 не существовало. Точнее, до тех пор, пока хакер axi0mX не обнаружил уязвимость checkm8 и не объяснил, как можно заюзать ее на благо прогрессивной общественности. А сегодня мы расскажем об этой находке тебе и покажем, как с ней обращаться.
Название уязвимости checkm8 произносится по-английски примерно как checkm-eight, что созвучно со словом checkmate — «шах и мат», символизирующим окончание шахматной партии. Отсюда и характерный логотип одноименного эксплоита в виде опрокинутой фигуры шахматного короля. «Игра окончена, ребята из Купертино, — как бы намекают нам авторы сплоита, — you lose».
Самое интересное во всей этой истории с checkm8 то, что уязвимость была обнаружена не на программном, а на аппаратном уровне яблочной техники, причем охватывает она очень большой диапазон моделей, начиная с самых древних устройств на чипе А5 вроде iPhone 4S и заканчивая вполне современным iPhone X.
Дыра прячется в механизме BootROM, который играет ключевую роль в процессе загрузки айфонов и айпадов. Причем пофиксить ее программными заплатками невозможно: для того чтобы решить проблему, нужно пересмотреть аппаратную конфигурацию самого девайса, чего, как ты понимаешь, за пару месяцев никак не сделать. На мой взгляд, checkm8 — это крупнейший факап Apple со времен трояна Flashback, заразившего и объединившего в ботнет почти 500 тысяч маков под управлением OS X по всему миру. Но тогда, в 2012 году, все успешно разрешилось обновлением Java-машины в macOS, уязвимость в которой и использовал трой. Сейчас у Apple уже не получится соскочить столь же легко и элегантно.
О checkm8 известно уже давненько. Первые упоминания об уязвимости в BootROM яблочных мобильных устройств появились в Сети 27 сентября 2019 года, когда axi0mX публично сообщил в твиттере о своей находке. Горячую новость тут же подхватили многочисленные сайты и даже авторитетные СМИ, громко заявившие о появлении универсального джейлбрейка для целого зоопарка смартфонов от Apple. На самом деле полноценного джейла на тот момент еще не существовало: экспериментируя с DFU, axi0mX обнаружил аппаратную уязвимость, которую потенциально можно использовать для взлома файловой системы iOS.
Сперва с помощью checkm8 нельзя было сделать практически ничего, кроме замены стандартной загрузочной картинки iPhone в виде надкусанного яблока на что-то более оригинальное. Полноценный джейлбрейк с возможностью установки Cydia был представлен только 8 ноября на конференции POC2019 в Сеуле, да и тот пока еще находится в состоянии бета-тестирования.
В разработке джейла на основе checkm8 принимала участие целая команда исследователей, объединенная под общим названием checkra1n. В нее, помимо самого axi0mX и известного iOS-исследователя и талантливого хакера Луки Тодеско (qwertyoruiop), входит еще как минимум десяток человек, о чем красноречиво свидетельствует раздел Credits на сайте этой банды.
На сегодняшний день бета-версия разработанного командой checkra1n джейлбрейка позволяет взломать устройства с установленной iOS 13, начиная с iPhone 6S и заканчивая Х — на более ранних девайсах утилита не тестировалась. Как происходит этот взлом и на каких принципах он основан? Давай разбираться.
Для пользователя загрузка айфона выглядит крайне просто: нажал на кнопочку — и спустя пару секунд на экране появляется привычный интерфейс iOS. С технической точки зрения все немного сложнее.
За начальный этап запуска яблочного устройства отвечает так называемый SecureROM, он же Boot ROM. Это — самый первый код, который запускается при холодной загрузке в Application Processor. Фактически он представляет собой урезанную и упрощенную версию загрузчика iBoot. Основная задача SecureROM — получить образ загрузчика из энергонезависимой памяти и передать ему управление. Этот код хранится непосредственно в чипе на аппаратном уровне, доступен только на чтение и потому не может быть изменен никаким образом извне. SecureROM — это самый доверенный код в Application Processor, который выполняется без каких-либо проверок. Он же отвечает за переход устройства в сервисный режим восстановления DFU (Device Firmware Update), активизируемый нажатием специальной комбинации кнопок при включении девайса. Для нас важно, что в режиме DFU доступна загрузка на устройство файлов через интерфейс USB.
Архитектурно SecureROM представляет собой первое звено цепочки безопасной загрузки, придуманной Apple для защиты от самого главного врага яблочных мобильных устройств — вредоносных программ и джейлбрейков. В SecureROM вшит криптографический ключ Apple, используемый для расшифровки образов, которые задействованы на последующих этапах загрузки, а также имеется необходимый инструментарий для работы с криптоалгоритмами. Получив управление от SecureROM, загрузчик iBoot расшифровывает и запускает ядро операционной системы, после чего загружается образ самой iOS с графическим интерфейсом пользователя. Однако все эти этапы запуска iPhone или iPad выполняются, только если инициализация SecureROM прошла успешно.
Именно поэтому все существовавшие до открытия checkm8 джейлбрейки старались всячески обойти этот механизм. Ведь их первоочередная задача — загрузить пропатченный образ iOS, допускающий установку программ из сторонних источников, чего не должно происходить с использованием SecureROM, стоящего на страже безопасной загрузки. Именно полный контроль над процессом запуска операционной системы гарантирует невозможность проникновения на устройство всевозможных буткитов, руткитов и прочей подобной малвари, отсутствием которой всегда и славилась мобильная платформа от Apple.
Как уже упоминалось, режим восстановления яблочного девайса DFU используется, если невозможна штатная загрузка айфона или айпада, и допускает обмен данными между компьютером и устройством через интерфейс USB. Для организации этого обмена в Купертино придумали специальный протокол DFU. С его помощью можно залить на окирпиченный айфон новую прошивку, восстановить телефон из резервной копии или обновить операционную систему.
Протокол DFU загружает с компьютера на яблочный девайс блоки данных с образом прошивки по запросу 0x21, 1
. Когда загрузка полностью завершается, запрашивается состояние устройства, после чего соединение по USB разрывается, устройство выходит из режима DFU, перезапускается и пытается загрузить полученный образ прошивки. Это если процесс протекает в штатном режиме. Однако исследователи заметили, что выйти из DFU можно и другими способами, например по запросу 0x21, 4
(DFU abort). В этом случае выполняется форсированное завершение режима восстановления устройства.
При передаче данных протокол DFU использует режим, который носит наименование USB Control Transfer. Соединение инициализируется с использованием установочного пакета (Setup Stage) длиной 8 байт, структура которого показана на следующей картинке.
Назначение всех полей этого пакета нам сейчас не принципиально — кроме самого последнего. Если значение wLength ненулевое, сразу за установочным пакетом следует стадия данных (Data Stage), то есть данные пойдут с компьютера на устройство или обратно (направление определяется значением bmRequest Type
). Эти данные передаются последовательно фрагментами размером от 8 до 64 байт в зависимости от скорости USB-соединения. Сессия передачи данных завершается стадией проверки статуса транзакции (Status Stage), на которой стороны обмениваются пакетами нулевой длины.
В USB-стеке iBoot временный буфер выделяется в момент инициализации USB и пакеты, передаваемые в фазе данных, загружаются в него непосредственно «на входе». Важный момент состоит в том, что USB-стек включается сразу, как только устройство переходит в режим DFU. Выделенный буфер используется для временного хранения информации на стадии данных. После передачи управления указатель на этот буфер (и размер ожидаемых данных) копируется в глобальную переменную, которую USB-стек использует как место назначения для пакетов, поступающих на устройство в фазе данных. Как только устройство выходит из режима DFU, USB-стек снова выключается. Однако глобальная переменная при этом не обнуляется! Таким образом исследователи нащупали классическую уязвимость типа Use-after-Free (UaF).
Уязвимость типа Use-after-Free обусловлена методами взаимодействия с динамической памятью, или кучей (heap). Подробнее об этом типе уязвимостей можно прочитать, например, здесь.
В этом и кроется баг, лежащий в основе checkm8. Если отправить на устройство запрос Setup Stage, инициировать передачу данных, но, не начав эту самую передачу, отправить девайсу запрос DFU abort (0x21, 4
) на форсированный выход из DFU, то устройство попытается снова запуститься в режиме DFU и завершить прерванную сессию. При этом состояние памяти останется инициализированным и мы получаем возможность передать на устройство, загрузить в память и выполнить произвольный код по адресу буфера, выделенного до момента предыдущего выхода устройства из DFU.
Поскольку вся программа, обеспечивающая выделение буфера, работу с кучей и структурами задач, хранится в SecureROM и исполняется на аппаратном уровне, пофиксить эту ошибку попросту невозможно. Шах и мат!
Примечательно, что на девайсах с 32-разрядным ROM (A7, A10, A10X, A11 и A11X) указанный механизм не работает, поскольку буфер там аллоцируется всякий раз в одном и том же месте при каждой инициализации USB-стека. Тем не менее axi0mX нашел способ обойти такую предопределенность с использованием правильно подобранного сценария эксплуатации Use-after-Free.
Для этого он использовал то обстоятельство, что система одновременно может инициализировать несколько USB-передач. Например, в ответ на некоторые запросы устройство не сможет отправить данные, если получатель занят, до тех пор, пока конечная точка (endpoint) не освободится или не будет сброшен USB, то есть не будут устранены условия блокировки. Отправленные в таком состоянии запросы попадают в очередь. После устранения блокировки выполняется обход очереди и все запросы поочередно завершаются. Информация о конечной точке (endpoint) обнуляется, а запросы нулевой длины остаются в куче. Управляя запросами и тайм-аутами, теоретически можно создать такие условия формирования кучи, которые в итоге повлияют на следующее выделение памяти при создании буфера.
Обобщая, можно сказать, что из-за найденной в SecureROM ошибки в механизме создания и уничтожения USB-стека происходит утечка памяти, которая может использоваться для формирования состояния кучи, дающего возможность управлять выделением памяти при размещении буфера. В результате с помощью UaF можно выполнить запись в выделенную память для получения контролируемого косвенного перехода (controlled indirect branch) при выходе из DFU.
По принципу своего действия использующий эту уязвимость эксплоит checkm8 — типичный буткит. Основная его задача состоит в том, чтобы дать устройству нормально загрузиться, но при этом скомпрометировать каждое звено в цепочке загрузки после того, как отработает BootROM.
Материалы из последних выпусков становятся доступны по отдельности только через два месяца после публикации. Чтобы продолжить чтение, необходимо стать участником сообщества «Xakep.ru».
Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», увеличит личную накопительную скидку и позволит накапливать профессиональный рейтинг Xakep Score! Подробнее
1 год7690 р. |
1 месяц720 р. |
Я уже участник «Xakep.ru»
Читайте также
Последние новости