Прошли те дни, когда мобильные приложения с завидным упорством игнорировали все SSL ошибки и позволяли вам перехватывать и модифицировать трафик по вашему желанию. Теперь более современные приложения, по крайней мере, проверяют наличие цепочки сертификатов, выданных надежным центром сертификации (ЦС). Мы, будучи пентестерами, хотели бы убедить приложение, что наш сертификат действителен и надежен, чтобы мы смоли провести MITM-атаку и модифицировать его трафик. В этой статье я расскажу о 4 методах, которые вы сможете использовать, чтобы обойти проверки SSL-сертификата на Android:

• Добавление заранее созданного ЦС в хранилище доверенных сертификатов
• Переписать упакованный сертификат на свой сертификат
• Использовать Frida, чтобы обойти проверки SSL-сертификата
• Сделать обратный код для своего сертификата

Эти методы варьируются от довольно простых до более продвинутых в своем исполнении. Попробую рассказать о каждом из них, не вдаваясь в скучные и ненужные детали. Все четко и по делу.

SSL MITM – почему?
Почему нужно уделить особое внимание SSL MITM, когда речь идет о мобильных приложениях? Для того чтобы просматривать и тестировать вызовы веб-службы мобильного приложения, нам нужно использовать перехватывающий прокси, например BurpSuite или ZAP. Перехватывая SSL трафик при помощи прокси, SSL-соединение от клиента прерывается и какой бы сертификат не отправил прокси, чтобы идентифицировать себя, мобильное приложение оценит его, как если бы прокси был конечной точкой веб-службы. По умолчанию, самозаверенный сертификат, сгенерированный такими инструментами, как Burp, не будет иметь действительной цепочки доверия, а если сертификат не будет верифицирован, как доверенный, то большинство мобильных приложений прервет соединение, вместо того, чтобы подключаться к потенциально небезопасному каналу. Все описанные ниже методы имеют общую цель — убедить мобильное приложение в том, что сертификат, предоставляемый нашим перехватывающим прокси, является доверенным.

Метод 1 - Добавление заранее созданного ЦС в хранилище доверенных сертификатов
Простейший способ избежать SSL-ошибок — это иметь действительный доверенный сертификат. Это относительно просто, если у вас есть возможность установить новые доверенные ЦС на устройство, так как если операционная система доверяет вашему сертификату, то она будет доверять и сертификату, подписанному вашим ЦС.
В Android есть два встроенных хранилища сертификатов, которые отслеживают, какие из них одобрила операционная система. Первое — это системное хранилище (содержит предустановленные сертификаты) и второе — пользовательское хранилище (содержит сертификаты, установленные пользователем). От разработчика developer.android.com:
По умолчанию, безопасные соединения (с использованием таких протоколов, как TLS и HTTPS) со всех приложений доверяют предустановленным системой сертификатам. Приложения на Android 6.0 (23 уровень API) и ниже также доверяют сертификатам в пользовательском хранилище по умолчанию. Приложение может настраивать свои собственные соединения, используя base-config (для настройки на уровне приложения) или domain-config (для настройки на уровне домена).
Что это означает для нас? Если приложение, к которому мы хотим применить MITM работает на Android 6.0 и нижу, то мы можем просто добавить свой ЦС в пользовательское ЦС хранилище. Когда приложение оценит нашу цепочку доверия, оно найдет самозаверенный ЦС в хранилище и наш сертификат тоже станет доверенным. Если приложение работает на версиях позже 6.0, то сертификат из пользовательского хранилища не получит статус доверенного. Для того чтобы обойти это препятствие, мы может отредактировать манифест приложения таким образом, чтобы приложение работало на Android 6.0. API уровень указан в атрибуте platformBuilderVersionCode элемента manifest в файле AndroidManifest.xml
Код:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.test.app" platformBuildVersionCode="25" platformBuildVersionName="7.1.1">
Вышеуказанный элемент манифеста ориентирован на platformBuildVersionCode=25, а нам нужно изменить его на 23.
Код:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.test.app" platformBuildVersionCode="23" platformBuildVersionName="6.0">
Когда приложение заново упаковано с обновленным манифестом, оно станет доверенным в пользовательском ЦС хранилище.
Или, если требуется конкретная версия платформы, то мы можем определить доверие в файле конфигурации ‘/res/xml/network_security_config.xml’ в APK. Например, следующий файл определяет новый доверенный ЦС, который нужно хранить в /res/raw/my_ca (из https://developer.android.com/traini...-config.html):
Код:
<?xml version="1.0" encoding="utf-8"?> 
<network-security-config> 
<base-config> 
<trust-anchors> 
<certificates src="@raw/my_ca"/> 
</trust-anchors> 
</base-config> 
</network-security-config>
Если приложение проверяет только действительность представленного сертификата, то этот метод должен позволить вам создать удачные условия для MITM.

Метод 2 - Переписать упакованный сертификат на свой сертификат
Что если вы успешно установили свой сертификат в пользовательском ЦС хранилище, приложение ориентировано на Android 6.0 и ваш сертификат прошел проверку, когда вы пытались найти другие SSL-защищенные ресурсы, но приложение все равно не работает из-за SSL-ошибки? Скорее всего, разработчики предприняли дополнительные меры, чтобы ограничить ЦС, которые пройдут проверку приложения. Вспомним, что в первом методе мы задали свой якорь доверия и создали путь к ЦС. Эта желаемая функциональность, которая и может использоваться разработчиками в попытке защитить свое приложение от перехвата SSL.

Если цепочка самозаверенного сертификата распределяется приложением, то разархивирования APK и переписывания предоставленного ЦС на наш ЦС будет достаточно, чтобы наш перехватывающий сертификат вызвал у приложения доверие. Обратите внимание, что в некоторых случаях может потребоваться дополнительная верификация цепочки доверия, поэтому этот метод может дать разные результаты.


Если открыть APK при помощи такого инструмента, как APK Studio, то станет очевидным присутствие сертификатов применяемого приложения. На картинке сверху видно, что сертификаты расположены в директории assets. Перепишите удачно названный сертификат UniversalRootCA на свой сертификат и это должно помочь нам обмануть приложение, и оно примет наш сертификат.

Метод 3 — Frida
Если установки самозаверенного ЦС недостаточно для успешного перехвата SSL-трафика, возможно приложение выполняет SSL-pinning или дополнительную проверку. Обычно, чтобы пройти этот тип проверки, нам нужно привязаться к коду приложения и вмешаться непосредственно в процесс проверки. Такой тип вмешательства раньше был ограничен рутингом и джейлбрейком (rooting/jailbreaking) телефонов, но благодаря Frida Gadget, теперь мы можем работать с Android приложением и получать полный доступ без рутинга устройства.

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

Обычно, Frida запускается на операционной системе, как независимая программа, но это требует рутинга устройства. Для того чтобы этого избежать, мы можем внедрить Frida Gadget в целевой APK. Frida Gadget имеет почти такой же функционал, как и Frida, но он инкапсулирован в динамическую библиотеку, которая загружается целевым приложением при запуске, что позволяет нам модифицировать код интересующего нас приложения.

Для загрузки Frida Gadget нам нужно разархивировать APK, вставить динамическую библиотеку, отредактировать smali код, чтобы первым, что будет вызываться при запуске приложения стала наша динамическая библиотека, затем заново архивируем APK и устанавливаем его. Весь это процесс был подробно описан Джоном Козиракисом (https://koz.io/using-frida-on-android-without-root/). Стоить проделать все это вручную, чтобы почувствовать, как все работает. Однако для экономии времени у нас есть еще один инструмент — Objection. Он автоматизирует весь этот процесс и в командную строку нужно забить только целевой APK.
Код:
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 в нашей рабочей директории. По умолчанию к имени оригинального APK прибавляется .objection. Мы можем установить этот APK, как и любой другой APK. Команда adb install test_app.objection.apk должна направить его в наше подключенное устройство. После того как измененный APK установлен на вашем устройстве, запущенное приложение должно сделать паузу, когда появится экран загрузки приложения. В этот момент, мы можем подключиться к серверу Frida, который должен прослушивать устройство. Если вы предпочитаете утилиты 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-библиотеки, вместо того, чтобы полагаться на библиотеки системы для проверки сертификата. В этом случае, нам нужно будет разархивировать APK и конвертировать 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-трафик на Android и обойти некоторые самые распространенные методы защиты, применяемые разработчиками. Кроме того, мы кратко рассмотрели функционал Objection и Frida и их способность обходить SSL-pinning и другие методы защиты. Надеюсь, что эта статья была для вас полезным введением в различные методы, которые могут применяться для тестирования безопасности мобильных приложений на Android.

©Источник: NetSPI Blog
©Автор: Cody Wass