Обход средств защиты в iOS-приложениях

058e30a9ba39e9e51bcff06323abb167.jpg

В прошлой статье мы рассмотрели базовые уязвимости и способы их обнаружения. Но что делать, если в приложении используются дополнительные средства защиты (например, 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 можно попасть из общих настроек устройства через раздел с установленными твиками:

94d376de390a969b455fb21b5c3c02e3.png

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

61b8b580921f9e824791d3eddf6df969.png

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

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

5fc376b457f9467b708158f11d7b3073.png

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

4b2c01228354c80c7468e2b9a8552a26.png

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

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

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

a482801639689535a91db01d85fe9347.png

Frida

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

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

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

bb1cac5d2bba7050e3063a1a845eecca.png

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

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

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

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

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

Hidden text

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

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

frida-ios-dump

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

python dump.py -H  -p 22 

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

a393f90bf02690c155740e6d1ac73286.png

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

cd51f6472f02e3141c760a8477fe6e9b.png

Clutch

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

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

$ Clutch -d  
5544bee827ba13a33c11948e54d4ecc9.png

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

b6c80559b593859722b6586d78ae9d86.png

Iridium

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

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

8a21c97f873e69086f2877a1f2e0c882.pnga904bbf8b45ec957bdb92354477cbad5.png

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

932658d53975f35da50a093e93a07a0d.png

bagbak

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

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

$ bagbak -l
55dc1595aec984fb1edec829a946bc44.png

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

$ bagbak -z Bitkub
eb37a325ccbd7ad401cadbec7b0de8f5.png

Для того, чтобы достать из .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, который возвращает булево значение — с высокой вероятностью это именно то, что нам нужно:

ba8bd971b17058af2f913130aa5f4cfd.png

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

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

0af9b23f8f310af8f9caf7b6b0d273ee.png

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

3ccb8d46454c3f33829c4d3aa9280ad1.png

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

b4dbad15303c2fad1bea83f70678ed45.png

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

0509c1993aded308feab8e52e986a146.png

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

3de47f6e5a771f17ac652e67dc7fd1fa.png

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

aeddaad818660b968ea525cb4022710a.png

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

739d30d1f4609cea6dee91131406ba40.png

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

81fdc07e0f216ebf4c2c1e05ee744ce7.png

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

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

3524cc5351376e854b3bcafce106eef5.png

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

49d48347a62d613985575cf11aabad02.png

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

a6f4da2854ab7095dfb50db7ceeba736.png

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

a77838fba7b8b49f1ae3ab8dce4a9717.png

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

5e694b959035f77152c7d21854d6142b.png

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

File → Produce New Executable:

622eb134c8c905f07d0fd7843faa1453.png

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

790226d48da07a592815dcd741b8811c.png

Сжимаем нашу папку 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@:/User/Downloads

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

484de44053fbb4b10022b381b2a2af9c.png

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

3dbf4225476883055d2a3a916490948c.png

SSL-pinning

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

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

ae682c05b7e4a32af96d94e6d7478731.png

SSL Kill Switch 2

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

1e5865802c0a537a5a5d447baca88120.png

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

b5fecaee67e6053c915e9c9e38af35c6.png

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

53d3c8f4d986328cce531750ee70c17f.png

Objection

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

902a4422ea79635eec229d4ccf448b80.png

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

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

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

5b25c94b67d3b960870fc7a530880ee1.png

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

645c66d5e1828df8b6c109f7f696de7d.png870f47eb30f83387d5c43dc9a250bbba.png

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

4868aca392995c5ec55d6356709be7b6.png07e363e65b885221c34b6df819390a0b.png

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

bb4293a27af5086942f2e3a4400eb822.png

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

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

f63a0c4c2f9fc5e53bd68d9add5e614e.png

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

© Habrahabr.ru