Статья Пентест Android-приложений: от настройки окружения до обхода root-detection и SSL pinning

Схема пентеста Android на тёмной бумаге с цепочкой атак: декомпиляция APK, инъекция Frida, перехват трафика. Узел обхода root-detection выделен янтарным.


На пентесте e-commerce приложения для маркетплейса стандартный Frida-скрипт с CodeShare отказался обходить SSL pinning - трафик в Burp Suite так и не появился. Приложение использовало OkHttp3 с CertificatePinner плюс кастомную проверку целостности APK при старте. Четыре часа ушло на декомпиляцию в jadx, идентификацию конкретного класса с пиннингом и написание точечного хука - после чего IDOR в платёжном API нашёлся за пятнадцать минут. Ситуация до боли знакомая: на мобильном пентесте 80% времени уходит на подготовку окружения и обход клиентских защит, а не на поиск самих уязвимостей. Ниже - полный путь от чистого эмулятора до перехваченного трафика, включая те случаи, когда стандартный tooling молча отваливается.

Требования к окружению и место в цепочке атаки​

Что нужно до первой команды​

ПараметрМинимумРекомендация
RAM8 ГБ16 ГБ (эмулятор + Burp + jadx одновременно)
CPU4 ядра, VT-x / AMD-V6+ ядер
Диск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 цепочка мобильного пентеста выглядит так:
  1. Recon - декомпиляция APK, извлечение эндпоинтов, ключей, конфигурации (T1082, System Information Discovery)
  2. Initial access к API - обход SSL pinning для перехвата трафика (T1040, Network Sniffing) и установка CA-сертификата прокси на устройство (T1553.004, Install Root Certificate)
  3. Тестирование API - IDOR, broken authentication, mass assignment - то, ради чего обходились клиентские защиты
  4. Сбор данных - токены, shared preferences, SQLite-базы с устройства (T1005, Data from Local System)
Без обхода root-detection и SSL pinning вы застрянете на шаге 2. По классификации OWASP MASVS, root-detection и anti-tampering относятся к категории MASVS-RESILIENCE (защита от реверс-инжиниринга), SSL pinning - к MASVS-NETWORK. Эти меры усложняют тестирование, но серверные уязвимости никуда не деваются. Серверная сторона остаётся дырявой вне зависимости от того, проверяет ли клиент наличие su-бинаря.

Настройка эмулятора, 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  # видите список процессов - сервер работает
На физическом устройстве с Magisk замените 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-хуки тут бесполезны
Root-detection - типичные проверки (по данным Appknox и набора secfb/Frida-Android-SSL-Pinning-Script):
  • Наличие 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)
Если ProGuard/R8 обфусцировал имена классов (T1027, Obfuscated Files or Information), поиск по строковым литералам (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 - возврат false
  • PackageManager.getPackageInfo() для root-пакетов - выброс NameNotFoundException
  • SystemProperties.get() - подмена ro.secure=1, ro.debuggable=0
  • Runtime.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 + скриптObjectionXposed (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 есть задачи, где клиентские контроли нужно пройти прежде чем добраться до уязвимости.
 
Мы в соцсетях:

Взломай свой первый сервер и прокачай скилл — Начни игру на HackerLab

Похожие темы

🚀 Первый раз на Codeby?
Гайд для новичков: что делать в первые 15 минут, ключевые разделы, правила
Начать здесь →
🔴 Свежие CVE, 0-day и инциденты
То, о чём ChatGPT ещё не знает — обсуждаем в реальном времени
Threat Intel →
💼 Вакансии и заказы в ИБ
Pentest, SOC, DevSecOps, bug bounty — работа и проекты от проверенных компаний
Карьера в ИБ →

HackerLab