Как работает джейлбрейк Evasi0n

4 февраля войдет в историю как день выхода джейлбрейка iOS 6 / 6.1. И теперь, когда первоначальная эйфория начинает сходить на нет, а пользователи один за другим «освобождают» свои девайсы, давайте рассмотрим, в чем состоит принцип работы этого самого Evasi0n. Предупреждаем, что данный материал из категории «много букв», изобилует большим количеством специальных терминов и элементов кода, поэтому он заинтересует лишь тех, кто в этом разбирается.

Как работает джейлбрейк Evasi0n

Evasi0n отличается тем, что полностью работает на уровне файловой системы устройства. Он не требует намеренной порчи памяти, чтобы получить административный доступ к устройству. Возможно, его назвали «evasi0n» («избег@ние»), поскольку он избегает всех защитных механизмов, встроенных в систему, вместо того, чтобы атаковать их прямо в лоб.

Evasi0n работает в три этапа, которые мы опишем ниже. Все этапы используют ту функциональность телефона, которая предоставляется MobileBackup’ом, сервисом, который используется для создания и восстановления резервных копий устройства. Поскольку резервные копии создаются с пользовательского устройства, и должны быть переносимы между разными устройствами, их не так просто криптографически подписать, так что по сути они не могут считаться достоверными данными.

MobileBackup использует общий идентификатор типа MediaDomain, который указывает на фиксированное место на устройстве, и относительный путь, чтобы идентифицировать каждый файл в резервной копии. Статический абсолютный путь (то есть от корня диска — прим. пер.) идентификатора, соединенный с относительным путем к файлу, дает абсолютный путь к восстанавливаемому на устройстве файлу. Evasi0n создает все свои файлы в MediaDomain, все файлы которого лежат в /var/mobile/Media.

Этап 1

Во время первого этапа evasi0n создает свежую резервную копию для восстановления на устройстве, содержащий только следующие файлы. Все файлы хранятся в MediaDomain.

каталог: Media/
каталог: Media/Recordings/
ссылка на каталог: Media/Recordings/.haxx -> /var/mobile
каталог: Media/Recordings/.haxx/DemoApp.app/
файл: Media/Recordings/.haxx/DemoApp.app/Info.plist
файл: Media/Recordings/.haxx/DemoApp.app/DemoApp
файл: Media/Recordings/.haxx/DemoApp.app/Icon.png
файл: Media/Recordings/.haxx/DemoApp.app/Icon@2x.png
файл: Media/Recordings/.haxx/DemoApp.app/Icon-72.png
файл: Media/Recordings/.haxx/DemoApp.app/Icon-72@2x.png
файл: Media/Recordings/.haxx/Library/Caches/com.apple.mobile.installation.plist

Символьная ссылка в каталоге .haxx to /var/mobile создана для того, чтобы обойти традиционные ограничения пути MobileBackup. Как правило, файлы MediaDomain должны располагаться в директории /var/mobile/Media. Тем не менее когда символьная ссылка создается, любой файл, который находится в .haxx, восстанавливается в in /var/mobile. Данная методика также использовалась в предыдущих джейлбрейках.

Делее в /var/mobile создается приложение iOS под названием DemoApp.app, дополненное иконками и другими атрибутами. Plist com.apple.mobile.installation.plist обновляется таким образом, что Springboard знает, где располагается это приложение, и может отображать его на главном экране.

Однако, в отличие от обычного приложения iOS, исполняемый код этого приложения весьма необычен и выглядит следующим образом:

#!/bin/launchctl submit -l remount -o /var/mobile/Media/mount.stdout -e /var/mobile/Media/mount.stderr -- /sbin/mount -v -t hfs -o rw /dev/disk0s1s1

Для тех, кто знаком со скриптами оболочек UNIX, ядро смотрит на первую строку текста, чтобы определить интерпретатор скрипта. Содержание файла выше сообщает ядру задание на выполнение launchctl с этими конкретными аргументами. Кроме того, Plist com.apple.mobile.installation.plist содержит специальный раздел для DemoApp.app, определяющий среду переменных окружения, которую нужно установить при запуске приложения:

EnvironmentVariables

LAUNCHD_SOCKET
/private/var/tmp/launchd/sock

В этот момент устройство перезагружается, чтобы приложение попадало в Springboard и отобразилось пользователю.

Этап 2.1

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

каталог: Media/
каталог: Media/Recordings/
символьная ссылка: Media/Recordings/.haxx -> /var/db
символьная ссылка: Media/Recordings/.haxx/timezone -> /var/tmp/launchd

Это позволяет создать символьную ссылку под названием /var/db/timezone, которая указывает на /var/tmp/launchd. Стандартные права доступа на /var/tmp/launchd следующие:

drwx------ 2 root wheel 102 Feb 4 12:17 launchd

Обычно эти права доступа не позволяют приложениям, работающим как пользователь mobile попадать в эту директорию. Далее evasi0n сообщает пользователю, что он «пинает» lockdownd. На самом деле это означает, что evasi0n отправляет неправильно сформированную команду PairRequest к lockdownd. Lockdownd — это основной сервис на устройстве, который работает с командами, полученными через USB, и используется для запуска/остановки других служб, таких как MobileBackup и AFC. Так как lockdownd работает с правами администратора, и пользователь может к нему обращаться, применение его не по назначению для выполнения нестандартных задач было весьма распространенным среди предыдущих джейлбрейков.

И вот мы подошли к использованию первой уязвимости. Отправление lockdownd неправильно сформированной команды PairRequest заставляет lockdownd выполнить команду chmod 777 /var/db/timezone, чтобы она была доступна для пользователя mobile (и всех пользователей). Нам не известно, находится ли эта уязвимость в lockdownd или в какой-то системной библиотеке.

Этап 2.2

В рамках этапа 2.2 мы продолжаем углубляться в /var/tmp/launchd. Это позволяет изменить права доступа к сокету (специальный файл, через который идёт коммуникация между программами в UN*X-подобных системах — прим. пер.) так, чтобы обычный пользователь без административных прав мог получить доступ к launchd. В рамках этапа 2.2 символьная ссылка меняет timezone следующим образом:

Символьная ссылка: Media/Recordings/.haxx/timezone -> /var/tmp/launchd

В

Символьная ссылка: Media/Recordings/.haxx/timezone -> /var/tmp/launchd/sock

После этого evasi0n отсылает еще один специально сформированный запрос PairRequest в lockdownd, приводя к тому, что и файл /var/tmp/launchd/sock станет доступным для пользователя mobile.

Этап 2.3

Этап 2.3 начинается с загрузки на телефон запакованного набора файлов, содержащего установщик Cydia. Сразу эти данные не используются, но сохраняются на будущее, чтобы быть распакованными после успешного джейлбрейка.

Далее пользователю предлагается запустить на своем телефоне приложение Jailbreak (на самом деле это DemoApp.app, который был создан в ходе выполнения Этапа 1). Напомним, что делает приложение:

#!/bin/launchctl submit -l remount -o /var/mobile/Media/mount.stdout -e /var/mobile/Media/mount.stderr -- /sbin/mount -v -t hfs -o rw /dev/disk0s1s1

С переменной окружения

LAUNCHD_SOCKET = /private/var/tmp/launchd/sock

Если вы прочтете мануал на launchctl, вы увидите, что команда подачи описывается следующим образом:

submit -l label [-p executable] [-o path] [-e path] -- command [args]

Простой способ подачи программы для запуска без конфигурационного файла. Этот механизм также сообщает launchd команду поддерживать работу программы в случае отказа.

-l label

Уникальный лейбл, использующийся для назначения этого задания launchd.

-p program

Программу, которую необходимо выполнить независимо от того, что следует за — в подаваемой подкоманде.

-o path Куда отправить stdout программы.

-e path Куда отправить stderr программы.

Если вы взглянете на страницу мануала launchd, вы увидите:

ENVIRONMENTAL VARIABLES
LAUNCHD_SOCKET

Эта переменная экспортируется, когда вызов команды осуществляется через командную строку launchd. Она сообщает launchctl о том, как найти нужный сокет launchd для коммуникации.

В отличие от большинства других компонентов iOS, механизм IPC (interprocess communication, взаимодействие между процессами — прим. пер.) launchd работает через сокеты сервисов UNIX. Существует несколько процессов launchd, каждый из которых работает для каждого пользователя. На iOS имеется один процесс, работающий как root (администратор), и еще один — как mobile (обычный пользователь). Поэтому пользователь запускает launchctl через DemoApp.app с обычными привилегиями доступа. Тем не менее launchctl не обращается к launchd, относящемуся к mobile user. Вместо этого он обращается к launchd, запущенному с административным доступом, через сокет launchd, открытый ранее через права доступа UNIX с использованием уязвимости /var/db/timezone.

Поскольку launchd работает как root (администратор), эта команда будет выполняться от имени администратора. В рамках этого процесса системный раздел диска устройства будет преобразован в режим «чтение-запись» (вся суть джейлбрейка — открыть системный раздел файловой системы устройства на запись, так как обычно он доступен только для чтения — прим. пер.), что позволяет эксплойту вносить изменения в системный раздел, которые будут выполнены с правами администратора при загрузке устройства.

Этап 3

И вот начинается заключительный этап джейлбрейка, вновь с использованием MobileBackup, однако на этот раз с полным доступом к системному разделу диска устройства.

каталог: Media/
каталог: Media/Recordings/
символьная ссылка: Media/Recordings/.haxx -> /
символьная ссылка: Media/Recordings/.haxx/private/etc/launchd.conf -> /private/var/evasi0n/launchd.conf
каталог: Media/Recordings/.haxx/var/evasi0n
файл: Media/Recordings/.haxx/var/evasi0n/evasi0n
файл: Media/Recordings/.haxx/var/evasi0n/amfi.dylib
файл: Media/Recordings/.haxx/var/evasi0n/udid
файл: Media/Recordings/.haxx/var/evasi0n/launchd.conf

Это может выглядеть несколько запутанно в связи с избыточным использованием символьных ссылок, но по сути, это создает каталог /var/evasi0n, содержащий исполняемый файл, библиотеку и новый файл launchd.conf. Launchd.conf описывается Apple следующим образом:

ОПИСАНИЕ:

launchd.conf состоит из перечня подкоманд (load, unload и т.д.) для запуска через launchctl(1), когда запускается launchd(8).

Подставной launchd.conf, запускающийся при каждой загрузки, содержит:

bsexec .. /sbin/mount -u -o rw,suid,dev /
setenv DYLD_INSERT_LIBRARIES /private/var/evasi0n/amfi.dylib
load /System/Library/LaunchDaemons/com.apple.MobileFileIntegrity.plist
bsexec .. /private/var/evasi0n/evasi0n
unsetenv DYLD_INSERT_LIBRARIES
bsexec .. /bin/rm -f /private/var/evasi0n/sock
bsexec .. /bin/ln -f /var/tmp/launchd/sock /private/var/evasi0n/sock

Вот что он делает, поэтапно:

bsexec .. /sbin/mount -u -o rw,suid,dev /

Устанавливает системному разделу диска атрибуты «чтение-запись»

setenv DYLD_INSERT_LIBRARIES /private/var/evasi0n/amfi.dylib

Загружает библиотеку amfi.dylib в любой исполняемый файл, который запускается после этого этапа

load /System/Library/LaunchDaemons/com.apple.MobileFileIntegrity.plist

Загружает сервис MobileFileIntegrity

bsexec .. /private/var/evasi0n/evasi0n

Запускает специально подготовленный код, ранее помещенный в /var/evasi0n/evasi0n

unsetenv DYLD_INSERT_LIBRARIES

Очищает переменную окружения DYLD_INSERT_LIBRARIES, чтобы amfi.dylib больше никуда не загружался

bsexec .. /bin/rm -f /private/var/evasi0n/sock

Удаляет сокет-файл, ранее присутствовавший в /private/var/evasi0n/sock

bsexec .. /bin/ln -f /var/tmp/launchd/sock /private/var/evasi0n/sock

Создает символьную ссылку с /var/tmp/launchd/sock на /private/var/evasi0n/sock, что позволяет другому коду получать прямой доступ к сокету административного launchd

После этого эксплойт перезагружает устройство, в результате чего эта конфигурация строка за строкой выполняется во время следующего запуска. Интересная особенность amfi.dylib и evasi0n состоит в том, что они не имеют криптографическую подпись. Если взглянуть на amfi.dylib с помощью otool, можно увидеть, что там вообще нет раздела TEXT/text. Отсутствие раздела TEXT/text означает, что там просто нечего подписывать. Вместо этого там содержится следующая информация для линковщика (компонент системы, отвечающий за привязку вызовов системных библиотек — прим. пер.):

$ dyldinfo -export amfi.dylib
export information (from trie):
[re-export] _kMISValidationOptionValidateSignatureOnly (_kCFUserNotificationTokenKey from CoreFoundation)
[re-export] _kMISValidationOptionExpectedHash (_kCFUserNotificationTimeoutKey from CoreFoundation)
[re-export] _MISValidateSignature (_CFEqual from CoreFoundation)

Благодаря умному использованию особенностей линковщика, системные методы (такие как CFEqual()) могут быть переопределены на другие, в результате чего другие вызовы, такие как MISValidateSignature, всегда будут выдавать 0, что позволяет запускать любой неподписанный бинарный код.

Заключение

Evasi0n интересен тем, что он получает административный доступ, а затем и полный доступ к системному разделу диска устройства безо всяких трюков, связанных с загаживанием памяти (оперативная память устройства намеренно загружается мусором и специально подготовленным куском исполняемого кода, в результате чего исполняется этот подготовленный код в результате переполнения — прим. пер.). Он делает это, используя уязвимость с /var/db/timezone, чтобы получить доступ к административному сокету launchd. Затем он использует launchd, чтобы запустить MobileFileIntegrity с дополнительной библиотекой, не содержащей кода, которая переназначает MISValidateSignature, чтобы та всегда возвращала 0.

Благодарим Славу Карпенко за помощь при создании материала.

По материалам Accuvantlabs.com

Как работает джейлбрейк Evasi0n. Заключение. Фото.