Перехват трафика в Android. Большой гайд. - (не)Уникальный опыт

Перехват трафика в Android. Большой гайд.


Зачем еще одна статья?

Задача перехвата трафика android приложений довольно хорошо описана на куче языков и даже не нужно уметь гуглить чтобы найти информацию о том, как настроить прокси и посмотреть заветные запросы. Даже набившая уже всем оскомину тема “как отломать ssl pinning” была множество раз разжевана и надо быть по пояс странным чтобы в этом не разобраться.

…когда ты слишком долго в пути, когда тебя обуревает жадность, приходит черный пес чтобы отобрать у тебя все.
Черный пес (1998)

Да… потом появляется то самое приложение, которое вопреки всем настройкам не хочет работать через прокси. Или через прокси проходит только часть трафика. В такой ситуации лучше не начинать нажимать все подряд, чтобы не увеличивать энтропию происходящего, а подойти к вопросу системно и последовательно попробовать разные методы для решения этой проблемы.

/img/intercept-traffic-android/mitm-logo.gif


Базовая настройка

Начать хотелось бы с базовой настройки, которая работает у меня, чтобы читателю был понятен контекст происходящего. А начинающие специалисты возможно откроют для себя что-то новое ;)

этот кусок фактически повторяет мою статью из 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 сети.

Шаг #1

Шаг #1

Шаг #2

Шаг #2

Шаг #3

Шаг #3

Шаг #4

Шаг #4

Шаг #5

Шаг #5

Шаг #6

Шаг #6

Вернемся к сертификатам. Когда прокси уже настроен, то установка системного сертификата сводится к шести простым шагам:

  1. Зайти на адрес http://burpsuite
  2. Там нажать CA Certificate и скачать его на девайс
    /img/intercept-traffic-android/burp-ca.png
  3. Переименовать cert.der -> cert.cer
  4. Settings -> Security -> Encryption & credentials -> Install a certificate -> CA certificate -> Install anyway и выбрать cert.cer
    /img/intercept-traffic-android/install-cert.png
    Также неплохо бы убедиться, что сертификат появился в /data/misc/user/0/cacerts-added под именем вида 9a5ba575.0

[✋Этот пункт устарел! Временное решение описано здесь✋]5. Зайти в MagiskManager и поставить модуль Move Certificates (легко найти поиском)

/img/intercept-traffic-android/move-cert.png
6. Перезагрузиться и убедиться, что сертификат переместился в /system/etc/security/cacerts (удобно смотреть по дате через ls -la например)
/img/intercept-traffic-android/lsla-certs.png

На этом базовая настройка закончена и можно переходить к решению проблем, когда описанный выше сетап почему-то перестает работать

Когда ничего не работает…

Проблем, из-за которых трафик может не ходить через проксю довольно много. Часть их них относится к самому приложению и тем технологиям на которых оно сделано, другая часть возникает из-за глюков операционной системы смартфона или хостовой машины. А еще бывают космические аномалии, луна в Козероге, шумы в портах и вообще три часа ночи уже спать иди…

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

Проверить работает ли HTTP трафик (который без TLS)

Очень может быть что сертификаты не встали правильно или приложение как-то особенно хитро гоняет трафик по HTTPS, поэтому нужно убедиться, что прокси вообще работает. Для этого нужно открыть любой сайт по HTTP в браузере. Например http://neverssl.com на котором намеренно отключена настройка Strict Transport Security (HSTS) и трафик этого сайта точно дожен отобразиться в проксе.

Если трафика не видно, то в случае с Burp-ом можно проверить, что отключен перехват трафика (Intercept is off)

/img/intercept-traffic-android/burp-intercept.png

SSL pinning aka Public Key Pinning aka Certificate Pinning

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

А про самое явление здесь

Также можно попробовать вот эти способы:

UPD 21.02.2023: Еще один довольно мощный скрипт. Умеет в динамический патчинг.

Если досталось приложение на Xamarin/Unity, то придется разбираться в коде и патчить. Начать этот путь лучше всего с ILSpy и fridax. А вот с Flutter-ом все несколько проще. Нужно использовать reFlutter, который патчит ssl_crypto_x509_session_verify_cert_chain, что и позволяет обойти некоторые реализации пиннинга. Чуть больше подробностей тут

Подборка статей про обход ssl pinning

Проверить, что прокси поднят на внешнем интерфейсе

По умолчанию Burp Suite поднимает прокси на 127.0.0.1, а значит достучаться до этого адреса со смартфона не выйдет. Нужно поднять его на внешнем интерфейсе, или сразу на всех интерфейсах. Сделать это можно в настройках прокси нажав кнопку Edit

/img/intercept-traffic-android/burp_allinterfaces.webp

Проверить, что прокси доступен по сети

Если в системе уже включен прокси (глобальный или на уровне Wi-Fi), то его нужно отключить. После этого открыть браузер и зайти на какой-нибудь сайт, чтобы проверить, что прокси отключен. После этого нужно перейти по адресу http://<your-host-ip>:<proxy-port>. Вы должны увидеть страницу приветствия Burp-а. Теперь нужно снова включить прокси как было описано ранее и проверить доступен ли адрес http://burpsuite.

Если доступа нет, то можно попробовать сделать следующее:

  • Подключиться к другой Wi-Fi сети. Лучше всего сделать гостевую и выключить там все механизмы безопасности. Задача этого этапа понять где проблема. Продолжать работу в такой сети не нужно =)
  • Поднять прокси на собственном сервере доступном по сети Интернет. Можно купить VDS или взять годовой бесплатный EC2 на амазоне
  • Провести ARP-спуфинг чтобы смартфон начал считать роутером ваш компьютер и все операции делал через него.
  • Проверить настройки фаервола на хостовой машине, возможно там запрещены какие-то порты и/или адреса. Универсальных рекомендаций под конкретные ОС нет. Нужно гуглить.
  • Проверить настройки фаервола на смартфоне. Вы могли их сделать когда-то давно и забыть об этом. Для Android это чаще всего iptables. Подробности тут.
  • Завернуть трафик через USB с помощью adb
    1. В качестве ip адреса прокси на смартфоне указать 127.0.0.1 и порт 8080
    2. Подключить смартфон к комьпьютеру и убедиться, что он виден в выводе adb devices
    3. На хостовой машине выполнить команду adb reverse tcp:8080 tcp:8080, которая перенаправит трафик с порта 8080 на смартфоне на порт 8080 на хосте. Конечно же прокси должен слушать этот же порт
    4. Открыть браузер на смартфоне и проверить доступен ли адрес http://127.0.0.1:8080/

Проверить установленный ранее сертификат

Еще раз убедиться, что на устройстве установлен правильный сертификат. Идем в Settings -> Security -> Encryption & Credentials -> Trusted Credentials -> System и ищем сертификат PortSwigger, который должен быть активным

/img/intercept-traffic-android/system-cert.png
Если ничего такого нет, то обнуляемся и идем в раздел “Базовая настройка” чтобы на этот раз сделать все правильно.

Убедиться, что установленный сертификат не протух

Попробовать открыть любой 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

/img/intercept-traffic-android/invisible-proxy.webp

Проверить не использует ли приложение нестандартный порт

Приложение вполне может использовать какие-то нестандартные порты для общения с сервером. Там может быть все, что угодно, особенно если это обращение к каким-то тестовым стендам или приватному API. Эта информация пригодится для ручной настройки iptables, которая была в предыдущем разделе. Узнать про нестандартные порты можно путем статического анализа, покопавшись в декомпилированном и/или дизассемблированном коде приложения или путем динамического анализа с помощью tcpdump.

Его можно запустить прямо на смартфоне (нужен root) командой

tcpdump -i wlan0 -n -s0 -v

после чего открыть приложение и как-то с ним повзаимодействовать чтобы пошел трафик. Соединений может быть довольно много, поэтому лучше предварительно закрыть все приложения и убедиться что с сетью ничего в данный момент не работает.

Для удобства, можно записать весь трафик в pcap файл командой

tcpdump -i wlan0 -n -s0 -w /sdcard/output.pcap

и открыть этот файл на хостовой машине в WireShark

/img/intercept-traffic-android/wireshark.webp

Когда нестандартный порт идентифицирован, то завернуть с него трафик можно с помощью adb reverse или iptables, как было показано выше.

Но вместе с нестандартным портом может прийти нестандартный протокол. А большинство проксей, и Burp в том числе, понимают только HTTP. В случае с Burp-ом может помочь расширение NoPE Proxy (статья про него), а вот для всех остальных придется или искать специализированный прокси под нужный вам протокол или использовать тот же WireShark и разбирать наполовину сырой трафик.

Убедиться, что нет ограничений при подключении к Wi-Fi

Иногда, при подключении к Wi-Fi сетям, это подключение происходит с ограничениями. В частности само подключение к Wi-Fi может быть стабильным, но подключение к интернету - нет. Явление носит спорадический характер и может исправиться автоматически после нескольких секунд прошедших с момента подключения к сети или показать вот такое окно:

/img/intercept-traffic-android/wi-fi-limit.jpg

В этом диалоге нужно нажать “yes” и все заработает. Но такой красивый сценарий бывает не всегда. Иногда это окно не появляется, а ограничения при этом остаются. Вот несколько способов как с этим бороться:

Пути к настройкам отличаются на разных версиях Android. Проще искать их через Search settings

  • Перезагрузить смартфон. Способ на все случаи жизни. Делайте почаще.
  • Изменить настройки приватности Wi-Fi. Для этого идем в Settings -> Wi-Fi & Internet -> Wi-Fi Preference -> MAC Address и устанавливаем Device MAC
    /img/intercept-traffic-android/wifi-privacy.webp
  • Установить синхронизацию времени по сети. Переходим в Settings -> Systems -> Date & Time и выставляем Use Network Provided Time Zone
    /img/intercept-traffic-android/network-provided-timezone.webp
  • Вручную указать, что эта сеть не тарифицируемая. Переходим в Settings > Network & Internet -> Wi-Fi -> настройки текущей сети -> Advanced -> Network usage и выбираем Treat as unmetered
    /img/intercept-traffic-android/unmetered.png
  • Удалить проблемную Wi-Fi сеть. Переходим в Settings -> Wi-Fi & Internet -> Wi-Fi -> Saved Networks, там выбираем нужную сеть и жмем Forget. После этого лучше перезагрузиться.
    /img/intercept-traffic-android/forget-ssid.webp
  • Изменить 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 или любой свободный.
    /img/intercept-traffic-android/dhcp-change.webp
  • Полностью сбросить все сетевые настройки на смартфоне. Метод грубый, но иногда остается только он. Сделать это можно в Settings -> System -> Reset Options в меню Reset Wi-Fi, mobile & Bluetooh.
    /img/intercept-traffic-android/reset-WiFi.jpg

Если ничего не помогает

Да, вдумчивый читатель уже все понял. Здесь будет красная кнопка Factory Reset. Без вариантов.

Бонус

В качестве бонуса хочу показать неплохое дерево решений проблем перехвата трафика.

/img/intercept-traffic-android/mobile_app_intercept-3.png

Ссылки

Это ссылки на материалы, которые частично использовались для написания статьи. Часть информации переносилась из них в неизменном виде, часть адаптировалась под повествование или вовсе переосмысливалась. Статья позиционируется мной как самодостаточная, поэтому читать эти материалы или нет - полностью ваш выбор.

А это дополнительные ссылки, которые прислали благодарные читатели.


Смотрите также