Certificate installation on devices with Android 11+
В этой статье рассказывается об AdGuard для Android — многофункциональном блокировщике рекламы, который защищает ваше устройство на системном уровне. Чтобы увидеть, как он работает, скачайте приложение AdGuard
Чтобы фильтровать HTTPS-трафик (что крайне важно, поскольку большая часть рекламы передаётся по протоколу HTTPS), AdGuard необходимо установить сертификат в пользовательское хранилище устройства. На старых версиях Android это происходило автоматически, но на Android 11 и выше приходится устанавливать его вручную.
Как установить сертификат AdGuard:
- В уведомлении «HTTPS-фильтрация отключена» нажмите Включить.
- Появятся три экрана с объяснениями:
- Зачем фильтровать HTTPS-трафик
- Почему эта фильтрация безопасна
- Почему сертификат AdGuard необходим
На этих экранах последовательно нажмите Далее → Далее → Сохранить сертификат.
Всё готово! Когда сертификат будет установлен, HTTPS-фильтрация включится автоматически.
Эти шаги основываются на смартфоне Google Pixel 4. В других устройствах Android названия настроек могут отличаться. Возможно, вам поможет ввести слово «сертификат» в строке поиска по настройкам.
Если у вас возникли проблемы при ручной установке сертификата (например, вы установили сертификат, но приложение продолжает его игнорировать), вы можете воспользоваться одним из решений ниже.
- Перезапустите AdGuard.
- Попробуйте ещё раз установить правильный сертификат (AdGuard Personal CA).
Если вы по-прежнему сталкиваетесь с проблемой и не можете установить сертификат, напишите нашей команде поддержки по адресу support@adguard.com.
Откручивание SSL пиннинга в Android приложениях
В процессе тестирования на проникновение мобильных приложений на Android часто необходимо выяснить, каким образом приложение общается с сервером, с какими адресами происходит взаимодействие, как выглядят запросы, какие данные передаются. Но не всегда это удается сделать.
В наше время для взаимодействия компонентов веб-приложений используется протокол HTTPS, в основе которого лежат протоколы HTTP и TLS. Просто так перехватить трафик приложения не выйдет, т.к. он зашифрован. Можно, конечно, использовать прокси сервер, который с помощью своего сертификата сможет расшифровать трафик приложения и увидеть все запросы. Однако и средства защиты приложений не стоят на месте. Многие мобильные приложения используют SSL Pinning.
SSL Pinning – это внедрение SSL сертификата, который используется на сервере в код мобильного приложения. Таким образом, приложение не использует хранилище сертификатов устройства и не будет работать с сертификатом, который мы ему подсунули.
Способы защиты приложений
Для того чтобы понять, как обходить защиту, необходимо сначала разобраться, какими средствами эта защита осуществляется. Для этого существуют несколько способов.
Для данного способа необходимо добавить файл сертификата в файлы приложения, затем создать KeyStore и добавить в него наш сертификат.
После этого создаем сам TrustManager, который будет работать с нашим KeyStore, в котором находится нужный сертификат.
Далее создается SSLContext, который использует наш TrustManager. Затем указываем для URLConnection 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 – инструмент для динамического внедрения кода в приложение. Утилита прямо в процессе работы приложения способна отслеживать вызовы методов приложения, модифицировать методы приложения, обращаться к памяти выполняемого приложения и многое другое.
Для обхода 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 настраиваются домены.
Для обхода защиты достаточно лишь убрать весь блок .
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 с доверенным сертификатом в файлах приложения тоже легко реализуется. Но опять же данный способ может не сработать в случае, если приложение при запуске проверяет, не было ли каких-либо изменений в файлах приложения (например, высчитывает чек-сумму).
Таблица 1. Область применения
Способ обхода
Способы защиты, которые можно обойти
TrustManager, OkHttp CertificatePinner
Находки программиста
Решения конкретных задач программирования. Java, Android, JavaScript, Flex и прочее. Настройка софта под Linux, методики разработки и просто размышления.
среда, 27 мая 2015 г.
Https в Android: делаем правильно
To что я опишу ниже — не открытие и не тайна. Это есть даже в официальной документации. Проблема в том, что большинство программистов под Android (и я в том числе) пришли из других, более старых платформ, где проблемы с ssl решались иначе или не возникали вообще.
Например, если сертификат вашего сервера почему-то не в порядке (например он самоподписной), то решение отключить проверку сертификата напрашивается само собой. Такое себе «быстрое решение». В результате вроде бы https и все круто, но на публичном wifi ваш клиент рискует пообщаться по «защищенному» каналу с мошенником. Или, к примеру, вы подключаетесь по ip к своему серверу, а в сертификате прописан домен. Отключаем проверку домена? Давайте не будем спешить. Есть решение которое в «особых» случаях не только не снижает безопасность соединения вашего приложения с сервером но и повышает её до воистину параноидального уровня.
Совсем чуть-чуть теории.
Когда мы устанавливаем https-соединение с сервером, происходит такое себе «рукопожатие», в процессе которого клиент получает публичный ключ сервера. Этот ключ используется для шифрования трафика и для проверки подлинности сервера. Как убедиться что сервер действительно тот, за кого себя выдает? Сертификат, который он предоставляет клиентскому приложению должен быть заверен организацией, чей сертификат есть в системе Android как доверенный и в нём должно быть «зашито» имя домена, соответствующее тому, к которому мы обращаемся. Если мы отключаем проверку, то любой сертификат любого мошенника становится валидным, и вы отправляете ему данные. Он же может общаться с вами, проксируя ваши данные на ваш сервер, который ни о чем не подозревая, обслуживает его как нормального клиента.
Если у вас нет заверенного сертификата, вы можете сгенерировать его себе самостоятельно. Это бесплатно. Но после этого ваше приложение должно доверять этому сертификату «без опоры на авторитеты». Это можно сделать двумя способами: быстрым и правильным. Быстрый — отключить проверку. Правильный: «вшить» публичный ключ вашего сервера в клиентское приложение. Так вы сможете доверять соединению с вашим сервером, не доверяя больше никому, даже самым «супернадежным» сертификатам.
И практика.
Допустим, наш сервер telebank.ru. Он https, причем его сертификат заверен GeoTrust, поэтому мы все ему доверяем. Но допустим, мы хотим принимать его не потому что он заверен кем-то а потому, что он «вшит» в наше приложение. Тогда даже конец света не помешает нам установить защищенное соединение 😉
1. Получим свой публичный ключ:
openssl s_client -connect telebank.ru:443
Из того, что приехало в ответ берём строчки начиная с —BEGIN CERTIFICATE— и заканчивая —END CERTIFICATE—, и сохраняем их в файл, к примеру в telebank.ru.cer. Это и будет наш публичный ключ в base64 представлении.
2. Чтобы работать с ключом, сделаем ему хранилище с помощью BouncyCastle Provider. Скачать его можно, например тут. Скачиваем библиотеку, кладём её рядом с нашим файлом сертификата и выполняем:
keytool -importcert -v -trustcacerts -file «telebank.ru.cer» -alias TelebankCA -keystore «tlkeystore.bks» -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath «bcprov-jdk16-145.jar» -storetype BKS -storepass password
Кeytool спросит вас, доверяете ли вы этому сертификату, отвечайте «yes» и получите файл хранилища tlkeystore .bks , который мы положим в res/raw нашего приложения.
3. Дальше — переходим к программированию.
Делам простое Activity, которое будет слать запрос и выводить результат подключения:
import android.app.Activity; import android.os.Bundle; import android.view.Gravity; import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.TextView; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.client.methods.HttpGet; import java.io.IOException; public class MyActivity extends Activity private TextView rez; @Override public void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState); rez = new TextView(this); rez.setGravity(Gravity.CENTER); LinearLayout root = new LinearLayout(this); root.setGravity(Gravity.CENTER); root.addView(rez, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); setContentView(root, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); > @Override protected void onResume() super.onResume(); rez.setText("Wait, connecting. "); new Thread(new Runnable() @Override public void run() try HttpResponse resp = new SHttpClient(MyActivity.this).execute(new HttpGet("https://telebank.ru/content/telebank-client/ru/login.html")); int status = resp.getStatusLine().getStatusCode(); if (HttpStatus.SC_OK != status) throw new IOException("Invalid status code: " + status); > runOnUiThread(new Runnable() @Override public void run() rez.setText("Done!"); > >); > catch (final Exception e) runOnUiThread(new Runnable() @Override public void run() rez.setText("Error: " + e.getMessage()); > >); e.printStackTrace(); > > >).start(); > >
И, собственно, наш класс, расширяющий стандартный DefaultHttpClient:
import android.content.Context; import org.apache.http.conn.ClientConnectionManager; import org.apache.http.conn.scheme.PlainSocketFactory; import org.apache.http.conn.scheme.Scheme; import org.apache.http.conn.scheme.SchemeRegistry; import org.apache.http.conn.ssl.SSLSocketFactory; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; import java.io.InputStream; import java.security.KeyStore; public class SHttpClient extends DefaultHttpClient private static final String KEYSTORE_PASS = "password"; private KeyStore keyStore; public SHttpClient(Context ctx) throws Exception InputStream in = null; try keyStore = KeyStore.getInstance("BKS"); in = ctx.getResources().openRawResource(R.raw.tlkeystore); keyStore.load(in, KEYSTORE_PASS.toCharArray()); > finally if (in != null) in.close(); > > @Override protected ClientConnectionManager createClientConnectionManager() SchemeRegistry registry = new SchemeRegistry(); registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); registry.register(new Scheme("https", getSslSocketFactory(), 443)); return new ThreadSafeClientConnManager(getParams(), registry); > private SSLSocketFactory getSslSocketFactory() try SSLSocketFactory sf = new SSLSocketFactory(keyStore); sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER); return sf; > catch (Exception e) throw new AssertionError(e); > > >
Тут подробнее: в конструкторе вычитываем наш keystore-файл в обьект класс KeyStore. В метод load кроме собственно файла передаем пароль, который указали при генерации хранилища ( -storepass password , помните? ). Передаём KeyStore в конструктор SSLSocketFactory, которую в свою очередь используем для создания Scheme и т.д.
Проверим?
Не забудьте добавить разрешение на выход в интернет в манифесте и запустите приложение.
4 метода обхода верификации SSL-сертификатов в Android
Прошли те времена, когда мобильные приложения мужественно игнорировали все ошибки, связанные с SSL, и позволяли перехватывать и модифицировать трафик.
- Добавление сертификатов в хранилище достоверных сертификатов.
- Перезапись упакованных сертификатов.
- Использование скрипта Frida для обхода проверок SSL-сертификатов.
- Изменение кода проверки сертификата.
Некоторые из вышеуказанных техник — простые, другие – более сложные в реализации. Мы рассмотрим каждый из этих методов без особого углубления в специфические детали.
Зачем нужна MITM-атака на SSL
Чтобы просматривать и изменять вызовы веб-службы, используемой мобильным приложением, нам понадобится промежуточный прокси сервер для перехвата, созданный при помощи утилит навроде BurpSuite или ZAP. При перехвате SSL-трафика SSL-соединение прерывается на стороне прокси-сервера. Сертификат, отсылаемый прокси-сервером, анализируется мобильным приложением, как если бы прокси был оконечной точкой веб-службы. По умолчанию самоподписанный сертификат, генерируемые утилитами наподобие Burp, не будет принадлежать проверенной достоверной цепочке. Если сертификат нельзя проверить на достоверность, большинство мобильных будут обрывать соединение вместо того, чтобы подключаться и работать в потенциально незащищенном канале. Техники, представленные ниже, предназначены для одной цели – убедить мобильное приложение, что сертификат, отправляемый прокси-сервером, является достоверным.
Техника 1 – Добавление сертификата в хранилище пользовательских сертификатов
Самый простой способ избежать SSL-ошибок – обзавестись валидным и надежным сертификатом. Эта задача решается относительно просто, если вы сможете установить достоверный сертификат на устройство. Если операционная система доверяет вашему центру сертификации, то будет доверять и сертификату, подписанному центром сертификации.
В Android есть два встроенных хранилища сертификатов, которые отслеживают, каким центрам сертификации доверяет операционная система: системное хранилище (хранит предустановленные сертификаты) и пользовательское хранилище (хранит сертификаты, добавленные пользователями).
Выдержка с сайта developer.android.com:
По умолчанию безопасные соединения (использующие протоколы TLS, HTTPS и им подобные) во всех приложениях доверяют предустановленным системным сертификатам. В Android 6.0 (API level 23) и более ранних версиях по умолчанию также считаются достоверными сертификаты, добавленные пользователями. Приложение может настраивать свои собственные соединения на уровне приложения (base-config) и на уровне домена (domain-config).
Сей факт означает, что, если мы имеем дело с приложением, которое работает в Android 6.0 и более ранних версиях, то можно просто добавить сертификат в пользовательское хранилище. Когда приложение пытается проверить достоверность цепочки для нашего сертификата, то обнаружит, что наш центр сертификации связан с достоверным хранилищем и, следовательно, будет доверять нашему сертификату. В более новых версиях приложение не будет доверять хранилищу пользовательских сертификатов. Чтобы решить эту проблему, нужно прописать такой уровень API и версию Android, чтобы приложение стало доверять пользовательским центрам сертификации. Мы будем редактировать атрибут «platformBuildVersionCode» элемента «manifest» в файле AndroidManifest.xml.
В коде выше в строке «platformBuildVersionCode=25» нужно поменять значение 25 на 23, а в строке platformBuildVersionName=»7.1.1″ значение 7.1.1 на 6.0.
После переупаковки приложения с обновленным файлом AndroidManifest.xml, доверие пользовательским центрам сертификации будет восстановлено.
Если требуется запуск на конкретной версии платформы, мы можем определить тэг trust-anchors в файле «/res/xml/network_security_config.xml». Например, следующий файл (https://developer.android.com/training/articles/security-config.html) определяет новый достоверный сертификат, который должен храниться по адресу /res/raw/my_ca.
Если в приложении будет проходить проверку только указанный сертификат, условия для успешного выполнения этой техники выполняются.
Техника 2 – Перезапись упакованного сертификата
Если после установки сертификата в пользовательское хранилище, изменении в настройках версии Android и успешном прохождении проверок при просмотре других ресурсов, защищенных протоколом SSL, все равно возникают ошибки, значит, разработчики внедрили дополнительные условия, которым должны удовлетворять достоверные центры сертификации. Если не забыли, в предыдущей технике внутри тэга trust-anchors добавлялся новый путь к сертификату. Подобный трюк может использоваться разработчиками для защиты приложений от перехвата SSL.
Если в приложении используется индивидуальная цепочка сертификатов, может сработать метод, связанный с перезаписью сертификата. Поскольку в некоторых случаях разработчики могут предусмотреть дополнительные методы для проверки достоверной цепочки, эта техника не гарантирует стопроцентного результата.
Рисунок 1: Перечень сертификатов, используемых приложением
Если открыть пакет приложения при помощи, например, APK Studio, то можно сразу увидеть перечень привязанных сертификатов. На картинке выше сертификаты находятся в папке «assets». Замена явно бросающегося в глаза сертификата UniversalRootCA позволит нам подсунуть приложению наш сертификат.
Техника 3 – Подключение к функциям через фреймворк Frida
Если установки собственного сертификата недостаточно для успешного перехвата SSL-трафика, скорее всего, в приложении используются техники навроде SSL pinning или дополнительная SSL-валидация. В этом случае нужно блокировать проверки через непосредственное подключение к соответствующим функциям. Ранее эта техника была доступна для реализации только на устройствах с правами суперпользователя. Однако на данный момент при помощи библиотеки Frida Gadget можно работать с приложением и получить доступ к полному функционалу фреймворка Frida без прав суперпользователя.
Если вы уже выполняли пентесты мобильных приложений, то, вероятно, знакомы с этим фреймворком. Описание всей функциональности Frida выходит за рамки этой статьи, но если говорить в общем, то этот фреймворк позволяет изменять логику работы приложения во время выполнения. Обычно Frida работает как отдельное приложение и требует прав суперпользователя на устройстве. Если у нас нет прав суперпользователя, мы можем инжектировать в пакет приложения динамическую библиотеку Frida Gadget, содержащую большую часть функционала фреймворка Frida. Эта библиотека загружается во время выполнения приложения и позволяет вносить изменения в код.
Чтобы загрузить Frida Gadget, нужно распаковать APK, вставить динамическую библиотеку, отредактировать smali-код так, чтобы динамическая библиотека вызывалась самой первой, а затем переупаковать и установить пакет. Весь этот процесс хорошо задокументирован Джоном Козиракисом (John Kozyrakis). Вначале лучше пройти все этапы вручную, чтобы лучше понять, как работает эта технология. Чтобы сэкономить время, существует утилита — Objection, которая автоматизирует весь вышеупомянутый процесс. Требуется лишь указание целевого пакета, над которым нужно выполнить манипуляции.
C:\ >objection patchapk -s test_app.apk No architecture specified. Determining it using `adb`. Detected target device architecture as: armeabi-v7a Github FridaGadget is v10.6.28, local is v10.6.13. Updating. Downloading armeabi-v7a library to C:\.objection\android\armeabi-v7a\libfrida-gadget.so.xz. Unpacking C:\.objection\android\armeabi-v7a\libfrida-gadget.so.xz. Cleaning up downloaded archives. Using Gadget version: 10.6.28 Unpacking test_app.apk App already has android.permission.INTERNET Reading smali from: C:\Temp\tmp8dxqks1u.apktemp\smali\com/test/app/TestMainActivity.smali Injecting loadLibrary call at line: 10 Writing patched smali back to: C:\Temp\tmp8dxqks1u.apktemp\smali\com/test/app/TestMainActivity.smali Creating library path: C:\Temp\tmp8dxqks1u.apktemp\lib\armeabi-v7a Copying Frida gadget to libs path. Rebuilding the APK with the frida-gadget loaded. Built new APK with injected loadLibrary and frida-gadget Signing new APK. jar signed. Signed the new APK Performing zipalign Zipaling completed Copying final apk from C:\Users\cwass\AppData\Local\Temp\tmp8dxqks1u.apktemp.aligned.objection.apk to current directory. Cleaning up temp files.
После завершения в нашей рабочей директории должен появиться файл «test_app.objection.apk». По умолчанию утилита objection добавляет постфикс «.objection» к имени пакета. Далее мы можем установить этот пакет так же, как и любой другой APK, при помощи команды adb install test_app.objection.apk. После того как измененный пакет установлен на целевом устройстве, во время запуска приложение должно встать на паузу на начальном экране. В этот момент мы можем подключиться к серверу Frida, который отслеживает наше устройство:
C:\>frida-ps -U
PID Name
—- ——
6383 Gadget
C:\>frida -U gadget
____
/ _ | Frida 10.3.14 — A world-class dynamic instrumentation framework
| (_| |
> _ | Commands:
/_/ |_| help -> Displays the help system
. . . . object? -> Display information about ‘object’
. . . . exit/quit -> Exit
. . . .
. . . . More info at http://www.frida.re/docs/home/
[Motorola Moto G (5) Plus::gadget]-> Java.available
true
Alternatively, Objection supports interaction with the listening Frida server by using the ‘explore’ command:
C:\>objection explore
___| |_ |_|___ ___| |_|_|___ ___
| . | . | | | -_| _| _| | . | |
|___|___|_| |___|___|_| |_|___|_|_|
|___|(object)inject(ion) v1.2.2
Runtime Mobile Exploration
by: @leonjza from @sensepost
[tab] for command suggestions
com.test.app on (motorola: 7.0) [usb] # android hooking search classes TrustManager
android.security.net.config.RootTrustManager
android.app.trust.ITrustManager$Stub$Proxy
android.app.trust.ITrustManager
android.security.net.config.NetworkSecurityTrustManager
android.security.net.config.RootTrustManagerFactorySpi
android.app.trust.TrustManager
android.app.trust.ITrustManager$Stub
com.android.org.conscrypt.TrustManagerImpl
com.android.org.conscrypt.TrustManagerImpl$ExtendedKeyUsagePKIXCertPathChecker
com.android.org.conscrypt.TrustManagerImpl$TrustAnchorComparator
com.android.org.conscrypt.TrustManagerFactoryImpl
javax.net.ssl.TrustManagerFactory$1
javax.net.ssl.TrustManager
javax.net.ssl.TrustManagerFactory
javax.net.ssl.X509TrustManager
javax.net.ssl.TrustManagerFactorySpi
javax.net.ssl.X509ExtendedTrustManager
[Ljavax.net.ssl.TrustManager;
Теперь вы можете воспользоваться функцией для обхода технологии SSL pinning:
com.test.app on (motorola: 7.0) [usb] # android sslpinning disable
Job: 2f633f86-f252-4a57-958e-6b46ac8d69d1 — Starting
[6b46ac8d69d1] [android-ssl-pinning-bypass] Custom, Empty TrustManager ready
Job: 2f633f86-f252-4a57-958e-6b46ac8d69d1 – Started
Техника 4 – Реверс-инжиниринг кода верификации сертификата
Возможен такой случай, когда разработчик использует собственные SSL-библиотеки вместо системных для верификации сертификата. В этой ситуации нам нужно распаковать пакет, сконвертировать smali-код в Java-код и найти функции, отвечающие за проверку сертификата.
Если использовать «dex2jar», синтаксис будет следующим:
C:\>d2j-dex2jar.bat «C:\test_app.apk»
dex2jar C:\test_app.apk -> .\test_app-dex2jar.jar
Полученный файл .jar должен быть пригоден для открытия в вашей любимой утилите для исследования Java-приложений (например, JD-GUI).
После того как вы нашли функции, отвечающие за проверку сертификата, можно либо полностью пропатчить код, либо подцепиться к нужной функции при помощи Frida. Чтобы сэкономить время и не пересобирать полностью приложение, эффективнее подцепиться к функциям, отвечающим за проверку сертификата. Шаги, описанные в предыдущей технике, позволят подключиться к приложению, и далее вы можете либо подцепиться к функции при помощи утилит фреймворка Frida, либо при помощи приложения Objection.
Заключение
Техники, описанные в этой статье, позволяют перехватывать SSL-трафик и обходить некоторые наиболее распространенные защиты, используемые разработчиками. Кроме того, я кратко рассказал об утилите Objection и фреймворке Frida. Обход технологии SSL pinning и других защит лишь небольшая часть возможностей, которые позволяют реализовать эти инструменты.
Надеюсь, мне удалось на доступном языке рассказать о техниках, которые могут быть пригодны для оценки безопасности мобильных Android-приложений и демонстрируют важность наличия нескольких способов проведения подобного рода исследований.
Открой дверь в мир, где наука не имеет границ — подписывайся на наш канал!