В прошлой статье мы рассмотрели базовые уязвимости и способы их обнаружения. Но что делать, если в приложении используются дополнительные средства защиты (например, Jailbreak Detection или SSL-pinning), которые не позволяют нам изучить его? В этой статье расскажем, как и с помощью каких инструментов можно обходить данные средства защиты. Рассмотрим варианты от самых простых (использование твиков), до сложных (патчинг руками). Как и в предыдущей статье, рассматривать примеры обхода мы будем на специальном приложении – SecureStorev2, которое содержит некоторые методы защиты от запуска в недоверенной среде и SSL-pinning.

Jailbreak Detection

Jailbreak Detection – это процесс, в ходе которого приложение понимает, что оно запущено в недоверенной среде. На наличие Jailbreak'а может указывать множество прямых и косвенных признаков, но т.к. есть разные способы Jailbreak'a устройств, то и список проверок может быть довольно разнообразным и непостоянным. По этим причинам обнаружение Jailbreak'a – непростая задача, и в разных приложениях встречаются разные проверки: где-то они проще, а где-то сложнее и изобретательнее. Самые банальные проверки заключаются в анализе приложением файловой системы устройства: например, при установке Cydia создаются определенные файлы и директории, однозначно говорящие о том, что данное приложение находится на устройстве. Кроме того, все твики, установленные на iPhone, попадают в директорию /Application и имеют понятные названия, поэтому можно проверить эту директорию на наличие популярных твиков и понять, что устройство джейлбрейкнуто.

Обычно простые проверки успешно обходятся с помощью установленных в нашей первой статье твиков: A-Bypass и Liberty. Каждый из них содержит свою логику для обхода проверок на Jailbreak, поэтому если один из них не сработает, то стоит попробовать воспользоваться другим твиком.

Обычно, если в приложении есть проверка на Jailbreak, то оно выдает уведомление о том, что проверка не пройдена и дальнейшая работа на устройстве невозможна или, например, просто вылетает. В примере с SecureStorev2 мы сталкиваемся именно со вторым вариантом поведения приложения и делаем предположение, что дело именно в Jailbreak'е устройства.

Твики

Пробуем обойти эту проверку с помощью упомянутых ранее твиков и начинаем с A-Bypass:

В меню настройки A-Bypass можно попасть из общих настроек устройства через раздел с установленными твиками:

Внутри A-Bypass устанавливаем ползунок напротив интересующего нас приложения и пробуем его запустить:

Байпас через A-Bypass не сработал, и приложение по-прежнему вылетает, поэтому переходим ко второму варианту – Liberty.

Попасть в настройки Liberty можно так же, как и в настройки A-Bypass. Принцип активации байпаса для приложения тот же:

Пробуем открыть приложение – оно больше не вылетает, а значит байпас проверки на Jailbreak с помощью Liberty прошел успешно.

Еще одним простым способом байпаса является хорошо знакомый нам по прошлой статье Objection. В нем есть встроенная команда # ios jailbreak disable, однако в предыдущей статье мы сначала инжектились в приложение, а потом вводили необходимые нам команды. В случае, когда приложение сразу вылетает из-за проверки, мы можем воспользоваться флагом -s и передать необходимую нам команду, чтобы она выполнилась раньше проверки:

$ objection -g 'cst.securestorev2' explore -s "ios jailbreak disable"

В данном примере Objection тоже успешно выполнил байпас проверки:

Frida

Для Frida уже написано множество разных скриптов, которые помогают решить популярные и часто встречающиеся проблемы, их можно найти на Frida CodeShare. Попробуем воспользоваться скриптом оттуда для байпаса Jailbreak Detection:

$ frida --codeshare liangxiaoyi1024/ios-jailbreak-detection-bypass -U -f cst.securestorev2 --no-pause

В результате, как и в случае с Objection, мы видим, как именно проходит проверка на Jailbreak, и успешно проходим ее:

Ручной патчинг приложения

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

Посмотреть на классы приложения мы можем либо через Objection, либо через class-dump.

В Objection листинг классов выполняется командой # ios hooking list classes, но для рассмотрения еще одного инструмента, воспользуемся именно class-dump.

class-dump применяется к исполняемому файлу приложения, и в данном случае он сразу же есть у нас на руках, т.к. нам изначально доступен .ipa-файл приложения. Но очень часто во время исследований такого не бывает, и приходится дампить .ipa-файл вручную с устройства. Небольшая инструкция о том, как это сделать при помощи различных инструментов, находится в спойлере ниже:

Способы сдампить .ipa-файл

.ipa – формат архивных файлов приложений для установки на iOS-устройства. Любой .ipa-файл можно переименовать в .zip и посмотреть его структуру после распаковки.

Есть несколько инструментов, которыми можно достать .ipa-файл с устройства, про все из них мы говорили в первой статье. Рассмотрим получение .ipa-файлов на разных приложениях из AppStore.

frida-ios-dump

Приложение: BTSE

python dump.py -H <ios_dev_ip_addr> -p 22 <Application Identifier>

После ввода команды запускается приложение, начинается процесс дампа:

По окончании процесса мы должны увидить надпись Generating "<App_name>.ipa" без ошибок, и сам .ipa-файл в текущей директории:

Clutch

Приложение: Unstoppable

Подключаемся по ssh к iOS-устройству и выполняем команду:

$ Clutch -d <Application Identifier> 

После дампа .ipa-файл будет находиться в директории /private/var/mobile/Documents/Dumped/

Iridium

Приложение: Bridge Wallet

Все интуитивно понятно: выбираем приложение → Decrypt Now:

После декрипта видим сообщение о том, что извлеченный .ipa-файл доступен в директории /var/mobile/Documents/wiki.qaq.iridium/Packages:

bagbak

Приложение: Bitkub

Через bagbak приложения дампятся по 'name', а не по 'Application Identifier', поэтому сначала делаем листинг через сам bagbak:

$ bagbak -l

И дампим приложение по имени:

$ bagbak -z Bitkub

Для того, чтобы достать из .ipa исполняемый файл, меняем расширение .ipa-файла на zip, распаковываем, переходим в .app приложения:

$ mv SecureStorev2-resigned.ipa SecureStorev2-resigned.zip
$ unzip SecureStorev2-resigned.zip
$ cd Payload/SecureStorev2.app

Внутри лежит исполняемый файл SecureStorev2, из которого мы дампим классы через class-dump:

$ class-dump SecureStorev2 | tee class_dump_output.txt

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

Когда мы определились с необходимым методом – пришло время загрузить исполняемый файл в дизассемблер.В данной статье мы будем пользоваться Hopper Disassembler.

Открываем Hopper → File → Read Executable to Disassemble:

Выбираем исполняемый файл → Ничего не меняем в лоадере и нажимаем ОК.

В левой панели выбираем поиск по строке и в поиске вводим название метода:

В правой панели подсвечивается интересующая нас область, щелкаем ПКМ → References to "aisdevicejailbr":

В открывшемся окне выбираем наш ViewController → Go:

В правом верхнем тулбаре переключаемся на отображение в виде графа и
видим, что после этого метода выполнение уходит в одну из двух веток в
зависимости от результатов проверки:

Рассмотрим подробнее левую ветвь. По последней строчке exit понимаем,
что если выполнение попадает сюда, то приложение закрывается:

Чтобы это исправить, нам нужно заменить последнюю инструкцию в первом блоке:

tbz выполняет проверку и переход на условную метку loc_1000c560 (если
посмотрите на правую ветвь, то увидите, что это ее обозначение), если
результат проверки – ноль.

Теперь переходим к патчингу. Самый простой способ в данном случае – это поменять инструкцию tbz на противоположную ей, tbnz, тогда выполнение при обнаружении Jailbreak'а будет уходить в правую ветвь вместо левой. Для этого кликаем по строчке с tbz и переключаемся на отображение в hex-режиме:

Видим, что у нас выделены байты, отвечающие за нашу инструкцию:

Идем на https://armconverter.com или любой другой сайт, который конвертирует hex в arm64-инструкции, вводим наши байты, проверяем инструкцию:

Переключаемся в режим обратной конвертации, меняем tbz на tbnz и смотрим результат:

Отличие двух инструкций в последнем байте, меняем значение на 37:

После того как мы внесли изменения, создаем новый исполняемый файл:

File → Produce New Executable:

Выбираем Keep Invalid Signature (нам все равно на
подпись, т.к. устанавливать пропатченное приложение мы будем через
Fliza) → Сохраняем в директории Payload/SecureStorev2.app с именем SecureStorev2

Сжимаем нашу папку Payload в zip и переименовываем в .ipa:

$ zip -r SecureStorev2_no_jb.zip Payload
$ mv SecureStorev2_no_jb.zip SecureStorev2_no_jb.ipa

Переносим .ipa-файл на устройство через scp:

$ scp SecureStorev2_no_jb.ipa root@<iOS-device_ip_addr>:/User/Downloads

Удаляем старую версию приложения и устанавливаем новую через Fliza:

Запускаем и видим, что приложение успешно запускается без обнаружения Jailbreak'a:

SSL-pinning

SSL-pinning – один из способов защиты канала связи между клиентом и сервером, который противостоит атакам типа MITM. Однако, такая защита мешает нам исследовать трафик мобильного приложения, и нам необходимо уметь ее обходить. О технической составляющей SSL-pinning написана великолепная статья нашими коллегами из Swordfish Security, так что вместо того, чтобы повторяться на этот счет, просто рекомендуем прочитать ее, если хотите узнать больше про принцип работы данного способа защиты.

При попытке проксирования траффика приложения на устройстве мы получаем ошибку с текстом "Something went wrong", а в Burp Suite – ошибку TLS-соединения. Делаем вывод, что в рассматриваемом приложении применяется SSL-pinning, и посмотрим, как можно его обойти.

SSL Kill Switch 2

В меню настройки SSL Kill Switch 2 можно попасть из общих настроек устройства через раздел с установленными твиками, управление твиком очень простое: мы отключаем валидацию сертификата для всех приложений. Если хотим исключить какие-то приложения, то прописываем их BundleID в соответствующее поле:

Пробуем открыть интересующую нас страницу и видим, что ошибка исчезла:

В логах устройства можно увидеть, хуки SSL Kill Switch 2:

Objection

Для байпаса SSL-pinning в Objection есть команда # ios sslpinning disable, пробуем ее применить и видим, что результат достигнут:

Ручной патчинг приложения

Снова представим, что простые способы не сработали и попробуем пропатчить приложение руками через Hopper.

Загружаем исполняеымй файл в Hopper и пытаемся найти нужный нам контроллер по ключевым словам ошибки, которую мы получаем:

Находим референсы:

Переходим по первому референсу и ищем еще раз:

Видим, что второй референс привел нас к контроллеру, переходим в режим графов и видим две ветви исполнения:

По строке "Something went wrong" понимаем, что исполнение уходит в
правую ветвь, если проверка на SSL-pinning не пройдена. Соответственно
нам нужно сделать то же самое, что и в примере с Jailbreak detection –
пустить исполнение в другую ветвь с помощью замены инструкции tbz на
tbnz. Меняем значение последнего байта на 37 и сохраняем новый исполняемый файл так же, как и в примере с Jailbreak detection.

После этого подготавливаем .ipa-файл с новым исполняемым файлом, переносим его на устройство, устанавливаем и смотрим на результат:


В этой статье мы познакомились с такими методами защиты в приложениях, как Jailbreak Detection и SSL-pinning, и научились обходить их разными способами. В примерах с Securestorev2 использовались довольно простые способы защиты приложения, которые хорошо разбирать, если вы только начинаете вкатываться в тему безопасности мобильных приложений. Вот еще несколько статей и источников информации начального/среднего уровней, с которыми мы советуем ознакомиться:

Комментарии (3)


  1. vorgovsky
    22.08.2022 16:42
    +3

    Шикарная статья, спасибо ????????????


  1. VVitaly
    24.08.2022 09:02

    Самая главная проблема при наличии jailbreak на устройстве - логика разработчиков ios приложений... :-)
    Казалось бы, ну есть/нашли что он установлен, предупредили пользователя при запуске своего приложения в диалоге что есть определенная "проблема безопасности" и спросили "Хочешь продолжить работу с приложением? Да/Нет." и все.... Пользователь сам решает.
    Но по какой то извращенной логике основное большинство ios приложений тупо при этом перестают работать. И никто не может вразумительно объяснить откуда такая логика извращенная берется... Ну ладно Apple со своим подходом "мы лучше вас знаем что вам нужно!", но сторонние то разработчики должны что-то понимать и быть более лояльны к потенциальным клиентам?


  1. Shaman_RSHU
    25.08.2022 11:27

    Насколько я понял в природе не существует скриптов, способных скачать с AppStore приложение и сконвертировать его в IPA? Только с устройства?