Проблемы перехвата трафика
В процессе тестирования на проникновение мобильных приложений на Android часто необходимо выяснить, каким образом приложение общается с сервером, с какими адресами происходит взаимодействие, как выглядят запросы, какие данные передаются. Но не всегда это удается сделать.
В наше время для взаимодействия компонентов веб-приложений используется протокол HTTPS, в основе которого лежат протоколы HTTP и TLS. Просто так перехватить трафик приложения не выйдет, т.к. он зашифрован. Можно, конечно, использовать прокси сервер, который с помощью своего сертификата сможет расшифровать трафик приложения и увидеть все запросы. Однако и средства защиты приложений не стоят на месте. Многие мобильные приложения используют SSL Pinning.
SSL Pinning это внедрение SSL сертификата, который используется на сервере в код мобильного приложения. Таким образом, приложение не использует хранилище сертификатов устройства и не будет работать с сертификатом, который мы ему подсунули.
Ошибка, которая возникает в случае использования Burp suite для перехвата трафика с помощью собственного сертификатаСпособы защиты приложений
Для того чтобы понять, как обходить защиту, необходимо сначала разобраться, какими средствами эта защита осуществляется. Для этого существуют несколько способов.
-
Trust manager
Для данного способа необходимо добавить файл сертификата в файлы приложения, затем создать KeyStore и добавить в него наш сертификат.
После этого создаем сам TrustManager, который будет работать с нашим KeyStore, в котором находится нужный сертификат.
Далее создается SSLContext, который использует наш TrustManager. Затем указываем для URLConnetction SocketFactory из созданного SSLContext.
Основная суть этого метода в том, что мы используем непосредственно сам файл сертификата в проекте, а затем создаем TrustManager, который будет работать только с этим сертификатом.
Данная реализация работает непосредственно с API на достаточно низком уровне, поэтому этот способ надо использовать осторожно.
-
OkHttp CertificatePinner
Вторым способом является использование библиотеки OkHttp. В ней есть удобный CertificatePinner, который с помощью своего конструктора закрепляет за доменом определенный fingerprint сертификата.
Этот fingerprint высчитывается из сертификата, с которым должно работать приложение, а затем пишется непосредственно в код.
Можно указать несколько сертификатов для разных доменов.
-
Network Security Configuration
С версии Android 7.0 стала возможна настройка конфигурации сети. В папке res/xml/ создается файл network_security_config.xml, в котором прописываются правила и указываются fingerprints, как в случае с OkHttp.
Затем в AndroidManifest.xml прописывается использование данного файла в качестве android:networkSecurityConfig.
Этот способ позволяет редактировать сертификаты, не меняя исходный код приложения.
Способы обхода механизмов защиты
-
Frida
Frida инструмент для динамического внедрения кода в приложение. Утилита прямо в процессе работы приложения способна отслеживать вызовы методов приложения, модифицировать методы приложения, обращаться к памяти выполняемого приложения и многое другое.
Для обхода SSL Pinning с помощью Frida есть несколько готовых скриптов, создающих кастомный TrustManager, который будет доверять нашему сертификату. Рассмотрим скрипт.
CertificateFactory и X509Certificate нужны для создания экземпляра сертификата из считанного файла.
FileInputStream и BufferedInputStream используются для считывания файла сертификата.
KeyStore наш кастомный KeyStore, в который положим наш сертификат.
TrustManagerFactory создает экземпляр TrustManager, который будет работать с нашим KeyStore.
SSLcontext реализация протокола SSL, которая выступает как factory для sslSocketFactory.
Считываем сертификат cert-der.crt, который мы предварительно поместили на устройство, и создаем экземпляр этого сертификата.
Создаем keyStore, в который складываем наш сертификат.
Создаем trustManager, который доверяет keyStore с нашим сертификатом.
Вот здесь начинается настоящее использование Frida. Данный фрагмент перезаписывает метод SSLContext. Теперь при вызове приложением метода сначала будет вызываться информационный лог в консоль, затем выполнится исходный метод, который мы перезаписываем. Но он вызовется не просто так. Вместо второго параметра, который будет передан в функцию, новая функция подставляет кастомный TrustManager с нашим сертификатом. И в конце снова информационный лог в консоль о том, что все прошло удачно.
Таким образом, данный скрипт готовит TrustManager, а затем использует его в методе вместо того, который передается (переменные a и с передаются в вызов исходной функции, а вот переменная b заменяется на кастомный TrustManager).
Frida позволяет переопределять методы, выполнять собственные скрипты. Поэтому с помощью Frida можно обойти защиту, реализованную через OkHttp CertificatePinner.
Главное преимущество этого метода отсутствие необходимости патчить исходный код apk и пересобирать приложение. А так как нам не нужно пересобирать приложение, значит этому способу не помешают методы защиты приложения от пересборки.
С другой стороны, для данного метода необходимо подключить телефон к устройству с Frida, установить frida-server на телефон, а это не всегда удобно.
-
Изменение исходного кода и пересборка apk
В случае, если мы хотим один раз произвести обход средств защиты и получить приложение, в котором не будет SSL Pinning, необходимо изменить сам код приложения.
Для этого сначала нужно декомпилировать apk файл. Декомпилируется он в smali код. Smali ассемблер для android-приложений. Все изменения будут производиться в .smali файлах, так как именно из них будет пересобираться приложение.
Для декомпиляции можно воспользоваться удобной утилитой apktool. Также для декомпиляции работы с разобранным apk, а затем и для сборки можно использовать удобное расширение для Visual Studio Code ApkLab.
Чтобы не копаться в трудночитаемых исходных кодах smali, вышеперечисленные утилиты умеют преобразовывать их в Java-код, который уже гораздо удобнее изучать. Также утилиты предоставляют функциональность деобфускации, которая очень помогает в изучении исходного кода.
ApkLab предоставляет также автоматизированный поиск необходимых участков кода. Рассмотрим что и почему он изменяет.
В первом файле утилита закомментировала исполнение следующих методов: checkClientTrusted, checkServerTrusted, getAcceptedIssuers.
По названиям методов можно предположить, что первый проверяет, является ли клиент доверенным, второй проверяет, является ли сервер доверенным, а третий получает лист доверенных сертификатов. Но не будем гадать и перейдем к Java-коду данных методов.
Теперь мы можем уже с пониманием рассмотреть, почему утилита закомментировала эти фрагменты. Первые два метода внутри ничем не отличаются и вызывают новый метод mo9499a (такое название из-за деобфускации), который слишком большой, чтобы вставлять его здесь. Но, судя по документации, этот метод строит цепочку сертификатов до корневого сертификата, а потом проверяет, можно ли ему доверять. В данном методе при ошибке будет выброшено исключение. Но мы закомментировали вызов данной функции, поэтому никаких проверок сертификат проходить не будет, и поэтому исключений мы не получим.
Метод getAcceptedIssuers должен возвращать массив доверенных сертификатов. Но дальнейшая реализация и использование данного метода работает таким образом, что если мы вернем пустой массив, то программа будет доверять любому сертификату. Именно это и сделала утилита: закомментировала код, в котором происходит получение сертификатов из keyStore (это происходит в методе m7931a), а вместо этого просто возвращается пустой массив.
Автоматический редактор кода заменяет эти фрагменты, т.к. они используются в проверке сертификата. Поэтому, если необходимо самому изменить какие-то фрагменты проверки, сначала лучше изучить, как работают те или иные методы, а затем уже вручную менять их в smali. К тому же обычно не приходится писать много кода вместо методов. В рассмотренном выше примере не делается ничего сложнее комментирования основной функциональности и создания каких-либо переменных-заглушек.
Также можно рассмотреть OkHttp CertificatePinner. В обзоре реализации был представлен фрагмент кода, где в OkHttpClient передается CertificatePinner. Найдя в smali соответствующий метод, можно убрать строчку, в которой CertificatePinner складывается в поле объекта OkHttpClient.
-
Изменение NSC (Network Security Configuration)
Самый простой способ обхода SSL Pinning.
В случае, если в приложении присутствует NSC, необходимо его изменить. В файле NSC могут быть прописаны base-config и domain-config.
В base-config может быть указано, каким сертификатам приложение может доверять.
В domain-config настраиваются домены.
Для обхода защиты достаточно лишь убрать весь блок <domain-config>.
ApkLab также умеет делать автоматическое изменение NSC файла.
В случае отсутствия файла в проекте утилита создает его с указанным выше содержимым, а также прописывает его в AndroidManifest.xml.
-
Подмена файла сертификата
В случае, когда защита реализована с помощью TrustManager, использующего KeyStore, в котором лежит доверенный сертификат. Обычно KeyStore вшит в приложение. В .apk KeyStore обычно лежит либо в /res/raw, либо /assets.
Поэтому можно просто положить туда свой сертификат вместо того, который установили туда разработчики.
Итог
В связи с тем, что SSL Pinning может быть реализован множеством разных способов, от различных библиотек, до кастомных реализаций привязки сертификата, задача его обхода не всегда простая и очевидная. Каждый раз, рассматривая новое приложение, нужно изучить, какие методы используются, а затем уже применять соответствующие способы обхода, которые тоже не всегда удобны и работоспособны.
Frida достаточно сильный инструмент, но возникает неудобство в виде постоянного подключения телефона к устройству, предварительной конфигурации и прочего. А если в интернете нет готового скрипта для нужных целей, то написание собственного требует хорошего понимания работы Frida.
Непосредственный патчинг apk хорош тем, что его можно сделать всего раз и на выходе будет приложение без SSL Pinning. Однако на этом пути может помешать защита приложения от пересборки. Конечно и ее можно попытаться обойти, раз мы имеем исходный код приложения, но это потребует больше времени и сил.
Изменение Network Security Configuration достаточно простой и рабочий способ, но редко когда приложения ограничиваются только этим способом защиты. Поэтому знание обхода этого способа SSL Pinning необходимо, но недостаточно.
Подмена KeyStore с доверенным сертификатом в файлах приложения тоже легко реализуется. Но опять же данный способ может не сработать в случае, если приложение при запуске проверяет, не было ли каких-либо изменений в файлах приложения (например, высчитывает чек-сумму).
Способ обхода |
Способы защиты, которые можно обойти |
Frida |
TrustManager, OkHttp CertificatePinner |
Редактирование APK |
TrustManager, OkHttp Certificate Pinner, NSC |
Редактирование NSC |
NSC |
Подмена файла сертификата |
TrustManager |
Способ обхода |
Плюсы |
Минусы |
Frida |
Универсальный инструмент, позволяющий во время работы приложения менять его методы Не изменяет само приложение |
В случае, когда надо написать свой скрипт, необходимо хорошее понимание работы утилиты и приложения Для каждого обхода необходимо подключать телефон к устройству Frida |
Редактирование APK |
Делается только раз и после получается приложение без защиты |
Если приложение защищено от изменения, придется разбираться еще и с этой защитой |
Редактирование NSC |
Прост в реализации Может довольно часто пригождаться в случае работы с Android версии 7.0 и моложе |
Обычно недостаточно только этого способа обхода, так как применяются и другие методы защиты Так же могут возникнуть трудности, в случае если приложение защищено от изменения |
Подмена файла сертификата |
Прост в реализации |
И данный метод так же неудобен в случае защиты приложения от изменений |