Универсальный перехват как обойти ssl pinning раз и навсегда и читать трафик любого приложения
В этой статье я кратко расскажу, что означает «безопасное соединение» между клиентом и сервером, что такое SSL-pinning, для чего он нужен и когда его использовать. Так же объясню от каких угроз мы защищаемся с его помощью.
Представим, что у нас есть сайт или мобильное приложение (оба подпадают под определение клиента). При обращении сайта или мобильного приложения к бекенду (сервер) безопасность соединения обеспечивается с помощью протокола SSL (Secure Socket Layer), а если быть точнее, TLS (Transport Layer Security). TLS ставит своей целью создание между двумя узлами сети защищённого от прослушивания и подмены информации канала связи, а также проверку того, что обмен данными происходит между именно теми узлами, т.е. обеспечение конфиденциальности, целостности и аутентификации. Под узлами можно понимать сервер и мобильное приложение, либо сервер и веб-браузер.
Изначально SSL был разработан компанией Netscape для своего одноименного браузера в середине 90-х. Позднее на основании SSL 3.0 был принят RFC-стандарт TLS 1.0. Рекомендованными для применения в 2019 году являются версии TLS не ниже 1.2 (актуальная версия на сегодня — 1.3). На странице в википедии можно посмотреть поддержку версии TLS у всех популярных браузеров.
В качестве удостоверяющего хост документа выступает сертификат стандарта X.509. Под сертификатом можно понимать файл, в котором содержится следующая информация:
- Название
- Публичный ключ
- Серийный номер
- Алгоритм сертификата
- Цифровая подпись и др.
Сертификаты не существую сами по себе — их выпускают центры сертификации (Certificate Authority), в цепочке сертификатов самым первым является сертификат CA, его еще называют корневой. CA являются общеизвестными и ключи, которые они выпускают являются доверенными по умолчанию. Корневые сертификаты как правило “зашиваются” в операционную систему и обновляются при следующих обновлениях. Сертификаты выстраиваются в цепочку, можно так же назвать термин дерево: сертификаты первого уровня (выпущенные CA), так же могут выпускать сертификаты следующих уровней. В случае компрометации сертификата, он может быть отозван, и тогда автоматически отзываются все дочерние сертификаты.
Кажется, что TLS решает атаку MITM. Тем не менее, возможен вариант, когда между узлами окажется самоподписанный корневой сертификат злоумышленника и каким-то образом этот сертификат попадёт к нам на устройство. Например, если пользователь недостаточно технически образован и ему предлагается установить сертификат для пользования сетью Wi-Fi. После этого данные шифруются сертификатом злоумышленника (которые он легко расшифровывает) и мы не подозреваем о подмене. В данном случае злоумышленник выступает неким прокси-сервером между нашими узлами.
Если мы реализуем проверку сертификата на клиенте, то можем отловить ситуацию, когда сертификат между узлами неподлинный. Технически это выглядит следующим образом: при установлении соединения с хостом на клиенте проверяется, соответствует ли сертификат от сервера тому сертификату, о котором знает клиент. Если нет — соединение считается небезопасным и обмен данных с хостом прекращается. Помимо прослушивания трафика, SSL-pinning так же не раскрывает спецификацию запросов API, что может пригодиться при атаках как на сервер, так и на клиент.
По тому, какой сертификат проверяем:
- Цепочка сертификатов — можно проверять данные каждого из сертификатов в цепочке.
- Конечный сертификат — наиболее распространённый вариант на практике, проверяется сертификат самого нижнего уровня.
- Корневой или промежуточный сертификат. Например, несколько наших хостов имеют один родительский сертификат, можем проверять только его вместо нескольких проверок.
По тому, какие данные из сертификата проверяем:
- Фингерпринт. Это хэш от данных сертификата (можно выбрать, например из SHA-1, SHA-256). Фингерпринт видно в окне браузера при просмотре сертификата. Подход достаточно прост в реализации и обычно в SDK уже есть API по вычислению фингерпринта сертификата. Но к минусам такого подхода могу отнести то, что при истечении сертификата прежний фингерпринт становится невалидным, и его необходимо обновить на клиенте. Невалидным он становится, т.к. у нового сертификата как минимум будет новый приватный ключ.
- Публичный ключ. Данный вид лишён недостатка о перевыпуске сертификата, т.к. если в вашем распоряжении имеется прежний сертификат (пара публичный-приватный ключ), то вы сможете выпустить новый сертификат с тем же публичным ключом даже у другого CA. После истечения текущего не придётся обновлять информацию на клиенте. К недостаткам можно отнести, во-первых, что публичный ключ извлекается чуть сложнее, чем фингерпринт, и во-вторых, сам по себе факт того, что ключ не будет меняется долгое время.
- Хосты сторонних сервисов — сертификат может измениться без нашего ведома. Например, Google-аналитика.
- Нет чувствительных данных — нет никакой угрозы, что данные будут получены третьей стороной. Например, любые открытые сервисы (текущее время, погода).
Раз уж мы обсудили SSL-pinning в контексте мобильных приложений, почему бы не сделать тоже самое с веб-сайтами? Ответ достаточно прост — браузер посещает большое количество сайтов, ровно как и каждый день появляется много новых, и это достаточно проблематично обладать информацией обо всех них. Мобильное приложение же, как правило, обращается к конечному числу доменов, информация о сертификатах хранится внутри него. В 99% случаев не нужно придумывать свои способы шифрования, TLS + SSL-pinning обеспечивают достаточный высокий уровень безопасности для передачи чувствительных данных по сети. Примеры приложений, где SSL-pinning является по-моему мнению обязательным — это мобильные приложения банков, другие приложения из финансового и страхового сектора. Для более подробного погружения в схему работы TLS советую данный ресурс.
Получая от сервера сертификат на третьем шаге рукопожатия, клиент принимает решение, доверять серверу или нет (тот ли он, за кого себя выдает?). Делает это клиент не без сторонней помощи, что в результате и приводит к существенному упрощению анализа трафика.
Получая от сервера сертификат, клиент всегда может узнать, кто именно его подписал, и удостовериться в этом с помощью приложенных публичных ключей. И так вплоть до корневого центра. Если на пути до корневого сертификата так и не встречается ни одного доверенного сертификата, клиент завершает процедуру рукопожатия, не передавая никаких полезных данных серверу (ведь он, вероятно, не тот, за кого себя выдает). Этот процесс называется проверкой цепочки сертификатов.
Для разработчиков сложности по сокрытию трафика своего приложения начинаются в тот момент, когда у клиента появляется возможность добавлять собственные доверенные сертификаты. По умолчанию источником таких сертификатов является какая-нибудь папка или группа папок (в зависимости от операционки) в локальной файловой системе, в которую разработчики ОС еще на этапе сборки поместили сертификаты доверенных центров. Давай попробуем убедиться в этом на практике.
Исследуем принципы работы OpenSSL на подопытном приложении
Кроме функции SSL_CTX_load_verify_locations существует еще несколько похожих способов загрузки проверенных сертификатов внутрь OpenSSL. Наверняка разработчики, которые писали свои клиенты TLS, не стеснялись подсматривать подобные общедоступные примеры.
Готовим тестовое приложение
В интерфейс тестового приложения включим две кнопки, по нажатию на которые будет происходить следующее:
Совершенно стандартный код, кочующий по Ctrl-C и Ctrl-V из одного проекта в другой, подвергаясь при этом несущественным изменениям. Итак, запускаем новоиспеченное приложение и сразу же заглядываем в разметку его памяти.
Продолжение доступно только участникам
Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», увеличит личную накопительную скидку и позволит накапливать профессиональный рейтинг Xakep Score! Подробнее
В этой статье мы рассмотрим анализ сетевого трафика у приложений, использующих технологию certificate pinning.
Автор: Prateek Gianchandani
В этой статье мы рассмотрим анализ сетевого трафика у приложений, использующих технологию certificate pinning. Одно из наиболее удачных толкований certificate pinning указано ниже (взято отсюда).
По умолчанию при инициации SSL-соединения клиент проверяет, что сертификат сервера:
- имеет проверяемую цепочку сертификатов до достоверного (корневого) сертификата.
- соответствует имени хоста.
Хотя, клиент не проверяет, является ли текущий сертификат именно тем, который использует сервер.
Проверка на соответствие между сертификатами на устройстве и на удаленном сервере потенциально является брешью в системе безопасности. Все дело в том, что хранилище сертификатов на устройстве может быть легко скомпрометировано; пользователь может установить небезопасные сертификаты, тем самым ставя себя под угрозу стать жертвой атак типа «человек посередине» (man-in-the-middle attacks). Технология certificate pinning позволяет решить эту проблему. Суть метода заключается в том, что сертификат, соответствующий тому, который использует сервер, жестко зашивается в мобильное приложение. Во время инициации SSL-соединения мобильное приложение игнорирует хранилище на устройстве и соединяется только с теми хостами, сертификат у которых соответствует сертификату, зашитому в приложении. Сия технология также помогает нам сделать хост достоверным при помощи самоподписанного сертификат и не устанавливать дополнительные сертификаты на устройстве.
Технология certificate pinning используется многими популярными приложениями: Twitter, Square и т. д. Вопрос заключается в том, как обойти проверку сертификата на стороне клиента? Важно отметить, что все проверки происходят на стороне клиента, и мы можем, используя различные фреймворки (Mobile Substrate и другие), патчить методы и обходить эти проверки.
Чтобы проанализировать трафик приложения Twitter, подключитесь к устройству через ssh и загрузите приложение iOS SSL Kill Switch. Кроме того, установите следующие приложения через Cydia:
- dpkg
- MobileSubstrate
- PreferenceLoader
Устанавливаем deb-пакет при помощи команды dpkg -i.
Рисунок 1: Установка приложения SSL Kill Switch
После установки сделайте респринг устройства при помощи команды killall -HUP SpringBoard.
Далее зайдите в настройки SSL Kill Switch и включите опцию Disable certificate validation.
Рисунок 2: Отключение проверки сертификата
Теперь трафик приложения Twitter будет проходить через Burp Proxy.
Рисунок 3: Лог Burp Proxy
Чтобы проверить, что SSL Kill Switch инжектируется в приложение, зайдите в Xcode -> Devices (я использую Xcode 6), найдите ваше устройстве в меню слева и кликните на стрелку, указывающую вверх, в левом нижнем углу. По логам устройства вы увидите, что SSL Kill Switch инжектируется в приложение.
Рисунок 4: Полный лог устройства
Еще одна утилита со схожим функционалом - trustme. Рекомендую вам также ознакомиться с этим приложением.
Прошли те времена, когда мобильные приложения мужественно игнорировали все ошибки, связанные с SSL, и позволяли перехватывать и модифицировать трафик. Современные приложения, как минимум, проверяют цепочки сертификатов на валидность и принадлежность к достоверному центру сертификации. Мы, пентестеры, ставим перед собой задачу «убедить» приложение, что сертификат надежный с целью выполнения атаки типа «человек посередине» и последующего изменения трафика. В этой статье будут рассмотрены следующие техники обхода проверок SSL-сертификатов в Android:
- Добавление сертификатов в хранилище достоверных сертификатов.
- Перезапись упакованных сертификатов.
- Использование скрипта Frida для обхода проверок SSL-сертификатов.
- Изменение кода проверки сертификата.
Некоторые из вышеуказанных техник - простые, другие – более сложные в реализации. Мы рассмотрим каждый из этих методов без особого углубления в специфические детали.
Зачем нужнаMITM-атака наSSL
Чтобы просматривать и изменять вызовы веб-службы, используемой мобильным приложением, нам понадобится промежуточный прокси сервер для перехвата, созданный при помощи утилит навроде BurpSuite или ZAP. При перехвате SSL-трафика SSL-соединение прерывается на стороне прокси-сервера. Сертификат, отсылаемый прокси-сервером, анализируется мобильным приложением, как если бы прокси был оконечной точкой веб-службы. По умолчанию самоподписанный сертификат, генерируемые утилитами наподобие Burp, не будет принадлежать проверенной достоверной цепочке. Если сертификат нельзя проверить на достоверность, большинство мобильных будут обрывать соединение вместо того, чтобы подключаться и работать в потенциально незащищенном канале. Техники, представленные ниже, предназначены для одной цели – убедить мобильное приложение, что сертификат, отправляемый прокси-сервером, является достоверным.
Техника 1 – Добавление сертификата в хранилище пользовательских сертификатов
Самый простой способ избежать SSL-ошибок – обзавестись валидным и надежным сертификатом. Эта задача решается относительно просто, если вы сможете установить достоверный сертификат на устройство. Если операционная система доверяет вашему центру сертификации, то будет доверять и сертификату, подписанному центром сертификации.
В Android есть два встроенных хранилища сертификатов, которые отслеживают, каким центрам сертификации доверяет операционная система: системное хранилище (хранит предустановленные сертификаты) и пользовательское хранилище (хранит сертификаты, добавленные пользователями).
Сей факт означает, что, если мы имеем дело с приложением, которое работает в Android 6.0 и более ранних версиях, то можно просто добавить сертификат в пользовательское хранилище. Когда приложение пытается проверить достоверность цепочки для нашего сертификата, то обнаружит, что наш центр сертификации связан с достоверным хранилищем и, следовательно, будет доверять нашему сертификату. В более новых версиях приложение не будет доверять хранилищу пользовательских сертификатов. Чтобы решить эту проблему, нужно прописать такой уровень API и версию Android, чтобы приложение стало доверять пользовательским центрам сертификации. Мы будем редактировать атрибут «platformBuildVersionCode» элемента «manifest» в файле AndroidManifest.xml.
В коде выше в строке «platformBuildVersionCode=25» нужно поменять значение 25 на 23, а в строке platformBuildVersionName="7.1.1" значение 7.1.1 на 6.0.
После переупаковки приложения с обновленным файлом AndroidManifest.xml, доверие пользовательским центрам сертификации будет восстановлено.
Если в приложении будет проходить проверку только указанный сертификат, условия для успешного выполнения этой техники выполняются.
Техника 2 – Перезапись упакованного сертификата
Если после установки сертификата в пользовательское хранилище, изменении в настройках версии Android и успешном прохождении проверок при просмотре других ресурсов, защищенных протоколом SSL, все равно возникают ошибки, значит, разработчики внедрили дополнительные условия, которым должны удовлетворять достоверные центры сертификации. Если не забыли, в предыдущей технике внутри тэга trust-anchors добавлялся новый путь к сертификату. Подобный трюк может использоваться разработчиками для защиты приложений от перехвата SSL.
Если в приложении используется индивидуальная цепочка сертификатов, может сработать метод, связанный с перезаписью сертификата. Поскольку в некоторых случаях разработчики могут предусмотреть дополнительные методы для проверки достоверной цепочки, эта техника не гарантирует стопроцентного результата.
Рисунок 1: Перечень сертификатов, используемых приложением Рисунок 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, который отслеживает наше устройство:
[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
Теперь вы можете воспользоваться функцией для обхода технологии SSL pinning:
Техника 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-приложений и демонстрируют важность наличия нескольких способов проведения подобного рода исследований.
Читайте также: