На аудите финтех-приложения под iOS мы упёрлись в трёхслойную jailbreak detection - файловые проверки, sandbox-запись в
/private и анализ загруженных dylib на предмет FridaGadget. Стандартная команда objection explore приводила к крашу за 200 миллисекунд: приложение завершалось до того, как Frida успевала зацепиться за процесс. Liberty Lite тоже мимо - приложение использовало кастомные inline-проверки на C вместо стандартных ObjC-методов. На разбор механики и написание рабочего хука ушло четыре часа, но именно этот кейс показал пропасть между учебными стендами вроде DVIA-2 и тем, что встречается в продакшне. Ниже - пошаговый разбор от подготовки устройства до работающих Frida-скриптов, обходящих конкретные механизмы защиты.Jailbreak bypass в цепочке мобильного пентеста
Обход jailbreak detection - не финальная цель, а входной барьер. Без него динамический анализ iOS приложений мёртв: приложение либо крашится при запуске, либо урезает функциональность до бесполезного состояния, блокируя доступ к критичным API-вызовам.Типичная цепочка пентеста iOS приложений:
- Jailbreak + SSH-доступ - root на устройстве через Palera1n или checkra1n
- Jailbreak detection bypass - обход проверок, чтобы приложение нормально запустилось
- SSL pinning bypass - снятие TLS-пиннинга для перехвата трафика в Burp Suite
- Runtime manipulation - Frida-хуки для перехвата API-вызовов, дамп Keychain, модификация логики
- Статический анализ - декомпиляция бинаря в Hopper или Ghidra, поиск hardcoded secrets
- Эксплуатация - IDOR, business logic flaws, API abuse на бэкенде
По MITRE ATT&CK jailbreak bypass - аналог Virtualization/Sandbox Evasion (T1497): приложение пытается определить модификацию среды выполнения, а атакующий маскирует этот факт. Frida-хуки реализуют Hooking (T0874) для перехвата и подмены возвращаемых значений в runtime. Сам механизм внедрения Frida в процесс - Process Injection (T1055).
По классификации OWASP MASVS, jailbreak detection относится к категории MASVS-RESILIENCE - устойчивость к реверс-инжинирингу. Стандарт описывает root/jailbreak detection, anti-debug и runtime integrity checks как обязательные для приложений с высоким уровнем риска. Задача пентестера - проверить, насколько эти меры устойчивы к реальному атакующему, а не к автоматизированному сканеру.
Подготовка окружения: от jailbreak до Frida
Требования к окружению
| Компонент | Минимум | Рекомендация |
|---|---|---|
| iPhone/iPad | Чип A11 или старше с поддержкой checkra1n/Palera1n | iPhone 8/X на iOS 15.x - 16.x |
| Jailbreak | Palera1n rootful | Palera1n с rootful режимом, Sileo как менеджер пакетов |
| macOS хост | macOS 12+, Homebrew | macOS 13+ |
| RAM хоста | 8 ГБ | 16 ГБ при параллельной работе Burp Suite + Ghidra |
| Frida клиент | 16.7.19 для совместимости с objection | Версия, совпадающая с сервером |
| Frida сервер (iOS) | Та же мажорная версия, что и клиент | 16.7.19 rootful build |
| Python | 3.9+ | 3.11+ |
| USB-кабель | Оригинальный Lightning или USB-C | - |
| Сеть | Online для установки пакетов через Sileo | Offline после настройки для OPSEC |
Альтернатива физическому устройству - Corellium: облачная платформа виртуализации iOS с пре-джейлбрейкнутыми устройствами и встроенной Frida-консолью. Не нужно возиться с физическим jailbreak. Минус - стоимость подписки и невозможность тестирования hardware-специфичных защит (Secure Enclave, биометрия через SEP). На реальных проектах я предпочитаю физику - Corellium хорош для быстрой проверки гипотез, но не заменяет живое устройство.
Установка Frida и проблема совместимости версий
После джейлбрейка первым делом - SSH. В Sileo ставите пакет OpenSSH, порт 22 на устройстве открывается автоматически. Дефолтные креды:mobile:alpine и root:alpine - смените их командой passwd через SSH до подключения к Wi-Fi. Серьёзно, до подключения. Я видел кейсы, когда на устройство заходили извне в первые секунды после подключения к сети.Для подключения через USB (без Wi-Fi, что безопаснее) на macOS нужен
usbmuxd: ставится через brew install usbmuxd, затем проброс порта командой iproxy 2222 22 & и подключение через ssh -p 2222 mobile@localhost.Дальше - Frida-сервер. В Sileo добавляете репозиторий
https://build.frida.re, ставите пакет Frida - сервер запускается автоматически. Проверка: ps aux | grep frida должен показать процесс /usr/sbin/frida-server.И вот тут начинается боль. Текущая версия Frida в Sileo - 17.5.2 (на момент публикации), а objection совместим только с Frida 16.7.19. Несовпадение мажорных версий клиента и сервера приводит к ошибке подключения - молча, без внятного сообщения. Решение - даунгрейд Frida-сервера на устройстве до 16.7.19 через скрипт обновления с GitHub-репозитория Frida (скрипт скачивает нужную версию
.deb-пакета и устанавливает через dpkg). После даунгрейда обязательна перезагрузка устройства и повторная активация jailbreak командой palera1n -f.На хосте macOS клиент ставится через
pip install frida==16.7.19 frida-tools==12.3.0 (версия frida-tools должна соответствовать версии Frida - сверяйте в release notes). Проверка: frida --version должна вернуть 16.7.19. Если версии разъехались хотя бы на минорку - готовьтесь к невнятным ошибкам при подключении.Анатомия jailbreak detection в iOS приложениях
Чтобы обойти защиту, нужно понять, что конкретно она проверяет. По результатам анализа исходного кода iOS Security Suite (разбор опубликован исследователями Appknox) и реального поведения банковских приложений, проверки делятся на три категории.
Файловые проверки и URL-схемы
Самый распространённый и самый слабый метод. Приложение вызываетNSFileManager.fileExistsAtPath: или C-функции fopen()/access() для путей, характерных для джейлбрейкнутого устройства:/Applications/Cydia.app- классический маркер/usr/sbin/sshd- OpenSSH-сервер/bin/bash- нестандартный shell/usr/bin/ssh- SSH-клиент/etc/aptи/private/var/lib/apt/- следы APT-менеджера пакетов
UIApplication.canOpenURL: тестирует доступность sileo://, cydia://, undecimus://. Хотя бы одна доступна - маркер джейлбрейка.По исходному коду iOS Security Suite, метод
performChecks() реализует восемь отдельных проверок:- Check URL Schemes - доступность
sileo://и аналогов - Check Existence Of Suspicious Files -
fileExists(atPath:),fopen,accessв read-only - Check Suspicious Files Can Be Opened -
isReadableFile(atPath:)и write-режим - Check Restricted Directories Writable - попытка записи в
/,/root,/private - Check Fork - sandbox violation через
fork() - Check Symbolic Links - нестандартные symlink'и в системных директориях
- Check DYLD - загруженные библиотеки: FridaGadget, CydiaSubstrate
- Check Suspicious ObjC Classes - обнаружение Shadow (bypass-твик)
amIJailbroken() агрегирует результаты: хотя бы одна проверка не пройдена - возвращается true, устройство считается скомпрометированным. Звучит грозно, но большинство приложений используют от силы три-четыре проверки из восьми.Sandbox-тесты, fork() и системные вызовы
Файловые проверки обходятся просто - хуком наfileExistsAtPath: и подменой ответа. Серьёзнее - sandbox-тесты: приложение пытается создать и удалить файл в директории, которая на стоковом iOS доступна только для чтения (/private, /root). Запись удалась - sandbox нарушен.Вызов
fork() - ещё один индикатор. На стоковом iOS sandbox запрещает создание дочерних процессов. Если fork() возвращает валидный PID вместо ошибки - устройство джейлбрейкнуто. Эту проверку сложнее обойти: fork() - системный вызов, а не ObjC-метод, и для перехвата нужен хук на уровне C-функций.DYLD-анализ: обнаружение Frida и Substrate
Продвинутые приложения лезут в список загруженных динамических библиотек через_dyld_image_count() и _dyld_get_image_name(). В списке ищут строки:FridaGadgetиfrida-agent- FridaCydiaSubstrateиSubstrateLoader- Cydia Substratelibhooker- LibHooker (альтернатива Substrate)
frida-server, её агент появляется в списке dylib - приложение это видит и крашится. Некоторые дополнительно сканируют TCP-порт 27042 (дефолтный порт Frida) или проверяют наличие ObjC-классов, ассоциированных с bypass-твиками.Это прямое обнаружение инструментария пентестера, и стандартные bypass-твики (Liberty Lite, Shadow) его не всегда закрывают: iOS Security Suite в проверке №8 сама детектирует Shadow по имени ObjC-класса. Классическая гонка вооружений.
Обход jailbreak detection: практика с Frida
Objection для быстрого старта в iOS pentest
Objection - фреймворк динамического анализа на базе Frida, который автоматизирует мобильный пентест: обход SSL-пиннинга, дамп Keychain, стандартный jailbreak bypass. Подключение к приложению через USB (после настройкиiproxy):
📚 Часть контента скрыта. Этот материал доступен участникам сообщества с рангом One Level или выше
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме
Результат: метод всегда возвращает
false (0x0) независимо от реального состояния устройства. Приложение продолжает работу как на стоковом iOS.Нюанс, на котором я сам спотыкался: используйте
+ isJailbroken (с плюсом) для class methods и - isJailbroken (с минусом) для instance methods. Перепутаете - хук молча не сработает, Frida не выбросит ошибку, а приложение продолжит крашиться. Сидишь и думаешь, что скрипт не работает, а на деле - не тот префикс. Проверить тип метода можно через перечисление ObjC.classes.JailbreakDetection.$ownMethods.Для хуков C-функций (
fopen, access, fork) синтаксис другой - вместо ObjC-класса используется Module.findExportByName(null, "fork") и аналогичный Interceptor.attach с подменой return value.Работа со Swift-модулями и iOS Security Suite
С Swift ситуация принципиально другая. Swift-методы не экспортируются в ObjC runtime - их имена подвергаются name mangling, и прямой доступ черезObjC.classes невозможен. Для хука нужен точный offset метода в бинаре.Workflow для обхода iOS Security Suite в Swift-приложении (по методологии Appknox):
- Распаковать IPA:
unzip target.ipa -d Payload/ - Найти фреймворк:
Payload/<name>.app/Frameworks/IOSSecuritySuite.framework - Открыть бинарь в radare2:
r2 IOSSecuritySuite, выполнитьaaaдля полного анализа - Найти целевой метод:
afl | grep amIJail- получаем offset методаamIJailbroken - Вычислить runtime-адрес:
Module.getBaseAddress("IOSSecuritySuite")+ offset - Поставить
Interceptor.attachпо вычисленному адресу
flutter_jailbreak_detection (обёртка над iOS Security Suite), достаточно обойти один метод - amIJailbroken(). Flutter-плагин внутри вызывает IOSSecuritySuite.amIJailbroken() и транслирует результат в Dart-слой. Bypass на уровне нативного фреймворка разрывает всю цепочку. Один хук - и Flutter-часть приложения даже не узнает, что устройство джейлбрейкнуто.Отдельная головная боль - приложения, где iOS Security Suite скомпилирована статически (вкомпилирована в основной бинарь, а не как отдельный
.framework). Метод amIJailbroken находится не в отдельном модуле, а в основном исполняемом файле. Поиск offset через radare2 остаётся тем же, но Module.getBaseAddress нужно вызывать для основного бинаря приложения. Мелочь, но при первом столкновении отнимает час на отладку.Когда что применять: decision tree для iOS pentest
| Ситуация | Техника | Инструмент | Время |
|---|---|---|---|
| Стандартные ObjC-проверки | Автоматический bypass | objection ios jailbreak disable | 2-5 мин |
| Кастомный ObjC-класс с известным именем | Ручной хук метода | Frida + Interceptor.attach | 15-30 мин |
| Swift-модуль (iOS Security Suite) | Offset-based хук | radare2 + Frida | 1-2 часа |
Inline C-функции (fork, fopen) | Хук C-экспортов | Frida + Module.findExportByName | 30-60 мин |
| Anti-tampering блокирует runtime хуки | Статический патч бинаря | Hopper/Ghidra + resign через ldid | 2-4 часа |
| Многослойная защита (всё вместе) | Послойный обход | Frida + radare2 + binary patching | 4-8 часов |
Алгоритм выбора:
- Запустите
objection explore- приложение работает? Да - переходите к SSL pinning bypass, jailbreak detection решён. - Нет (краш при запуске) - запустите через spawn:
frida -U -f com.target.app -l bypass.js --no-pause. Скрипт bypass.js содержит хуки из предыдущего раздела. - Frida детектируется - проверьте, не сканирует ли приложение порт 27042. Смените порт: на устройстве остановите
frida-serverи перезапустите с флагомfrida-server -l 0.0.0.0:1337. Альтернатива - внедрение через Frida Gadget (dylib, вкомпилированный в IPA) вместоfrida-server. - Всё ещё крашится - статический анализ бинаря. В дизассемблере найдите условный переход (CBZ/CBNZ в ARM64), отвечающий за ветвление «jailbroken / not jailbroken», и замените на NOP. Resign бинарь через
ldid -Sилиcodesign.
Ограничения техник обхода jailbreak detection
| Техника | Работает против | Не работает против |
|---|---|---|
objection ios jailbreak disable | Стандартные ObjC-проверки, NSFileManager | Кастомные C-функции, Swift, обфускация |
| Frida ObjC hook | Любые ObjC-методы с известным именем класса | Inline C, обфусцированные имена, anti-Frida |
| Frida C-function hook | fopen, access, fork, canOpenURL | Server-side validation, timing-based detection |
| Binary patching (NOP/CBZ) | Любые клиентские проверки | Server-side validation, integrity checks с HMAC |
| Liberty Lite / Shadow / A-Bypass | Массовые файловые проверки | iOS Security Suite (детектирует Shadow), кастомные SDK |
Конкретные сценарии, где стандартные подходы ломаются:
Server-side validation. Приложение отправляет результат jailbreak-проверки на бэкенд, и уже сервер принимает решение о блокировке. Клиентский bypass бесполезен - нужно перехватывать HTTP-запрос через Burp Suite (после обхода SSL pinning) и подменять значение
isJailbroken: true на false в теле запроса. По сути, вся клиентская защита сводится к одному параметру в JSON.Обфускация имён. Коммерческие SDK обфусцируют имена классов и методов. Вместо
isJailbroken - a3x_k9m. Поиск через ObjC.classes по имени не даст результата. Решение - статический анализ в Hopper или Ghidra с трассировкой ветвлений от точки краша назад по call graph. Муторно, но работает.Anti-Frida. Приложения, целенаправленно детектирующие Frida (DYLD-проверка на
frida-agent, сканирование порта 27042, обнаружение Interceptor через integrity checks), требуют модификации самой Frida - пересборки из исходников с изменёнными строковыми литералами и дефолтным портом. Занятие не для слабонервных, но иногда это единственный путь.Timing-based detection. Ряд защитных SDK замеряет время выполнения проверки: если jailbreak-функция отработала аномально быстро (хук мгновенно вернул
false без реального выполнения проверок), приложение трактует это как bypass. Обход - добавление задержки в хук через Thread.sleep(0.1) или выполнение части оригинальной логики перед подменой return value. Хитро, но предсказуемо.Integrity checks. Приложение вычисляет хеш собственного бинаря при запуске и сравнивает с эталоном. Пропатчен бинарь (NOP вместо CBZ) - хеш не совпадает - приложение отказывается работать. Для обхода нужен либо runtime-хук функции проверки хеша, либо пересчёт эталонного значения после патча.
Массовые bypass-твики (Liberty Lite, Shadow, A-Bypass) перехватывают системные API: когда приложение спрашивает «существует ли
/Applications/Cydia.app?», твик подменяет ответ на «нет». Но обновления отстают от защитных SDK. Shadow детектируется самим iOS Security Suite в проверке №8 (Check Suspicious ObjC Classes) - классический пример гонки вооружений, которую исследование jsmon.sh метко назвало «Cat and Mouse game».Заключение.
За последние пару лет jailbreak detection из формальной галочки в чек-листе разработчика превратился в первый серьёзный барьер мобильного пентеста. Банковские и финтех-приложения комбинируют файловый анализ, DYLD-инспекцию, sandbox-тесты и server-side валидацию. По MASVS-RESILIENCE - так и должно быть.
Но вот что я наблюдаю в реальных аудитах: подавляющее большинство приложений по-прежнему полагаются на один-два метода из iOS Security Suite без кастомизации. Bypass занимает 15 минут и десять строк JavaScript. Реально устойчивые реализации - с inline C, обфускацией имён, anti-Frida и server-side подтверждением - встречались мне примерно в трёх из двадцати аудитов за последний год. Остальные семнадцать ломаются стандартным Frida-скриптом с
retval.replace(0x0).Это не значит, что jailbreak detection бесполезен. Это значит, что клиентская защита без серверной валидации - декорация. Пока результат
amIJailbroken() не подтверждается на бэкенде, один Interceptor.attach сводит всю защиту к нулю. Пентестеры, которые понимают эту архитектурную слабость, тратят время не на очередной вариант обхода fileExistsAtPath, а на анализ серверной логики - и именно там находят уязвимости, которые действительно стоят отчёта.
Последнее редактирование модератором: