Рассматривается динамический анализ iOS-приложений
В первой статье данной серии мы обсуждали анализ трафика приложений iPhone. Вторая, третья и четвертая части были посвящены подробному анализу небезопасных мест хранения данных на iPhone. В данной статье мы рассмотрим динамический анализ приложений iOS (анализ во время выполнения). Динамический анализ позволяет атакующему манипулировать поведением приложения во время его выполнения, чтобы обойти механизмы безопасности и извлечь из памяти конфиденциальные данные. Перед тем, как перейти собственно к анализу, нам сначала нужно рассмотреть архитектуру приложения iOS и защитные механизмы, действующие во время его выполнения.
Приложение iOS представляет собой zip-архив с расширением .ipa. Архив содержит исполняемый двоичный файл и файл iTunesArtwork, который используется iTunes для управления приложением. Ниже показана типичная структура приложения iOS.
Папка в директории Payload, имя которой заканчивается на .app, содержит двоичный файл приложения, все ресурсы приложения вроде изображений и аудиозаписей, профиль, определяющий разрешения приложения, и подпись кода.
Двоичный файл приложения iOS скомпилирован под архитектуру ARM и использует файловый формат Mach-O (mach object). Данный файловый формат состоит из трех основных разделов: заголовка, загрузочных команд и сегментов/секций. Ниже показана структура файлового формата Mach-O.
Структура Mach-O файлов iOS-приложения может быть просмотрена на подвергшемся джейлбрейку устройстве с помощью утилиты otool. Otool доступен из пакета Darwin CC Tools в Cydia.
Раздел позволяет идентифицировать файл Mach-O и содержит основную информацию о типе файла вроде целевой архитектуры и флагов, влияющих на интерпретацию остальной части файла. Чтобы просмотреть Mach-O заголовок приложения iOS, подключитесь к iPhone через SSH и выполните команду:
otool –h ApplicationBinary
Вот заголовок Mach-O приложения Facebook для iOS.
Значения cputype и subtype в заголовке Mach-O определяют целевую архитектуру приложения. В показанном примере видно, что приложение Facebook имеет архитектуру ARM7.
ARM7s (iPhone 5) = cputype 12/ subtype 11
ARM7 (iPhone 4 & 4S) = cputype 12/ subtype 9
ARM6 (iPhone 3GS) = cputype 12/ subtype 6
Приложения, которые скомпилированы для нескольких архитектур, содержат более одного файла Mach-O. Соответствующие двоичные файлы также называются универсальными или толстыми. Чтобы посмотреть Mach-O заголовок универсального двоичного файла, выполните в SSH-терминале следующую команду:
otool –arch all -h ApplicationBinary
На рисунке выше видно, что приложение CardInfo скомпилировано для процессоров с архитектурами ARM7 и ARM7s.
Загрузочные команды определяют то, как сегменты файла располагаются в памяти, а также линковочные характеристики файла (связи с библиотеками). Они содержат первоначальную разметку файла в виртуальной памяти, расположение таблицы символов, состояние выполнения главного потока программы и информацию о подключаемых разделяемых библиотеках. Загрузочные команды (LC_ENCRYPTION_INFO) также определяют, зашифрован ли файл. Чтобы просмотреть загрузочные команды, выполните в SSH-терминале следующую строку:
otool –Vl ApplicationBinary
Файл Mach-O содержит собственно данные приложения в одном или нескольких сегментах. В каждом сегменте может быть некоторое количество секций, в том числе, нулевое. Каждая секция сегмента содержит код или данные определенного типа. Точное количество сегментов, секций и их расположение в памяти описывается в разделе загрузочных команд.
Платформа iOS предоставляет множество защитных механизмов, например, ASLR, защита от повреждения стека и ARC. Понимание этих механизмов защиты важно для выполнения реверсирования и анализа iOS-приложений.
ASLR – важный метод противодействия эксплоитам, появившийся в iOS 4.3. ASLR значительно усложняет удаленную эксплуатацию уязвимостей к повреждению памяти за счет рандомизации размещения объектов приложения в памяти. По умолчанию приложения iOS используют ограниченную ASLR, которая рандомизирует размещение только части объектов в памяти. Чтобы задействовать ASLR максимально, приложение должно быть скомпилировано с флагом -fPIE -pie
(в XCode этому флагу соответствует опция "Генерировать зависимый от расположения код"). В последнем выпуске XCode этот флаг выбран по умолчанию. На рисунке ниже показано состояние различных разделов памяти при частичном и полном применении ASLR.
Чтобы определить, было ли приложение скомпилировано с флагом PIE, подключитесь к iPhone по SSH и выполните команду:
otool –Vh ApplicaitonBinary
На рисунке выше в конце вывода мы видим слово PIE. Это означает, что приложение Facebook было скомпилировано с данным флагом.
Защита от повреждения стека – это механизм борьбы с эксплоитами, который защищает от атак переполнения стека путем помещения перед локальными переменными некоторого случайного, но известного значения, называемого стековой канарейкой (по аналогии с живыми канарейками, которых брали с собой шахтеры, чтобы проверить отсутствие взрывоопасных газов). При возврате из функции проверяется значение стековой канарейки. В случае переполнения канарейка будет повреждена, и, узнав об этом, приложение сможет защититься от переполнения. Чтобы включить защиту от повреждения стека, приложение нужно скомпилировать с флагом –fstack-protector-all.
Приложения iOS, которые используют стековых канареек, содержат в двоичном коде строки _stack_chk_fail и _stack_chk_guard. Чтобы определить, использует ли приложение защиту от повреждения стека, подключитесь к iPhone по SSH и выполните следующую команду:
otool –I –v ApplicationBinary | grep stack
Данный снимок экрана свидетельствует о том, что приложение Facebook использует защиту от повреждения стека.
ARC – еще один механизм для борьбы с эксплоитами, введенный в iOS 5. Он защищает приложения от уязвимостей к повреждению памяти путем перекладывания ответственности за управление памятью с разработчика на компилятор. ARC можно включить, установив значение "yes" для опции "Objective-C Automatic Reference Counting". По умолчанию данный механизм включен.
Приложения iOS с включенным ARC содержат в двоичном файле строку _objc_release. Чтобы определить, использует ли приложение ARC, выполните в SSH-терминале следующую команду:
otool –I –v ApplicationBinary | grep _objc_release
Показанный выше снимок экрана говорит о том, что приложение Facebook скомпилировано с поддержкой ARC.
Механизмы защиты во время выполнения создают дополнительный слой безопасности приложения. Поэтому хорошей практикой является явное включение этих механизмов при компиляции приложения, а в ходе тестирования на проникновение стоит проверить их наличие.
Чаще всего iOS-приложения пишутся на языке Objective-C. Objective-C – это динамический язык, основанный на принципах передачи сообщений между объектами. Поскольку язык является динамическим, все классы, методы и прочие компоненты хранятся внутри двоичного файла. Данная информация может быть извлечена с помощью утилиты class-dump-z, созданной kennytm.
wget -U Mozilla/5.0 http://www.securitylearn.net/wp-content/uploads/tools/iOS/class-dump-z.zip
unzip class-dump-z.zip
mv class-dump-z /usr/bin
class-dump-z ApplicationBinary
На рисунке ниже показана выгруженная информация о классах приложения Gmail для iOS. Здесь не содержится каких-либо полезных данных, поскольку двоичный файл зашифрован. Приложения, загруженные из AppStore, шифруются с помощью FairPlay DRM для защиты от пиратства.
Чтобы выяснить, является ли приложение зашифрованным, запустите в SSH-терминале следующие команды:
otool –l ApplicationBinary | grep crypt
cryptid 1 говорит о том, что приложение зашифровано. Для незашифрованных приложений значение cryptid равно 0.
Часто первым шагом при реверсировании iOS-приложений является снятие шифрования. Расшифровка приложения позволяет атакующему лучше понять, как работает приложение, внутреннюю структуру его классов, и подготовить двоичный файл для реверсирования. Изначально незашифрованными являются приложения, которые используют модель распространения in-house или являются самоподписанными.
Когда iOS-приложение запускается, загрузчик расшифровывает его и загружает в память. Данный факт лег в основу хорошо отлаженного метода, позволяющего снимать с приложения защиту от копирования FairPlay. Процесс расшифровки включает в себя следующие шаги:
Весь данный процесс можно автоматизировать с помощью приложений из Cydia, которые называются Clutch и Rasticrac.
installipa –c [iPAPath]
На рисунке ниже показаны выгруженные данные о классах расшифрованного приложения Gmail.
Полный дамп классов расшифрованного приложения позволяет узнать список классов и их методов, что позволяет глубже взглянуть на то, как устроено приложение. Как только дамп классов получен, мы можем искать интересующие нас классы, методы и проводить динамический анализ (анализ во время выполнения).
Динамический анализ включает в себя реверсирование приложения и анализ его потока управления для обхода блокировок, аутентификации, доступа к конфиденциальной информации в памяти, нарушения логических проверок и доступа к закрытым областям приложения. Objective-C – рефлективный язык, он позволяет модификацию своего поведения во время выполнения. На iPhone поведение приложения во время выполнения можно легко менять с помощью CyCript. CyCript можно найти среди пакетов Cydia.
Cycript – это язык программирования, сочетающий в себе Objective-C и Javascript. Cycript позволяет вмешиваться в процесс ОС и дает доступ ко всем классам, полям и методам выполняющегося приложения.
Перед тем, как приступить к динамическому анализу, необходимо изучить поток выполнения iOS-приложения.
Objective-C по сути является надстройкой над C, поэтому его выполнение начинается с функции main(). Фактически, main() вызывается, когда пользователь нажимает на значок приложения. Главная функция в свою очередь вызывает метод UIApplicationMain. Данный метод инициализирует объект UIApplication, отображает графический интерфейс (окна, представления), создает делегат приложения и запускает цикл обработки сообщений. Делегат приложения отслеживает высокоуровневые действия/события в приложении. С помощью Cycript мы можем подключиться к запущенному процессу и получить доступ к его объекту UIApplication. UIApplication – это синглтон, который представляет приложение и действует как центр управления. Так что, получение доступа к данному объекту – это получение доступа к внутренней структуре приложения.
Возможности Cycript показаны в следующих далее примерах. В целях демонстрации я использовал старую версию приложения Photo Vault. Перед внедрением в процесс с помощью cycript мы сначала выгрузим информацию о классах приложения через class-dump-z.
Приложение Photo Vault сохраняет конфиденциальность фотографий за счет ограничения доступа по паролю. Когда мы запускаем приложение в первый раз, оно просит пользователя установить пароль. В последующие разы для получения доступа к защищенным фотографиям пользователю нужно ввести правильный пароль. Ниже описаны шаги, как узнать пароль через динамический анализ посредством Cycript.
cycript –p [PID]
.
cycript –p [ApplicationName]
.
Cycript также позволяет модифицировать значения полей, вызывать методы и перезаписывать существующие методы прямо во время выполнения программы.
Это пятая часть серии статей о пентестинге приложений iPhone. В шестой части будет рассмотрен динамический анализ приложений iOS с помощью gdb и подмена методов с помощью Cycript.