Совсем недавно вышел свежий набор утилит для «джейла» iOS. Пришло время разобрать его и посмотреть, какие эксплойты и механизмы проникновения он использует. Сейчас «джейлить» iOS стало настолько просто, что люди забывают, насколько это сложный процесс. Механизмы защиты, встроенные в пространство пользователя, такие как песочница, ASLR (Address Space Layout Randomisation – рандомизация расположения в адресном пространстве) и механим цифровых подписей, делают процесс написания «джейла» невероятно сложным.
Стоит отметить, что, в отличие от предыдущих эксплойтов jailbreak.me, которые можно было использовать на ничего не подозревающих жертвах, «джейлы», которые требуют подключения по USB обычно несут меньшие угрозы безопасности, и типично полезны только самому владельцу устройства. Злоумышленники заинтересованы в них меньше, так как айфон с установленным пин-кодом откажется общаться по USB если он заблокирован, если он, конечно, ранее не был синхронизирован с компьютером, куда его подключают. Таким образом, если телефон был украден и на нем был установлен пин-код, злоумышленник не сможет «джейлнуть» его. Только вредоносный код, выполняемый на вашем компьютере может иметь хоть какую-то возможность выполнить «джейл» незаметно.
Evasi0n в пространстве пользователя
Эта статья сконцентрирована на пользовательском компоненте Evasi0n. Механизм, используемый в Evasi0n уникален, потому что он целиком основан на взаимодействии с файловой системой, ему не требуются более типичные подходы повреждения данных в памяти для повышения привилегий до root-пользователя. Возможно, Evasi0n был так назван именно потому что он избегает все защиты пространства пользователся, вместо того чтобы атаковать их в лоб.
Evasi0n работает в три этапа, описанных далее. Все они основаны на стандартной функциональности iOS, доступной через сервис MobileBackup, который делает архивные копии данных на устройстве и восстаналивает эти же копии назад при необходимости. Поскольку сами архивные копии создаются на одном iOS-устройстве, но должны иметь возможность быть восстановленными на другое, их сложно обезопасить криптографическим путем, т.е. данные в копиях фактически не достоверные.
MobileBackup использует домен, например MediaDomain
, и относительный путь в пределах домена для идентификации каждого файла. За каждым доменом константно зафиксирована определенная директория, и комбинация из пути к этой директории и относительного пути к файлу дает полный путь. Evasi0n создает все рабочие файлы в домене MediaDomain
, таким образом у всех файлов рабочий префикс это /var/mobile/Media
.
Этап 1
Во время первого этапа, Evasi0n создает новую пустую архивную копию для восстановления на устройство, содержащую следующие файлы:
directory: Media/
directory: Media/Recordings/
symlink: Media/Recordings/.haxx -> /var/mobile
directory: Media/Recordings/.haxx/DemoApp.app/
file: Media/Recordings/.haxx/DemoApp.app/Info.plist
file: Media/Recordings/.haxx/DemoApp.app/DemoApp
file: Media/Recordings/.haxx/DemoApp.app/Icon.png
file: Media/Recordings/.haxx/DemoApp.app/Icon@2x.png
file: Media/Recordings/.haxx/DemoApp.app/Icon-72.png
file: Media/Recordings/.haxx/DemoApp.app/Icon-72@2x.png
file: Media/Recordings/.haxx/Library/Caches/com.apple.mobile.installation.plist
Символьная ссылка из .haxx в /var/mobile создается для обхода ограничения работы с файлами только в пределах домена, т.е. хотя стандартное ограничение не допустит копирования фалов вне /var/mobile/Media
, но с помощью символьной ссылки файлы фактически попадают в /var/mobile
. Этот подход уже использовался в «джейлах» и ранее.
Далее, DemoApp.app
, обычное iOS приложение, создается в /var/mobile
. Это обычное приложение, с иконками и прочими сопроводительными файлами. Так же обновляется файл com.apple.mobile.installation.plist
, где Springboard хранит кеш путей к приложениям, чтобы иконка DemoApp появилась среди остальных.
В отличие от обычного 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
Фактически, при запуски программы DemoApp, на самом деле запускается launchctl
с заданными аргументами.
Помимо этого, в com.apple.mobile.installation.plist
немного модифицируется окружение для запуска DemoApp:
<key>EnvironmentVariables</key>
<dict>
<key>LAUNCHD_SOCKET</key>
<string>/private/var/tmp/launchd/sock</string>
</dict>
Устройство перезагружается, Springboard перечитывает кеш и отображает иконку.
Этап 2.1
Предидущие файлы остаются на местах, второй этап создает еще одну пустую архивную копию и восстанавливает на устройство еще несколько файлов:
directory: Media/
directory: Media/Recordings/
symlink: Media/Recordings/.haxx -> /var/db
symlink: 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 общается c lockdownd
, путем отправки неправильно сформированной команды PairRequest
. Lockdownd – это основной демон, который выполняет коммуникацию по USB, так же он используется для запуска/остановки других сервисов, таких как MobileBackup и AFC (Apple File Connection – сервис который позволяет обмениватся файлами с iTunes). Поскольку lockdownd
работает с правами root-пользователя и пользователь может общаться с ним, злоупотребление его возможностями или уязвимостями стало популярным в последних «джейлах».
Теперь мы подошли к первой уязвимости. Отправка некорректного пакета PairRequest
заставляет lockdownd
изменить права доступа к /var/db/timezone
на 777, таким образом делая /var/tmp/launchd
доступным для всех пользователей. Не ясно, уязвимость ли это непосредственно lockdownd
, или какой-то из библиотек, которуе он использует.
Этап 2.2
Evasi0n проникает вглубь /var/tmp/launchd
и модифицирует права доступа таким образом, что сокет launchd
становится доступным обычному пользователю. Так же, на этом этапе обновляется символьная ссылка на timezone:
symlink: Media/Recordings/.haxx/timezone -> /var/tmp/launchd/sock
Потом Evasi0n повторяет трюк с PairRequest
, делая /var/tmp/launchd/sock
доступным пользователю mobile.
Этап 2.3
Этот этап начинается с установки Cydia и архива пакетов на устройство. Они не будут использоваться прямо сейчас, но будут доступны уже после «джейла».
Далее, пользователю дается указание запустить приложение Jailbreak (фактически – DemoApp). Напомню еще раз, что оно делает:
#!/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
Если заглянуть в man по launchctl
то можно выяснить, что команда submit описана следующим образом:
submit -l label [-p executable] [-o path] [-e path] -- command [args]
A simple way of submitting a program to run without a configura-
tion file. This mechanism also tells launchd to keep the program
alive in the event of failure.
-l label
What unique label to assign this job to launchd.
-p program
What program to really execute, regardless of what fol-
lows the -- in the submit sub-command.
-o path Where to send the stdout of the program.
-e path Where to send the stderr of the program.
А в man по launchd
указано:
ENVIRONMENTAL VARIABLES
LAUNCHD_SOCKET
This variable is exported when invoking a command via the launchd command line. It informs launchctl how to find the correct launchd to talk to.
В отличие от большинства других вещей в iOS, IPC в launchd
основан на unix-сокетах. Так же, есть несколько процессов launchd
– по одному для каждого активного пользователя. На iOS один работает с правами root, другой – с правами mobile. Пользователь mobile выполняет launchctl
через DemoApp, но этот launchctl
общается не с launchd
пользователя mobile, вместо этого он общается с launchd
пользователя root из-за явно указанного пути к сокету и расширенных прав доступа, полученных через уязвимость с /var/db/timezone
.
Поскольку мы работаем с launchd
пользователя root, то и задача будет выполенна с правами root, что позволяет ей перемонтировать системный раздел с доступом на запись, чтобы позволить Evasi0n вносить изменения в систему, для выполнения их в раннем загрузочном окружении.
Этап 3
Финальный этап «джейла», и снова используется MobileBackup, но на этот раз уже есть полный доступ в системный раздел:
directory: Media/
directory: Media/Recordings/
symlink: Media/Recordings/.haxx -> /
symlink: Media/Recordings/.haxx/private/etc/launchd.conf -> /private/var/evasi0n/launchd.conf
directory: Media/Recordings/.haxx/var/evasi0n
file: Media/Recordings/.haxx/var/evasi0n/evasi0n
file: Media/Recordings/.haxx/var/evasi0n/amfi.dylib
file: Media/Recordings/.haxx/var/evasi0n/udid
file: Media/Recordings/.haxx/var/evasi0n/launchd.conf
Это выглядит немного запутанным из-за нескольких перенаправлений по символьным ссылкам, но фактически здесь создается каталог /var/evasi0n
с приложением и библиотекой, а так же новый 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
Сделают они следующее:
- перемонтируют системный раздел с правами на запись;
- amfi.dylib будет внедрен в любое приложение, начиная с этого момента;
- запускается сервис MobileFileIntegrity;
- запускается «вредоносный» код, записанный на предыдущем этапе;
- amfi.dylib больше не будет внедрятся;
- удаляется старая символьная ссылка на сокет в /private/var/evasi0n/sock;
- обновляется символьная ссылка /private/var/evasi0n/sock указывающая на /var/tmp/launchd/sock, позволяющая другому коду непосредственно взаимодействовать с launchd пользователя root.
Evasi0n перзагружает устройство, что выполняет описанную конфигурацию. Интересный момент связан с тем что ни amfi.dylib, ни evasi0n не содержат цифровой подписи. Если изучить файл amfi.dylib с помощью otool
, выясняется что в нем нет секции __text (прим переводчика: в секции __text сегмента __TEXT хранится машинный код). А если нет секции __text – то и подписывать нечего, и проверка на цифровую подпись выполняться не будет. Работает amfi.dylib с помощью информации о позднем связывании:
$ 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)
Эта техника рассмотрена в http://networkpx.blogspot.com/2009/09/compiling-iphoneos-31-apps-with-xcode.html:
Если мы сможем заставить MISValidateSignature() всегда возвращать 0, любые файлы пройдут тест. Эта функция – часть libmis.dylib, которая сейчас хранится в разделяемом кеше, так что сложно пропатчить саму функцию. Заменить реализацию этой функции с помощью MobileSubstrate было бы замечательно, но как я ни пытался, MS не мог ее подменить. Тогда я использовал трюк: создал «проксирующую» библиотеку, которая переадресует MISValidateSignature().
С помощью хитрого использования динамической библиотеки без кода, существующие нстоящие функции (такие как CFEqual()
) повторно экспортируются как другие функции с идентичными аргументами, что приводит к тому что MISValidateSignature()
всегда возвращает 0, позволяя выполнять любой исполняемый файл.
Итог
Evasi0n интересен тем, что он повышает привелегии и получает полный доступ к системному разделу без повреждений памяти процессов. С помощью уязвимости /var/db/timezone
он получает доступ к launchd
и модифицирует MobileFileIntegrity так, чтобы он всегда подтверждал, что цифровые подписи корректны.
Автор: farcaller