Зачем еще одна статья?
Задача перехвата трафика android приложений довольно хорошо описана на куче языков и даже не нужно уметь гуглить чтобы найти информацию о том, как настроить прокси и посмотреть заветные запросы. Даже набившая уже всем оскомину тема “как отломать ssl pinning” была множество раз разжевана и надо быть по пояс странным чтобы в этом не разобраться.
…когда ты слишком долго в пути, когда тебя обуревает жадность, приходит черный пес чтобы отобрать у тебя все.
Черный пес (1998)
Да… потом появляется то самое приложение, которое вопреки всем настройкам не хочет работать через прокси. Или через прокси проходит только часть трафика. В такой ситуации лучше не начинать нажимать все подряд, чтобы не увеличивать энтропию происходящего, а подойти к вопросу системно и последовательно попробовать разные методы для решения этой проблемы.
Базовая настройка
Начать хотелось бы с базовой настройки, которая работает у меня, чтобы читателю был понятен контекст происходящего. А начинающие специалисты возможно откроют для себя что-то новое ;)
этот кусок фактически повторяет мою статью из Telegraph, куда я решил больше ничего не постить. Если уже читали, то этот блок можно пропустить.
Покажу на примере BurpSuite, но эта инструкция применима к любой проксе. Предусловия: вы умеете настраивать прокси на устройстве и у вас установлен Magisk.
Начнем с добавления системного сертификата на устройство. Зачем вообще переноситcert.cer сертификат из пользовательских в системные? Ну во-первых это удобно. В этом случае если в приложении нет пиннинга, то перехват трафика будет работать сразу из коробки и без проблем, т.к. приложения по умолчанию доверяют системному хранилищу. А во-вторых вы избавитесь от дурацкой плашки, говорящей о том, что ваш трафик может быть перехвачен системным администратором.
Для начала включаем глобальный прокси на всю систему, чтобы не ковыряться с настройками Wi-Fi. Это делается простой adb
командой:
$ adb shell settings put global http_proxy <you-host-ip>:<you-proxy-port>
$ adb shell settings put global http_proxy :0
Если вам способ не зашел, то все еще легально настраивать прокси на уровне Wi-Fi сети.
Вернемся к сертификатам. Когда прокси уже настроен, то установка системного сертификата сводится к шести простым шагам:
- Зайти на адрес http://burpsuite
- Там нажать CA Certificate и скачать его на девайс
- Переименовать
cert.der
->cert.cer
- Settings -> Security -> Encryption & credentials -> Install a certificate -> CA certificate -> Install anyway и выбрать
cert.cer
/data/misc/user/0/cacerts-added
под именем вида9a5ba575.0
[✋Этот пункт устарел! Временное решение описано здесь✋]5. Зайти в MagiskManager и поставить модуль Move Certificates (легко найти поиском)
/system/etc/security/cacerts
(удобно смотреть по дате через ls -la
например)
На этом базовая настройка закончена и можно переходить к решению проблем, когда описанный выше сетап почему-то перестает работать
Когда ничего не работает…
Проблем, из-за которых трафик может не ходить через проксю довольно много. Часть их них относится к самому приложению и тем технологиям на которых оно сделано, другая часть возникает из-за глюков операционной системы смартфона или хостовой машины. А еще бывают космические аномалии, луна в Козероге, шумы в портах и вообще три часа ночи уже спать иди…
Важная информация: Не рекомендую пробовать все приведенные способы сразу без отката к изначальному состоянию. Это может вызвать дополнительные проблемы и можно во-первых сломать то, что уже работало или просто потратить время не придя к решению. Поэтому следуем первому правилу хорошего devops-а - небольшое изменение, проверка, откат, следующее изменение.
Проверить работает ли HTTP трафик (который без TLS)
Очень может быть что сертификаты не встали правильно или приложение как-то особенно хитро гоняет трафик по HTTPS, поэтому нужно убедиться, что прокси вообще работает. Для этого нужно открыть любой сайт по HTTP в браузере. Например http://neverssl.com
на котором намеренно отключена настройка Strict Transport Security (HSTS) и трафик этого сайта точно дожен отобразиться в проксе.
Если трафика не видно, то в случае с Burp-ом можно проверить, что отключен перехват трафика (Intercept is off)
SSL pinning aka Public Key Pinning aka Certificate Pinning
Самая безобидная и понятная проблема из всех. Решается хуками или правками в байт-коде приложения. Если пропустили ссылки в начале статьи, то про борьбу с пиннингом можно посмотреть здесь:
А про самое явление здесьТакже можно попробовать вот эти способы:
- В APKLab есть опция пересборки приложения с отключением пиннинга
- Похожая опция есть в Objection:
android sslpinning disable
- В Xposed под это есть модули: SSLUnpinning и JustTrustMe
- Скрипты для Frida: один, два, три, четыре, пять, шесть, семь и обязательно напишите свой ;)
UPD 21.02.2023: Еще один довольно мощный скрипт. Умеет в динамический патчинг.
Если досталось приложение на Xamarin/Unity, то придется разбираться в коде и патчить. Начать этот путь лучше всего с ILSpy и fridax. А вот с Flutter-ом все несколько проще. Нужно использовать reFlutter, который патчит ssl_crypto_x509_session_verify_cert_chain
, что и позволяет обойти некоторые реализации пиннинга. Чуть больше подробностей тут
Подборка статей про обход ssl pinning
- It’s all about Bypassing Android SSL Pinning and Intercepting Proxy Unaware applications
- Держи свой трафик в тайне. SSL Pinning — ещё раз о том же самом
- Универсальный перехват. Как обойти SSLPinning раз и навсегда и читать трафик любого приложения
Проверить, что прокси поднят на внешнем интерфейсе
По умолчанию Burp Suite поднимает прокси на 127.0.0.1
, а значит достучаться до этого адреса со смартфона не выйдет. Нужно поднять его на внешнем интерфейсе, или сразу на всех интерфейсах. Сделать это можно в настройках прокси нажав кнопку Edit
Проверить, что прокси доступен по сети
Если в системе уже включен прокси (глобальный или на уровне Wi-Fi), то его нужно отключить. После этого открыть браузер и зайти на какой-нибудь сайт, чтобы проверить, что прокси отключен. После этого нужно перейти по адресу http://<your-host-ip>:<proxy-port>
. Вы должны увидеть страницу приветствия Burp-а. Теперь нужно снова включить прокси как было описано ранее и проверить доступен ли адрес http://burpsuite
.
Если доступа нет, то можно попробовать сделать следующее:
- Подключиться к другой Wi-Fi сети. Лучше всего сделать гостевую и выключить там все механизмы безопасности. Задача этого этапа понять где проблема. Продолжать работу в такой сети не нужно =)
- Поднять прокси на собственном сервере доступном по сети Интернет. Можно купить VDS или взять годовой бесплатный EC2 на амазоне
- Провести ARP-спуфинг чтобы смартфон начал считать роутером ваш компьютер и все операции делал через него.
- Проверить настройки фаервола на хостовой машине, возможно там запрещены какие-то порты и/или адреса. Универсальных рекомендаций под конкретные ОС нет. Нужно гуглить.
- Проверить настройки фаервола на смартфоне. Вы могли их сделать когда-то давно и забыть об этом. Для Android это чаще всего
iptables
. Подробности тут. - Завернуть трафик через USB с помощью
adb
- В качестве ip адреса прокси на смартфоне указать
127.0.0.1
и порт8080
- Подключить смартфон к комьпьютеру и убедиться, что он виден в выводе
adb devices
- На хостовой машине выполнить команду
adb reverse tcp:8080 tcp:8080
, которая перенаправит трафик с порта8080
на смартфоне на порт8080
на хосте. Конечно же прокси должен слушать этот же порт - Открыть браузер на смартфоне и проверить доступен ли адрес
http://127.0.0.1:8080/
- В качестве ip адреса прокси на смартфоне указать
Проверить установленный ранее сертификат
Еще раз убедиться, что на устройстве установлен правильный сертификат. Идем в Settings -> Security -> Encryption & Credentials -> Trusted Credentials -> System и ищем сертификат PortSwigger, который должен быть активным
Убедиться, что установленный сертификат не протух
Попробовать открыть любой HTTPS сайт в браузере и если вы видите ошибку ERR_CERT_VALIDITY_TOO_LONG
, то нужно обнулиться и повторить установку свежего сертификата.
Приложение может игнорировать настройки прокси
Нативные Android приложения обычно используют стандартные библиотеки, которые работают с системными настройками прокси и чаще всего не вызывают проблем. Но бывают весьма одаренные разработчики и разные замечательные технологии, которые используют свои библиотеки и просто игнорируют системные настройки на любом уровне. Обычно это приложения на Xamarin, Unity и Flutter, но изредка бывают и вполне себе нативные приложения которые могут например использовать библиотеку на C++/Go/Rust/etc в качестве ядра для UI-ной логики на Android и iOS. Такие библиотеки могут иметь свой сетевой стек и всякую дополнительную логику вокруг него.
Вот некоторые маркеры, по которым можно понять использует ли приложение всякие экзотические технологии или нет:
appdir
- директория куда вы распаковали приложение
- Flutter:
appdir/lib/<arch>/libflutter.so
- Xamarin:
appdir/lib/<arch>/libmono*.so
appdir/assemblies/Mono.Android.dll
appdir/xamarin/
appdir/java/md5*/
- Вызовы вида
Runtime.register("My.Project.Android.Clicklistener, My.Project.Android", .Clicklistenerclass, __md_methods);
иTypeManager.Activate("...", this, new Object[]{str, context})
в коде
- Unity:
appdir/lib/<arch>/libunity.so
- Qt:
appdir/assets/.../Qt
,appdir/assets/.../QtTest
,appdir/assets/.../QtWebView
и т.п.- Мета-информация в манифесте
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
<meta-data android:name="android.app.use_local_qt_libs" android:value="1" /> <meta-data android:name="android.app.libs_prefix" android:value="/data/local/tmp/qt/" /> <meta-data android:name="android.app.load_local_libs" android:value="" /> <meta-data android:name="android.app.load_local_jars" android:value="jar/QtAndroid.jar:jar/QtAndroidBearer.jar:jar/QtPositioning.jar:jar/QtMultimedia.jar:jar/QtAndroidExtras.jar:jar/QtAndroidWebView.jar" /> <meta-data android:name="android.app.static_init_classes" android:value="org.qtproject.qt5.android.positioning.QtPositioning:org.qtproject.qt5.android.multimedia.QtMultimediaUtils" /> <meta-data
- Go Mobile:
appdir/META-INF/MANIFEST.MF
иappdir/META-INF/CERT.SF
могут содержать строкуCreated-By: 1.0 (Go)
- activity наследуются от
android.app.NativeActivity
- В коде встречаются логи с тегом “Go”:
Log.e("Go", "loadLibrary: no manifest metadata found");
Можно встретить и более экзотические вещи, которые может быть не так просто загнать под прокси. Но в общем случае бороться с этим всем можно так:
- Установить ProxyDroid или HTTP Proxy Client которые умеют заворачивать на проксю трафик конкретного приложения.
- Завернуть трафик на проксю самостоятельно через
iptables
(предварительно нужно понять какие порты использует приложение, ниже пример для80
/443
):1 2 3 4 5
iptables -t nat -F iptables -t nat -A OUTPUT -p tcp --dport 80 -j DNAT --to-destination <you-host-ip>:<your-proxy-port> iptables -t nat -A OUTPUT -p tcp --dport 443 -j DNAT --to-destination <you-host-ip>:<your-proxy-port> iptables -t nat -A POSTROUTING -p tcp --dport 80 -j MASQUERADE iptables -t nat -A POSTROUTING -p tcp --dport 443 -j MASQUERADE
- Если приложение на Flutter, то использовать reFlutter:
$ pip3 install reflutter $ reflutter <your-app>.apk Please enter your Burp Suite IP: <input_ip> SnapshotHash: 8ee4ef7a67df9845fba331734198a953 The resulting apk file: ./release.RE.apk Please sign the apk file Configure Burp Suite proxy server to listen on *:8083 Proxy Tab -> Options -> Proxy Listeners -> Edit -> Binding Tab Then enable invisible proxying in Request Handling Tab Support Invisible Proxying -> true
Все вышеописанное требует установки флага “Support invisible proxying”, который предназначен специально для таких случаев. Он находится в Proxy -> Options -> активная прокся -> Edit -> Request Handling -> Support invisible proxying
Проверить не использует ли приложение нестандартный порт
Приложение вполне может использовать какие-то нестандартные порты для общения с сервером. Там может быть все, что угодно, особенно если это обращение к каким-то тестовым стендам или приватному API. Эта информация пригодится для ручной настройки iptables
, которая была в предыдущем разделе. Узнать про нестандартные порты можно путем статического анализа, покопавшись в декомпилированном и/или дизассемблированном коде приложения или путем динамического анализа с помощью tcpdump
.
Его можно запустить прямо на смартфоне (нужен root) командой
tcpdump -i wlan0 -n -s0 -v
после чего открыть приложение и как-то с ним повзаимодействовать чтобы пошел трафик. Соединений может быть довольно много, поэтому лучше предварительно закрыть все приложения и убедиться что с сетью ничего в данный момент не работает.
Для удобства, можно записать весь трафик в pcap файл командой
tcpdump -i wlan0 -n -s0 -w /sdcard/output.pcap
и открыть этот файл на хостовой машине в WireShark
Когда нестандартный порт идентифицирован, то завернуть с него трафик можно с помощью adb reverse
или iptables
, как было показано выше.
Но вместе с нестандартным портом может прийти нестандартный протокол. А большинство проксей, и Burp в том числе, понимают только HTTP. В случае с Burp-ом может помочь расширение NoPE Proxy (статья про него), а вот для всех остальных придется или искать специализированный прокси под нужный вам протокол или использовать тот же WireShark и разбирать наполовину сырой трафик.
Убедиться, что нет ограничений при подключении к Wi-Fi
Иногда, при подключении к Wi-Fi сетям, это подключение происходит с ограничениями. В частности само подключение к Wi-Fi может быть стабильным, но подключение к интернету - нет. Явление носит спорадический характер и может исправиться автоматически после нескольких секунд прошедших с момента подключения к сети или показать вот такое окно:
В этом диалоге нужно нажать “yes” и все заработает. Но такой красивый сценарий бывает не всегда. Иногда это окно не появляется, а ограничения при этом остаются. Вот несколько способов как с этим бороться:
Пути к настройкам отличаются на разных версиях Android. Проще искать их через Search settings
- Перезагрузить смартфон. Способ на все случаи жизни. Делайте почаще.
- Изменить настройки приватности Wi-Fi. Для этого идем в Settings -> Wi-Fi & Internet -> Wi-Fi Preference -> MAC Address и устанавливаем Device MAC
- Установить синхронизацию времени по сети. Переходим в Settings -> Systems -> Date & Time и выставляем Use Network Provided Time Zone
- Вручную указать, что эта сеть не тарифицируемая. Переходим в Settings > Network & Internet -> Wi-Fi -> настройки текущей сети -> Advanced -> Network usage и выбираем Treat as unmetered
- Удалить проблемную Wi-Fi сеть. Переходим в Settings -> Wi-Fi & Internet -> Wi-Fi -> Saved Networks, там выбираем нужную сеть и жмем Forget. После этого лучше перезагрузиться.
- Изменить IP с динамического на статический. Переходим в Settings -> Wi-Fi & Internet и выбираем нужную сеть. В настройках сети жмем на “карандаш” и открываем Advanced Options. Находим IP settings и меняем с DHCP на Static. Теперь можно указать любой свободный адрес из того диапазона в котором работает текущая сеть. Узнать диапазон можно посмотрев ip на хостовой машине (
ifconfig
/ip addr
на *nix иipconfig
на Windows). Там будет что-то вроде192.168.1.98
, в этом случае смартфону поставьте192.168.1.99
или любой свободный. - Полностью сбросить все сетевые настройки на смартфоне. Метод грубый, но иногда остается только он. Сделать это можно в Settings -> System -> Reset Options в меню Reset Wi-Fi, mobile & Bluetooh.
Если ничего не помогает
Да, вдумчивый читатель уже все понял. Здесь будет красная кнопка Factory Reset. Без вариантов.
Бонус
В качестве бонуса хочу показать неплохое дерево решений проблем перехвата трафика.
Ссылки
Это ссылки на материалы, которые частично использовались для написания статьи. Часть информации переносилась из них в неизменном виде, часть адаптировалась под повествование или вовсе переосмысливалась. Статья позиционируется мной как самодостаточная, поэтому читать эти материалы или нет - полностью ваш выбор.
- Proxying Android app traffic – Common issues / checklist
- The Ultimate Decision Tree for Mobile App Network Testing aka “The Squirrel in the middle”!
- Transparent Proxying with mitmproxy
- How to MiTM Android app using IPTABLES
- Bypass SSL Pinning of Flutter apps to Capture HTTPS traffic in Burp Suite (with reFlutter)
- Pentesting Non-Proxy Aware Mobile Applications Without Root/Jailbreak
- Android Chrome 99 expands Certificate Transparency, breaking all MitM dev tools
А это дополнительные ссылки, которые прислали благодарные читатели.