Часто случается так что на необходимом сайте установлена защита от ботов. Например: QRATOR, Cloudflare, Akamai Bot Manager и пр. Можно потратить множество ресурсов на обход этих систем, но если у вашего ресурса есть мобильное приложение, то можно пойти другим путём. В подавляющем большинстве случаев мобильное приложение остается без защиты т.к. методы актуальные в браузерной разработке в мобильной не актуальны. В этой статье мы совершим атаку MITM на приложение [скрыто], узнаем эндпоинты по которым приложение получает данные и получим данные сами.
Важно что данное руководство немного не последовательно для того что бы объяснить с какими проблемами мы сталкиваемся и как каждую из них решаем.
Подготовка окружения
Мы будем использовать приложение для android т.к. с ним будет проще =)
Можно использовать любой удобный эмулятор или реальное устройство(для некоторых действий нужен будет root доступ)
Запуск эмулятора Android Studio
Для большей повторяемости я буду использовать виртуальное устройство Android Studio. Его установка не сложна.
Запускаем Android Studio и создаем пустой проект.
![](https://habrastorage.org/getpro/habr/upload_files/169/30a/087/16930a087f5990992a23c8affd4bd61b.png)
В меню Tools открываем Device Manager (1). Если список в окне Device Manager пуст, создаём новое устройство(2). Важно что в устройстве с Google Play не будет root доступа. В спике напротив названия устройства нажимаем кнопку Play (3).
Подготовка устройства
Для доступа по ADB обязательно нужно разрешить отладку по USB в настройках для разработчиков. Для открытия пункта "для разработчиков" нужно 7 раз тапнуть на номер сборке на экране "о устройстве" в настройках. На большинстве современных устройств при включении настроек для разработчиков отладка по USB уже активна, но лучше проверить
![](https://habrastorage.org/getpro/habr/upload_files/93f/cf8/d2c/93fcf8d2c1ef593451615c5a9d5f40f9.png)
Если вы использовали Android Studio то в директории с android sdk у вас есть папка platform_tools в которой лежит необходимая нам утилита ADB. Я для удобства прописал эту папку в переменную среды PATH.
MITM
У нас есть мобильное приложение и большое желание понять как оно общается с сервером. Можно было бы декомпилировать APK и копаться в Smali/Java исходниках, но зачем усложнять себе жизнь? Просто посмотрим какие запросы ходят на сервер почти как в девтулзах. Мы воспользуемся MITM атакой при помощи прокси. Что такое MITM? Краткое определение википедии
Атака посредника (человек посередине) — вид атаки в криптографии и компьютерной безопасности, когда злоумышленник тайно ретранслирует и при необходимости изменяет связь между двумя сторонами, которые считают, что они непосредственно общаются друг с другом.
Мы заставим трафик от приложения проходить через наш прокси который показывает нам все запросы и ответы.
В этой статье я буду использовать Burp Suite. Community Edition доступен бесплатно и обладает всеми необходимыми нам функциями.
Настройка Burp proxy
Открываем Burp и создаем проект с настройками по умолчанию. Переходим во вкладку Proxy и открываем Proxy settings. По умолчанию прокси устанавливается на localhost(127.0.0.1) на порту 8080 т.е. прокси может прослушивать только локальные подключения. Нам же нужно перехватить трафик с другого устройства.
![](https://habrastorage.org/getpro/habr/upload_files/0f3/15d/665/0f315d665ceedebfa10b1e5547147a86.png)
Изменим этот прослушиватель что бы проксировать трафик со всех интерфейсов (1, 2). Теперь установим корневой сертификат нашего прокси. Более подробно о сертификате я напишу далее. Экспортируем корневой сертификат burp(3). Выбираем экспорт сертификата в DER формате. Сохраняем сертификат с расширением .crt. Скидываем этот файл на устройство. На устройстве нужно установить наш сертификат. На всех устройствах он устанавливается по разному, но чаще всего достаточно написать в поиске по настройкам CA и выбрать пункт Установить сертификат. Устройство должно сообщить что пользовательский сертификат установлен. Настройка закончена. Burp готов принимать и проксировать входящие сообщения.
![](https://habrastorage.org/getpro/habr/upload_files/4a1/f95/24c/4a1f9524c75cedc0d821587a7f02ec81.png)
Устанавливаем прокси
Что бы наше устройство начало отправлять все запросы через прокси, его нужно указать. Сделать это можно разными способами, я приведу самые популярные.
При помощи ADB.
Что бы установить
adb shell settings put global http_proxy <адрес>:<порт>
Где <адрес> <port> это ip устройства и порт на котором запущен прокси сервер
Что бы отключить
adb shell settings put global http_proxy :0
2. Через настройки WiFi
![Процесс установки прокси через настройки WiFi Процесс установки прокси через настройки WiFi](https://habrastorage.org/getpro/habr/upload_files/72d/f51/f33/72df51f33d2a162f29c386386ac3942e.png)
3. Стороннее ПО. Я использовал ProxyDroid до того как нашёл способ установки через ADB. Для всех сторонних программ нужен root доступ
SSL Pinning
Прокси установлен и казалось бы всё готово, но если запустить приложение и смотреть историю http запросов в burp мы ничего не увидим. В dashboard'е же будут появляться логи certificate_unknown
![](https://habrastorage.org/getpro/habr/upload_files/218/84c/ee1/21884cee1a6fe22764cf9131ff699599.png)
Это происходит из-за того что приложение не может установить соединение из-за неизвестного SSL сертификата. И тут мы сталкиваемся с проблемой.
Если вы не знаете как работает SSL/TLS то вот упрощенное описание. Перед запросом клиент просит сервер идентифицировать себя, сервер присылает копию своего сертификата, клиент сравнивает сертификат с тем который должен быть у этого сервера.
Проблема в том что сертификат нашего прокси явно не совпадает с сертификатом сервера на который приложение посылает запросы. Раньше эту проблему можно было решить установив сертификат прокси на устройство в качестве доверенного(что мы уже сделали), но защита улучшается постоянно и сначала приложения перестали верить пользовательским сертификатам, а потом даже системным.
Сейчас приложение сверяет сертификат с тем который хранится в приложении и при несовпадении соединение не установится. Этот механизм называется SSL Pinning. Но ведь любая защита может быть взломана?
SSL Unpinning
Для нормального просмотра трафика нам нужно заставить приложение доверять пользовательским сертификатам. Сделать это можно разными способами. Я напишу о тех которые мне известны.
Патч APK файла
Можно декомпилировать приложение внести правки в исходный код и компилировать его обратно, но повторять этот процесс для каждого приложения напрягает. Если интересно можете изучить как работает утилита, о которой я пишу ниже, которая автоматизирует этот процесс .
apk-mitm инструмент с открытым исходным кодом под NodeJS. Для его работы вам нужно установить NodeJS. Установить apk-mitm можно при помощи npm, встроенного пакетного менеджера NodeJS, при помощи одной команды.
npm install -g apk-mitm
Процесс патчинга приложения сводится к выполнению одной команды.
apk-mitm <путь к apk>
Выполнение этой команды для крупных приложений занимает довольно много времени. После выполнения в папке с исходным apk файлом будет файл <исходное название>-patched.apk
Если у вас установлено исходное приложение, оно может не установится. Удалите исходное приложение и установите патченное.
После этих действий можно переходить к просмотру трафика
Инъекция патча в процесс приложения
В случае когда приложение не обфусцировано предыдущий метод работает отлично, но иначе приложение не соберется или не будет работать корректно.
Однако часто обфусцируется только код приложения и библиотеки по прежнему можно пропатчить при помощи инъекции кода в процессе работы приложения. Для этого будем использовать Frida. Этот инструмент позволяет выполнить пользовательский JavaScript код в процессе приложения.
Установить frida можно при помощи pip, пакетного менеджера python. Соответственно python не ниже 3 версии должен быть установлен (это последняя среда выполнения которая нам нужна?)
pip install frida-tools
Эта команда установит клиентскую часть frida, но нам также нужна серверная часть которая будет запускаться на устройстве. Сервер можно загрузить здесь: https://github.com/frida/frida/releases
Версия сервера должна соответствовать версии клиента и архитектуре устройства. Формат примерно такой:
frida-server-<версия клиента>-android-<архитектура устройства>.xz
Узнать версию клиента можно командой
frida --v
Узнать архитектуру устройства можно при помощи ADB
adb shell getprop ro.product.cpu.abi
Для меня необходимый файл сервера frida-server-16.1.4-android-x86_64.xz. Если подходящего файла нет можно использовать файл с другой патч-версией.
Этот файл - архив. Распаковать его можно при помощи 7-Zip (Windows) или The Unarchiver (Mac), если вы пользователь linux вы сами знаете что делать ?
Распакованный файл нужно закинуть на устройство в папку /data/local/tmp т.к. часто скрипты считают что запускаются оттуда
adb push ./frida-server-16.1.4-android-x86_64 /data/local/tmp/frida-server
Получаем доступ к терминалу устройства
adb shell
Получаем права суперпользователя
su
Выдаём права на выполнение
chmod 755 /data/local/tmp/frida-server
Запускаем сервер
/data/local/tmp/frida-server &
С этого момента сервер готов принимать команды. Мы будем использовать скрипт Universal Android SSL Pinning Bypass. Для корректной его работы необходимо азместить по пути /data/local/tmp/cert-der.crt корневой сертификат нашего прокси. Воспользуемся командой
adb push cert-der.crt /data/local/tmp/cert-der.crt
Перед запуском frida нужно узнать название пакета приложения. Найти его можно в адресной строке на странице в play market, экране "о приложении" или при помощи сторонних программ. Для wildberries идентификатор com.wildberries.ru
Frida позволяет запускать скрипты без скачивания. Выполним команду
frida --codeshare pcipolloni/universal-android-ssl-pinning-bypass-with-frida -f com.wildberries.ru
В консоли мы должны увидеть что то такое
![](https://habrastorage.org/getpro/habr/upload_files/63b/193/a14/63b193a14406f67586450a4662a492db.png)
А на устройстве откроется атакуемое приложение.
После этих действий можно переходить к просмотру трафика
Просмотр трафика
После того как SSL Pinning был преодолен мы можем открыть Burp. На вкладке Proxy -> HTTP History будет список со всеми запросами к серверу. Выбрав один из запросов мы увидим сырой HTTP запрос.
![](https://habrastorage.org/getpro/habr/upload_files/379/c67/6b4/379c676b4a6a7f6321676e6587a41e0c.png)
Нас может смутить что приложение передаёт в заголовках deviceId и deviceToken. В некоторых приложениях запросы подписываются специальным алгоритмом шифрования для подтверждения того что пакет сгенерирован приложением, но в нашем случае это не так. deviceId это идентификатор устройства который можно заменить любым UUIDv4 без "-". А изменение deviceToken не влияет на выдачу результата.
![Отправка запроса без deviceId и deviceToken Отправка запроса без deviceId и deviceToken](https://habrastorage.org/getpro/habr/upload_files/cff/5a7/e28/cff5a7e28ce047c8b95ff5b9f22066ed.png)
Итог
Полученных нами данных достаточно что бы собрать огромное кол-во данных в обход всякой защиты.
Данные получаются в красивом JSON.
Можем сэкономить на прокси
Но всё же злоупотреблять этим не стоит. Ведь если вы будете класть сервера сотнями тысяч запросов, то этот способ пофиксят =)
Всем удачной обратной разработки!
Подписывайтесь на мой Telegram. Там будет ещё много интересного)