На пентесте e-commerce приложения для маркетплейса стандартный Frida-скрипт с CodeShare отказался обходить SSL pinning - трафик в Burp Suite так и не появился. Приложение использовало OkHttp3 с
CertificatePinner плюс кастомную проверку целостности APK при старте. Четыре часа ушло на декомпиляцию в jadx, идентификацию конкретного класса с пиннингом и написание точечного хука - после чего IDOR в платёжном API нашёлся за пятнадцать минут. Ситуация до боли знакомая: на мобильном пентесте 80% времени уходит на подготовку окружения и обход клиентских защит, а не на поиск самих уязвимостей. Ниже - полный путь от чистого эмулятора до перехваченного трафика, включая те случаи, когда стандартный tooling молча отваливается.Требования к окружению и место в цепочке атаки
Что нужно до первой команды
| Параметр | Минимум | Рекомендация |
|---|---|---|
| RAM | 8 ГБ | 16 ГБ (эмулятор + Burp + jadx одновременно) |
| CPU | 4 ядра, VT-x / AMD-V | 6+ ядер |
| Диск | 30 ГБ свободных | SSD, 50+ ГБ |
| ОС хоста | Linux (Kali / Ubuntu 22.04+), macOS 13+, Windows 10+ | Linux - меньше проблем с ADB |
| Android | Эмулятор Android Studio API 28–33 или Pixel с unlocked bootloader | Эмулятор на старте; физический девайс при эмулятор-детекции |
Софт: Python 3.8+,
frida-tools и frida (обязательно одинаковая мажорная версия - несовпадение ломает spawn), ADB из platform-tools, Burp Suite Community или Pro, jadx (проект активно поддерживается, релизы на GitHub регулярные), apktool. Опционально: objection через pip install objection (sensepost/objection, поддерживается), MobSF для автоматизации статического анализа.Зачем обходить защиты: место в kill chain
APK - клиентская обёртка, цель - серверное API. В терминах MITRE ATT&CK цепочка мобильного пентеста выглядит так:- Recon - декомпиляция APK, извлечение эндпоинтов, ключей, конфигурации (T1082, System Information Discovery)
- Initial access к API - обход SSL pinning для перехвата трафика (T1040, Network Sniffing) и установка CA-сертификата прокси на устройство (T1553.004, Install Root Certificate)
- Тестирование API - IDOR, broken authentication, mass assignment - то, ради чего обходились клиентские защиты
- Сбор данных - токены, shared preferences, SQLite-базы с устройства (T1005, Data from Local System)
Настройка эмулятора, Frida и Burp Suite для android pentest
Эмулятор или физическое устройство
В Android Studio выбирайте образ с Google APIs, но без Google Play - такие образы позволяют получить root черезadb root. Образы с надписью «Google Play» - production-сборки, root недоступен в принципе. Это ловушка, в которую попадают все хотя бы раз.Если целевое приложение детектирует эмулятор (проверяет
ro.hardware, ro.product.model, наличие QEMU-артефактов), переходите на физический девайс. Pixel-линейка с unlocked bootloader и Magisk - отраслевой стандарт. На практике я использую оба варианта: эмулятор для первичной разведки и статического анализа, физическое устройство - когда эмулятор-детекция мешает динамике.[Применимо: оба подхода. На эмуляторе root доступен из коробки; физический девайс требует разблокированного загрузчика и Magisk.]
Развёртывание Frida-сервера
Определите архитектуру устройства черезadb shell getprop ro.product.cpu.abi - вернёт x86_64 для эмулятора или arm64-v8a для большинства физических устройств. Скачайте frida-server соответствующей архитектуры с GitHub Releases. Критически важно: версия сервера обязана совпадать с версией frida-tools на хосте. Несовпадение - причина ошибки «Failed to spawn» в каждом втором обращении на форумах. Не повторяйте чужих ошибок.
Bash:
frida --version # запомнить версию
# Загрузить frida-server той же версии под нужную архитектуру
adb push frida-server /data/local/tmp/frida-server
adb shell chmod 755 /data/local/tmp/frida-server
adb root # на эмуляторе; для Magisk: adb shell su -c "..."
adb shell "nohup /data/local/tmp/frida-server >/dev/null 2>&1 &"
frida-ps -U # видите список процессов - сервер работает
adb root на adb shell su -c "/data/local/tmp/frida-server &" - root через Magisk работает только через su.Сертификат Burp Suite в системном хранилище
На Android 7+ пользовательские CA-сертификаты по умолчанию не доверяются приложениями - даже без SSL pinning. Сертификат нужен в/system/etc/security/cacerts/. Последовательность: экспортируйте DER из Burp, конвертируйте через openssl x509 -inform DER -in burp.der -out burp.pem, получите хеш командой openssl x509 -inform PEM -subject_hash_old -noout -in burp.pem, переименуйте файл в <hash>.0 и скопируйте на устройство. На эмуляторе: запустите его с флагом -writable-system, выполните adb root, затем adb disable-verity, adb reboot, adb root && adb remount, и только после этого adb push <hash>.0 /system/etc/security/cacerts/. На физическом устройстве потребуется отключение dm-verity.На Magisk-устройствах проще: установите сертификат штатно через настройки безопасности, затем модуль MagiskTrustUserCerts переместит его в системный раздел при перезагрузке. Три клика вместо десяти команд.
Настройка прокси:
adb shell settings put global http_proxy <IP_хоста>:8080. В Burp убедитесь, что Proxy Listener принимает соединения на всех интерфейсах (All interfaces). Сброс после тестирования: adb shell settings delete global http_proxy.Анализ APK перед обходом защит
Перед запуском скриптов вслепую откройте APK в jadx и определите тип реализации защит - от этого зависит выбор метода обхода. Стянуть APK с устройства:adb shell pm path <package> и adb pull.SSL pinning - ключевые паттерны в декомпилированном коде:
- OkHttp: класс
CertificatePinner, строки видаsha256/...- хеши сертификатов. Реализация черезCertificatePinner.Builder().add(hostname, "sha256/...")- самый распространённый вариант в e-commerce и финтех-приложениях - Стандартный Android:
TrustManagerFactory, кастомныйX509TrustManagerс переопределённымcheckServerTrusted() - Конфигурационный: файл
res/xml/network_security_config.xmlс блоком<pin-set>- самый простой случай, достаточно удалить конфиг и пересобрать APK - TrustKit: зависимость
com.datatheorem.android.trustkit- специфический способ хукинга - Flutter:
ssl_pinning_plugin,http_certificate_pinningв assets - стандартные Java-хуки тут бесполезны
- Наличие su-бинарей:
/sbin/su,/system/bin/su,/system/xbin/su,/data/local/su - Установленные пакеты:
com.topjohnwu.magisk,eu.chainfire.supersu,com.noshufou.android.su,com.koushikdutta.superuser - Системные свойства:
ro.secure,ro.debuggable - Вызов
Runtime.exec("which su")илиRuntime.exec("id") - Доступ на запись в защищённые директории (
/system,/data)
su, Superuser, CertificatePinner, sha256) через grep по выводу jadx работает надёжнее навигации по дереву пакетов. Копаться в обфусцированных именах - пустая трата времени, а строки никто не шифрует (ну, почти никто).Обход root-detection Android с Frida и Objection
Финтех-приложения, банковские клиенты и приложения с DRM отказываются запускаться на рутованных устройствах. По классификации OWASP MASVS-RESILIENCE сюда входят anti-tampering, root/jailbreak detection, anti-debug (T1622, Debugger Evasion) и runtime integrity. Три метода по нарастающей сложности.Уровень 1: Objection - 30 секунд
Запуститеobjection -g <package_name> explore, в консоли введите android root disable. Objection перехватывает File.exists() для стандартных su-путей и подменяет возвращаемое значение на false. По практике с AndroGoat и типовыми приложениями - работает для базовых проверок.[Применимо: приложения с базовой Java-детекцией через проверку файлов и пакетов. Не работает против SafetyNet / Play Integrity API, нативных проверок через JNI.]
Уровень 2: Frida-скрипт - 5 минут
Когда Objection не справляется, берём скрипт с более широким покрытием. Набор frida-android-rootandpinning с GitHub (secfb/Frida-Android-SSL-Pinning-Script, 6 вариантов скриптов разной глубины) перехватывает:File.exists()иFile.canRead()для путей su и busybox - возврат falsePackageManager.getPackageInfo()для root-пакетов - выбросNameNotFoundExceptionSystemProperties.get()- подменаro.secure=1,ro.debuggable=0Runtime.exec()- нейтрализация командwhich su,id,mount
frida -U -f <package_name> -l root_bypass.js --no-pause. Флаг -f запускает приложение в spawn-режиме - критично, если root-проверка срабатывает в onCreate() главного Activity. Без spawn-режима вы просто не успеете подцепиться.Уровень 3: Magisk DenyList или smali-патчинг
Некоторые приложения выполняют root-проверку в нативном коде через .so-библиотеки - Java-хуки их не затрагивают. На физическом устройстве с Magisk 24+ включите Zygisk и добавьте приложение в DenyList: Magisk скроет факт root на уровне mount namespace. На эмуляторе DenyList недоступен - придётся декомпилировать APK командойapktool d app.apk, найти smali-код проверки, заменить const/4 v0, 0x1 (return true / «устройство рутовано») на const/4 v0, 0x0 (return false), пересобрать через apktool b app и подписать через apksigner.[Ограничение: smali-патчинг ломает оригинальную подпись APK. Если приложение дополнительно проверяет signature - потребуется обход и этой проверки. На практике это ещё один smali-патч или Frida-хук на
PackageInfo.signatures. Каждая защита - ещё один слой, который нужно снять.]SSL pinning bypass Android: от стандартных команд до кастомных Frida-хуков
SSL pinning (MASVS-NETWORK) привязывает приложение к конкретному хешу сертификата или публичного ключа сервера. Даже с установленным CA Burp Suite в системном хранилище трафик не перехватывается - приложение отвергает «чужой» сертификат при TLS-хендшейке. Выбор метода обхода определяется реализацией, которую вы нашли на этапе статического анализа.
📚 Часть контента скрыта. Этот материал доступен участникам сообщества с рангом One Level или выше
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме
Идентификация кастомного пиннинга
Когда универсальные скрипты не срабатывают, нужно найти конкретный метод, реализующий проверку. Командаfrida-trace -U -f <package_name> -j '[I]![/I]certificate*' трассирует все методы со словом «certificate» во всех классах в реальном времени. Запустите приложение, дождитесь TLS-хендшейка - в выводе появится класс и метод, который вызывается при проверке. Дальше пишете точечный хук, возвращающий true или пустое значение для именно этого метода.Для Flutter-приложений стандартные Java-хуки бесполезны - Dart VM работает отдельно от JVM. Набор скриптов из secfb/Frida-Android-SSL-Pinning-Script включает варианты для
ssl_pinning_plugin и http_certificate_pinning, но каждая мажорная версия Flutter может сломать смещения в скомпилированном коде - скрипт требует проверки под конкретную версию приложения. Flutter-приложения - отдельная головная боль, и готового универсального решения тут нет.Ограничения: что детектирует защита и когда менять подход
Frida-детекция на стороне приложения
Обход root-detection и SSL pinning - не бесплатная операция. Приложения с серьёзной защитой детектируют само присутствие инструментов:- Порт 27042 - дефолтный порт frida-server. Приложение подключается к localhost:27042 и проверяет ответ. Обход: запуск сервера на нестандартном порту через
frida-server -l 127.0.0.1:1337, затем на хостеadb forward tcp:1337 tcp:1337и подключениеfrida -H 127.0.0.1:1337 -f <package> - Frida-agent в памяти - сканирование
/proc/self/mapsна наличие строкиfrida-agent. Обход сложнее: требуется модифицированная сборка Frida или инъекция до инициализации защитного SDK - Файловая система - проверка наличия
frida-serverв/data/local/tmp/. Обход: переименуйте бинарь при загрузке на устройство (казалось бы очевидно, но забывают регулярно)
Google Play Integrity API и аппаратный attestation
Google Play Integrity API (замена SafetyNet) выполняет серверную верификацию целостности устройства. Ни Frida, ни Magisk Hide не обманут серверную проверку при активных Google-сервисах. Парадокс: на эмуляторе без Google Play этот механизм отсутствует - что упрощает тестирование.Приложения с сертификацией PCI DSS (платёжные системы) могут использовать аппаратный attestation через TEE (Trusted Execution Environment), который не обходится программными средствами. Тут уже чисто аппаратная история.
Runtime-protection SDK: Promon, DexGuard, Digital.ai
Приложения, защищённые коммерческими SDK (Promon SHIELD, GuardSquare DexGuard, Digital.ai / бывший Arxan), имеют многослойную runtime-защиту: детекция хуков на нативном уровне, integrity-проверки DEX-файлов, anti-debug через ptrace. Стандартные Frida-скрипты не работают - требуется реверс конкретной версии SDK защиты, что выходит за рамки стандартного bug bounty workflow. На одном проекте мы потратили два дня только на DexGuard, прежде чем добрались до API. Иногда проще договориться с заказчиком о тестовой сборке без защит.Frida vs Objection vs Xposed: выбор под задачу
| Критерий | Frida + скрипт | Objection | Xposed (LSPosed) |
|---|---|---|---|
| Требует root | Да | Да (использует Frida) | Да (через Magisk) |
| Гибкость хуков | Максимальная | Ограничена встроенным набором | Высокая, но нужен Java-модуль |
| Скорость старта | Средняя | Высокая - одна команда | Низкая - компиляция модуля |
| Обход кастомных защит | Да | Часто нет | Да |
| Детектируемость | Высокая (порт 27042, agent в памяти) | Высокая (те же артефакты Frida) | Средняя (нет сетевого порта) |
| Сценарий | Bug bounty, пентест, grey box | Быстрая проверка стандартных защит | Долгосрочный анализ, скрытность |
| Статус проекта | Активно поддерживается, ежемесячные релизы | Поддерживается (sensepost/objection) | LSPosed - активен; Xposed Classic - заброшен |
Рекомендация: начинайте с Objection. Не сработало - Frida-скрипт. Приложение детектирует Frida - Xposed/LSPosed (нет характерного сетевого порта и agent-строки в памяти). Каждый следующий уровень требует больше времени на настройку, но покрывает больше сценариев.
[Применимо: внешний пентест и bug bounty - Frida/Objection достаточно в 90% случаев. Internal assessment с многослойной защитой - может потребоваться Xposed или patching.]
Индустрия мобильной безопасности застряла в гонке вооружений, которая не решает реальную проблему. Разработчики интегрируют runtime-protection SDK стоимостью десятки тысяч долларов в год. Пентестер тратит от часа до дня на обход. А серверное API за этой защитой содержит те же IDOR, broken auth и mass assignment, что и десять лет назад. Из нескольких десятков мобильных пентестов за последние два года ни одна критическая уязвимость в моей выборке не оказалась связана с клиентской стороной - все были в API. Root-detection и SSL pinning защищают не от атакующего, а от ленивого атакующего. Тот, кто владеет Frida, пройдёт любой клиентский контроль - вопрос во времени, не в возможности. Серверная валидация, rate limiting, аномалия-детекция на API gateway - то, что останавливает реальные атаки. Но для этого нужно инвестировать в бэкенд, а не в обфускацию клиента. Если хочется собрать полную цепочку от обхода мобильных защит до эксплуатации API на стенде - на HackerLab.pro есть задачи, где клиентские контроли нужно пройти прежде чем добраться до уязвимости.