История джейлбрейков для iOS. Часть 1.

Ivan Ponurovskiy
12 min readApr 14, 2019

--

Введение

29 июня 2007 года компания Apple выпускает свой первый телефон с сенсорным управлением. Продукт имел такой огромный успех, что и по сей день устройства Apple, в том числе и телефоны, занимают огромную долю рынка мобильных устройств, и спрос на них по-прежнему высок.

Одной из особенностей первого iPhone (да и всех последующих моделей) являлось то, что файловая система была закрытой, то есть пользователь не мог по своему желанию добавлять или модифицировать элементы системы. Именно по этой причине возникает сама идея джейлбрейка (jailbreak). В общих словах, джейлбрейк — это процедура, позволяющая получить полные права доступа ко всем разделам на устройстве.

Изначально, джейлбрейк сводился к модифицированию файла /private/etc/fstab, в котором прописаны права доступа к разделам системы. Например, до джейлбрейка содержимое файла было таким:

/dev/disk0s1s1 / hfs ro 0 1/dev/disk0s1s2 /private/var hfs,nosuid,nodev rw 0 2

Здесь, как мы видим, корень системы “/“ имеет права read-only. После джейлбрейка этот же файл выглядит немного по-другому, и теперь у нас есть полные права ко всей файловой системе:

/dev/disk0s1s1 / hfs rw 0 1/dev/disk0s1s2 /private/var hfs,nosuid,nodev rw 0 2

Первоначальные джейлбрейки были достаточно простыми, так как защитные функции iOS находились еще в зачаточном состоянии и для того, чтобы обойти их, нередко хватало одного эксплойта. Но чем дальше, тем сложнее: в каждой новой версии iOS Apple устраняет уязвимости и добавляет новые и все более стойкие механизмы защиты. Так, в скором времени становится недостаточным только лишь модифицировать файл /private/etc/fstab, необходимо еще и вносить изменения в ядро, чтобы обойти, например, ограничения песочницы (sandboxing) или проверку подписи кода (code signing). Сами джейлбрейки тоже становятся все изощреннее и хитрее, и, когда, с выходом глобального обновления безопасности iOS, кажется, что вот теперь систему точно не удастся взломать, и надежды на джейлбрейк нет; последний появляется буквально через пару месяцев. Эта гонка продолжается до сих пор; закончится ли она когда-нибудь победой одного из “участников” — неизвестно.

Далее мне хотелось бы рассмотреть всю историю джейлбрейков, как они работают, какие уязвимости эксплуатируют, начиная от iPhone OS 1 вплоть до настоящего времени.

Но, перед тем, как перейти к рассказу о первых джейлбрейкам, немного теории.

Как известно, один из “столпов” безопасности iOS — цепочка доверенной загрузки. Это означает, что система загружается поэтапно: При включении устройства процессор немедленно начинает исполнять код из read-only памяти, так называемой BootROM. Код зашивается в чип еще при производстве, поэтому к коду имеется безоговорочное доверие. BootROM также содержит сертификат корневого центра сертификации Apple. C помощью сертификата BootROM проверяет цифровую подпись низкоуровнего загрузчика (Low-Level Bootloader — LLB). LLB затем проверяет подпись и запускает следующий загрузчик — iBoot. И, наконец, iBoot проверяет и запускает ядро.

Джейлбрейк может эксплуатировать уязвимости на одном или на нескольких уровнях:

  • на уровне BootROM. Такие джейлбрейки считаются самыми стойкими, потому что BootROM “вшит” в устройство, и обновление iOS не сможет устранить критическую уязвимость. Таких (публичных) эксплойтов было мало, и найти их сложнее всего. Самый известный, это, пожалуй, limera1n expoit;
  • на уровне iBoot;
  • на уровне ядра;
  • на уровне пользовательских процессов.

Также все джейлбрейки можно разделить на 4 типа:

  • непривязанные (untethered) — такие джейлбрейки не слетают при перезагрузке устройства, то есть единожды сделав джейлбрейк с помощью компьютера — в дальнейшем он уже не понадобится;
  • привязанные (tethered) — действуют до первой перезагрузки устройства. Чтобы сделать привязанный джейлбрейк, нужно подключать устройство к компьютеру и запускать специальную утилиту. Если в дальнейшем пользователь попытается загрузить устройство без подключения к компьютеру, то это может привести либо к “застреванию” в режиме восстановления (Recovery Mode), либо устройство загрузится, но на нем не будут работать некоторые программы, например Cydia, Mail, Safari, твики.
  • полупривязанные (semi-tethered) — в отличие от предыдущего типа, полупривязанные джейлбрейки слетают при перезагрузке, но устройство и все программы на нем (кроме Cydia и твиков) при этом остаются рабочими. Для повторного джейлбрейка опять же необходимо подключение к компьютеру.
  • полунепривязанные (semi-untethered) — появились относительно недавно: слетают при перезагрузке, устройство при этом остается рабочим, но для повторного джелбрейка компьютер уже не нужен: такой джейлбрейк, как правило, загружается прямо на телефон как отдельное приложение с помощью Cydia Impactor. После перезагрузки пользователь может просто запустить эту программу, чтобы повторить джейлбрейк.

1. iPhone OS 1

Первая версия операционной системы вышла вместе с первым же iPhone, но называлась она тогда не iOS, а просто iPhone OS 1.0. Вряд ли сейчас возможно найти “живое” устройство, которое работало бы на этой версии. Информацию о ней можно собрать разве что по записям в Интернете.

iPhone OS 1 еще не могла похвастаться высокой защищенностью: все процессы выполнялись от имени root, не было песочницы и проверки подписи кода. Кроме того, количество предустановленных приложений было весьма незначительным: SMS, Календарь, Фото, Камера, Youtube, Акции, Карты, Погода, Часы, Калькулятор, Настройки, Заметки, Почта, Safari. AppStore тогда еще тоже не было, поэтому и новые приложения было устанавливать неоткуда.

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

Самые первые джейлбрейки назывались AppTapp Installer и iBrickr: они оба использовали так называемый “iBoot cp-command” эксплойт и поддерживали версии 1.0/1.0.1/1.0.2 iPhone OS. Различие между ними заключалось лишь в том, что AppTapp Installer написан только под Mac OS X, а iBriсkr — только под Windows. Оба джейлбрейка позволяли установить пользовательские рингтоны и приложения из сторонних репозиториев (Сydia тогда еще не было!). На просторах Интернета мне удалось найти только файлы iBrickr, поэтому давайте на его примере рассмотрим, как работали первые джейлбрейки.

1.1 iBrickr

iBrickr — это по сути набор из нескольких утилит и файлов. Основные, на которые стоит обратить внимание: ibrickr.exe — визуальная оболочка джейлбрейка; jailbreak.exe — собственно, джейлбрейк; утилита командной строки, которая на вход получает два параметра: Restore Ramdisk (файловая система, которая целиком находится в оперативной памяти) и kernelcache (ядро системы).

Джейлбрейк происходит в несколько этапов:

  • Сначала ibrickr.exe просит перевести устройство в Recovery Mode, загружает необходимый файл прошивки (ipsw) и разархивирует его. Из архива достаются файлы Restore Ramdisk, kernelcache и передаются на вход jailbreak.exe;
  • jailbreak.exe общается с телефоном посредством библиотеки iTunesMobileDevice.dll, при этом используются приватные функции. Например, чаще всего будут встречаться функции VSendCommandToDevice и VSendFileToDevice:
  • С помощью VSendFileToDevice kernelcache и ramdisk загружаются на телефон;
  • Далее утилита с помощью протокола AFC создает два модифицированных файла на рамдиске: /root/Media/fstab, /root/Media/Services.plist. AFC (Apple File Conduit) — это сервис, который позволяет обмениваться данными с телефоном, но только внутри папки /Media. Именно благодаря этому протоколу iTunes может получить доступ к фотографиям на телефоне. Обратите внимание, что в iPhone OS пользователя mobile еще не было, поэтому AFC создавал файлы в папке /root/Media, а не в /mobile/Media, как сейчас. Services.plist — это файл, содержащий перечень сервисов, которые должны быть запущены после загрузки устройства. Модифицированный Services.plist содержит одну дополнительную запись — сервис AFC2, который имеет доступ уже к корню файловой системы, а не только к папке /Media. Джейлбрейки вплоть до iOS 8 будут модифицировать этот файл, чтобы добавить поддержку AFC2:
  • Затем джейлбрейк монтирует системный раздел /dev/disk0s1 к /mnt1, а раздел рамдиска /dev/disk0s2 к /mnt2
  • Остается только скопировать модифицированные файлы: /mnt2/root/Media/fstab /mnt1/etc/fstab, /mnt2/root/Media/Services.plist /mnt1/System/Library/ Lockdown/Services.plist
  • На заключительном этапе джейлбрейка файлы /root/Media/fstab и root/Media/Services.plist удаляются, смонтированные разделы отключаются, и устройство перезагружается.

После джейлбрейка iBrickr.exe загружает на телефон демона PXLdaemon — это по сути предшественник Cydia, которые позволяет устанавливать PXL-пакеты с программами от сторонник разработчиков. AppTapp для этих целей устанавливал отдельное приложение, которое называлось Installer.app.

В дальнейшем взаимодействие с телефоном осуществлялось с помощью утилиты iphoneinterface.exe. iphoneinterface.exe позволял загружать/скачивать файлы на телефон, а также имитировать выполнение таких команд на телефоне, как ls, cd, mkdir, rmdir и.т.п. На самом же деле в основе утилиты лежит взаимодействие по тем же приватным функциям iTunesMobileDevice.dll и протоколу AFC2, открывающему доступ ко всей файловой системе.

Как мы видим, первые джейлбрейки были весьма просты в своем исполнении и использовали скорее не уязвимости, а просто уловки, связанные с особенностями первых версии iPhone OS. Следующий джейлбрейк использует уязвимость в библиотеке libtiff и позволяет сделать джейлбрейк вообще без использования компьютера.

1.2 AppSnapp/JailbreakMe 1.0

Уязвимости в библиотеке libtiff подвержены версии iPhone OS 1.0/1.0.1/1.0.2/1.1.1. Специальный TIFF-файл, загруженный в Safari вызывал переполнение буфера в libtiff, что и позволяло сделать джейлбрейк. Причем пользователю достаточно было открыть в Safari сайт jailbreakme.com, и всё! Это первый так называемый Safari-based джейлбрейк.

Исходный код libtiff-эксплойта можно все еще найти в Интеренете, например здесь: https://github.com/OpenJailbreak/JailbreakMe-1.0/blob/master/tiff_exploit.cpp

Сначала эксплойт создает специальный TIFF-файл, которые приводит к переполнению буфера в библиотеке libtiff и затем передает управление шеллкоду.

Первым делом шеллкод переименовывал папку/var/root/Media в /var/root/Oldmedia :

stack.Add(Node(0, Node::PTR));      // r0 = "/var/root/Media"stack.Add(Node(1, Node::PTR));      // r1 = "/var/root/Oldmedia"stack.Add(Node(20, Node::BYTES));   // r2,r3,r5,r6,r12stack.Add(Node(12, Node::STACK));   // sp  -> offset 12stack.Add(ldmia_sp_r4);             // lr = load r4,r7,pc from spstack.Add(rename);                  // pc = rename(r0, r1)

Затем создается симлинк /var/root/Media, ссылающийся в корень файловой системы / (symlink-уязвимость):

stack.Add(Node(2, Node::PTR));           // r0 = "/"stack.Add(Node(0, Node::PTR));           // r1 = "/var/root/Media"stack.Add(Node(20, Node::BYTES));        // r2,r3,r5,r6,r12stack.Add(Node(12, Node::STACK));        // sp -> offset 12stack.Add(ldmia_sp_r0);                  // lr = load r0..pc from spstack.Add(symlink);                      // pc = symlink(r0, r1)

И, наконец, раздел файловой системы /dev/disk0s1 перемонтируется с флагом MNT_UPDATE. Вызов команды mount c этим флагом (но без MNT_RDONLY) превращал файловую систему read-only в read/write:

stack.Add(Node(3, Node::PTR));         // r0 = "hfs"stack.Add(Node(2, Node::PTR));         // r1 = "/"stack.Add(Node(0x00050000, Node::VAL));// r2 = MNT_RELOAD|MNT_UPDATEstack.Add(Node(8, Node::STACK));       // r3 = **datastack.Add(mount);                      // pc = mount(r0, r1, r2, r3)stack.Add(Node(4, Node::PTR));         // data = "/dev/disk0s1"

Для ранних версии iOS достаточно было всего одной уязвимости, чтобы сделать джейлбрейк. Механизмы защиты DEP (Data Execution Protection) и KASLR (Kernel Address Space Layout Randomization), которые присутствуют в современных версия iOS, исключили бы даже потенциальную возможность этого эксплойта, но на тот момент таких механизмов защиты еще не было. В iPhone OS 1.1.2 Apple исправляют libtiff и symlink-уязвимости, и для обхода защиты приходится искать другой путь.

1.3 OktoPrep + touchFree

Для того, чтобы сделать джейлбрейк iPhone OS 1.1.2 необходимо было выполнить определенную последовательность действий. Для начала, нужно иметь уже “взломанное” устройство с предыдущей версией iPhone OS 1.1.1. Далее, скачать из репозитория пакет OktoPrep, который “подготовит” телефон для последующего джеилбрейка. Своим названием OktoPrep обязан вероятно тому, что кодовым именем iPhone OS 1.1.2 было Oktoberfest. В сущности, OktoPrep — это простой скрипт, который создает в папке /var/root/Media/ символьный файл устройства, указывающий на системный раздел rdisk0s1:

mknod /var/root/Media/disk c 14 1

Это так называемая “mknod — уязвимость”; благодаря ей, последующий джейлбрейк touchFree мог получить доступ к этому файлу (а значит и ко всей системе) через протокол AFC. После этого подготовительного этапа пользователю оставалось обновить версию iPhone OS до 1.1.2 и запустить touchFree.

Исходный код touchFree, написанный на Java, можно найти по этой ссылке: https://github.com/planetbeing/touchfree

Для взаимодействия с устройством touchFree использовал утилиту iPHUC. iPHoneUtilityClient — это улучшенная версия упоминавшейся уже утилиты iPhoneInterface.

Вкратце, алгоритм touchFree выглядит следующим образом:

  • Проверить, подключено ли устройство, и создан ли на нем файл устройства /var/root/Media/disk;
  • Скопировать файлы репозитория Installer.app и ssh в папку /var/root/Media/touchFree/;
  • Скопировать необходимые системные утилиты (chmod, cp, csh и.т.п), скрипты и библиотеки в папку /var/root/Media/touchFree. Среди копируемых файлов особенно важными будут planetbeing.dylib — динамическая библиотека, которая чуть позже будет внедряться в системный процесс; модифицированный файл Services.plist c сервисом AFC2; утилита springpatch для патчa Springboard и утилита ldpatch для патча lockdownd;
  • Прочитать весь системный раздел через файл устройства /var/root/Media/disk и сохранить его во временном образе rdisk0s1.dmg;
  • В скопированном образе изменить два файла: fstab и com.apple.syslogd.plist. В последнем файле добавлялась еще одна запись: DYLD_INSERT_LIBRARIES: /var/root/Media/touchFree/planetbeing.dylib. Это означает, что при следующем запуске сервиса syslogd, в него будет внедрена “вредоносная” библиотека planetbeing.dylib.
  • Перезаписать системный раздел модифицированным образом и перезагрузить устройство.

После перезагрузки системный раздел монтируется как r/w, а процесс syslogd при запуске подгружает библиотеку planetbeing.dylib и выполняет код, который в ней содержится. Библиотека в свою очередь просто копирует системные утилиты из /var/root/Media/touchFree в /bin, заменяет файл Services.plist на модифицированный (с сервисом AFC2), а из файл com.apple.syslogd.plist удаляет запись DYLD_INSERT_LIBRARIES (код библиотеки достаточно выполнить всего один раз). И, наконец, запускает скрипт /var/root/Media/touchFree/run.sh.

Скрипт копирует файлы Installer.app, SSH в /Applications, и запускает патчи Springboard (springpatch) и lockdownd (ldpatch).

Процесс Springboard на домашнем экране отображает иконки не всех приложений, а только тех, которые перечислены в свойстве allowedDisplayIcons класса SBPlatformController; поэтому одного копирования Installer.app недостаточно: иконка этого приложения просто не будет видна на экране. Утилита springpatch устраняет это ограничение, она патчит методы [SBIconController relayoutIcons] и [SBIconModel addItemsToIconList: fromPath: withTags:], благодаря чему Installer.app виден на домашнем экране. Утилита ldpatch проводит так называемую хактивацию — патчит процесс lockdownd и обходит стандартный процесс активации устройства (если оно еще не было активировано до джейлбрейка).

Apple закрывает mknod-уязвимость в iPhone OS 1.1.3: c этой версии пользовательский раздел rdisk0s1 монтируется с флагом nodev. Это означает, что на нем теперь нельзя создавать файлы устройств. Кроме того, практически все процессы, начиная с этой версии запускались от имени пользователя mobile, а не root.

1.4 ZiPhone и iLiberty

Следующие две утилиты — ZiPhone и iLiberty — позволяли сделать не только джейлбрейк, но и анлок (отвязку от оператора) и активацию. Все это возможно благодаря уязвимости, обнаруженной спустя чуть меньше месяца после выхода iPhone OS 1.1.3. Уязвимость эта называется Ramdisk Hack и заключается она в том, что любой, даже неподписанный рамдиск будет загружен на устройство в Recovery Mode, если он располагается в памяти по адресу, большему 0x09C00000.

Использование Ramdisk Hack можно рассмотреть на примере ZiPhone, iLiberty работает примерно по такому же принципу. У утилиты есть графическая оболочка, которая предлагает выбрать дальнейшие действия — джейлбрейк, анлок, активацию или всё сразу. Нам интересен джейлбрейк, поэтому остановимся подробнее на нем.

  • Сначала утилита загружает файл Inga.dat на устройство в папку /var/mobile/Media/ (по протоколу AFC). Этот файл на самом деле является zip-архивом, содержащим необходимые системные утилиты (chown, su, scp, sftp, ssh), приложения (Installer.app, Terminal.app), конфигурационные файлы (например настройки ssh и список ресурсов для Installer.app);
  • Далее ZiPhone просит перевести устройство в Recovery Mode и после его обнаружения сначала устанавливает переменные nvram-окружения, например так:
setenv unlock 1setenv activate 1setenv jailbreak 1setenv boot-args rd=md0 -s -x pmd0=0x09CC2000.0x0133D000
  • Позже рамдиск будет читать эти переменные окружения из nvram, чтобы понять, какие именно действия от него требуется. Обратите внимание на последнюю строчку, где устанавливаются аргументы загрузки (boot-args). Именно в этом месте и эксплуатируется уязвимость Ramdisk Hack: мы загружаем рамдиск по адресу 0x09CC2000 в безопасном (-x) и однопользовательском (-s) режимах. В качестве рамдиска выступает файл zibri.dat, причем первые 0xCC2400 байт этого файла заполнены нулями, а со смещения 0xCC2400 начинается заголовок неподписанного dmg-диска.
  • После загрузки рамдиска автоматически запускается файл /etc/profile. Этот файл (bash-скрипт) читает переменные окружения из nvram и выполняет нужные действия. Для джейлбрейка скрипт сначала монтирует разделы:
/sbin/mount_hfs -o noasync,sync /dev/disk0s1 /mnt1 >/dev/null/sbin/mount_hfs -o noasync,sync /dev/disk0s2 /mnt2 >/dev/null
  • Затем необходимые файлы копируются с рамдиска на подмонтированные разделы. Среди этих фалов — шелл, еще один скрипт prof.sh, который выполнится сразу после перезагрузки устройства, модифицированный fstab:
if [ "`/usr/bin/nvram jailbreak 2>/dev/null|/bin/cut -f 2`" == "1" ] ; then/bin/echo "Starting jailbreak..."/bin/cp /bin/sh /mnt1/bin/sh/bin/cp /bin/sync /mnt1/bin/sync/bin/cp /bin/rm /mnt1/bin/rm/bin/cp /zib/prof.sh /mnt1/private/etc/profile/bin/cp /zib/fstab /mnt1/private/etc/fstabfi
  • И, наконец, скрипт отключает подмонтированные разделы, удаляет переменные окружения и перезагружает устройство:
/bin/echo "Unmounting filesystems..."/usr/bin/umount /mnt1 >/dev/null/usr/bin/umount /mnt2 >/dev/null/usr/bin/nvram -d unlock >/dev/null/usr/bin/nvram -d imei >/dev/null/usr/bin/nvram -d ierase >/dev/null/usr/bin/nvram -d jailbreak >/dev/null/bin/echo "Now rebooting..."/sbin/mount -uw / >/dev/null/sbin/reboot >/dev/nullwhile (true); do sleep 1; done
  • После перезагрузки автоматически выполняется скрипт prof.sh, который был скопирован в /private/etc/profile на предыдущем шаге. Этот скрипт разархивирует файл /private/var/mobile/Media/Inga.dat, выставляет права (скрипт Inga.sh), удаляет Inga.dat и еще раз перезагружает систему:
if [ -f /private/var/mobile/Media/Inga.dat ]; thenecho "Installing software..."mount -uw / >/dev/nullsyncunzip -o -K -X /private/var/mobile/Media/Inga.dat -d / >/dev/nullsyncif [ -f /tmp/Inga.sh ]; thenecho "Executing post-install script...". /tmp/Inga.shrm /tmp/Inga.sh >/dev/nullfirm /private/var/mobile/Media/Inga.dat >/dev/nullsyncmount -ur / >/dev/nullfi

Все, на этом джейлбрейк завершен. Отмечу также, что патчить SpringBoard больше не нужно: проверки на allowedDisplayIcons в новых версиях iPhone OS не было; но lockdownd по-прежнему патчится, только при выборе опции activate. Кроме того, ZiPhone не устанавливает протокол AFC2, как это делали другие джейлбрейки, пользователю необходимо было сделать это вручную уже после джейлбрейка.

Ramdisk Hack можно было использовать только на версиях iPhone OS 1.1.3/1.1.4/1.1.5. Начиная с iPhone OS 2.0, аргумент, показывающий, с какого адреса загружать рамдиск, игнорировался. Об уязвимостях и джейлбрейках для iPhone OS 2 речь пойдет в следующей главе, а пока приведу таблицу, в которой сведена информация по джейлбрейкам для iPhone OS 1:

--

--

Ivan Ponurovskiy

Hi, my name is Ivan! I work as a security researcher and developer. My field of interest includes iOS architecture and reverse engineering. See you in my blog!