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

Название приложения будет скрыто, допустим, приложение называется XYZ.

Настроив Burp Suite прокси на телефоне / эмуляторе и попытавшись перехватить трафик приложения, я не добился никаких результатов.

Я попытался войти в систему, чтобы увидеть любые запросы входа или обращения к API приложения, однако ничего не появилось.

Теперь мне было необходимо декомпилировать приложение, чтобы понять, на каком языке оно написано. Для этого я использовал инструмент APKTool.

Так как приложение было установлено на моём телефоне, мне потребовалось перенести его на компьютер с использованием утилиты Android Debug Bridge (ADB). Я запустил сервер Frida и перечислил установленные приложения.

firda-ps -Uia


adb shell pm path com.xyz.iq

adb pull /data/app/~~xxxxxxxxx==/com.xyz.iq-xxxxxx==/base.apk

Теперь, чтобы выяснить, на каком языке программирования разработано приложение, я воспользовался инструментом APKTool.

apktool d base.apk

I: Using Apktool 2.10.0 on base.apk with 6 thread(s).

I: Baksmaling classes.dex...

I: Baksmaling classes2.dex...

I: Loading resource table...

I: Decoding file-resources...

I: Loading resource table from file: C:\Users\2020\AppData\Local\apktool\framework\1.apk

I: Decoding values / XMLs...

I: Decoding AndroidManifest.xml with resources...

I: Regular manifest package...

I: Copying assets and libs...

I: Copying unknown files...

I: Copying original files...

I: Copying META-INF/services directory

Увидев папку C:\\Users\\2020\\Desktop\\XYZ\\base\\assets\\flutter_assets, я убедился, что приложение написано на Flutter.

Примечание: Существует несколько способов определить язык, на котором написано приложение:

  • Если вы видите файл с именем libflutter.so: приложение написано с использованием Flutter.

  • Если вы видите файл с именем libreactnative.so или librnjni.so: приложение написано с использованием React Native.

  • Если вы видите файл с именем libmonodroid.so или libmonosgen-2.0.so: приложение написано с использованием Xamarin.

  • Если вы видите файл с именем libil2cpp.so: приложение использует Unity (обычно игра).

  • Если файлы .so имеют нестандартные имена (например, libmygameengine.so) и отсутствуют библиотеки основных фреймворков: вероятно, это нативное приложение на Java/Kotlin, с высокопроизводительными частями, написанными на C/C++.

После долгих исследований я нашёл рабочий способ перехвата зашифрованного трафика (HTTPS) в приложениях на Flutter с помощью Burp Suite.

frida-flutterproxy

Я скачал скрипт и настроил его, указав IP-адрес и порт моего Burp Suite.

Затем я запустил приложение и скрипт с помощью Frida.

frida -f com.xyz.iq -l script.js -U

Итак, вернёмся назад, попробуем снова залогиниться и посмотрим, появится ли теперь нужный нам трафик.

Трафик успешно перехвачен. Я создал аккаунт и изучил работу приложения, пытаясь подробнее в нём разобраться.

Изучая приложение, я выявил ряд проблем, но ни одна из них не была критической. Меня интересовали исключительно серьёзные, высокоприоритетные уязвимости.

Разобравшись, как работает приложение, я перешёл к следующему этапу.

В качестве цели я выбрал функцию восстановления пароля («Forgot Password»), ввёл номер своего телефона и, к моему удивлению, полученный мной код подтверждения состоял всего лишь из четырёх цифр!

Я ввёл полученный код и внимательно наблюдал за происходящим.

Приложение проверяет введённый одноразовый пароль (OTP), и если тот окажется правильным, создает уникальный идентификатор (UUID), который используется в дальнейшем для смены пароля через соответствующий API endpoint.

Понимая, как осуществляется смена пароля, я осознал, что одноразовый код всего из четырех цифр легко взломать перебором всех возможных комбинаций — от 0000 до 9999. Всего получится около десяти тысяч попыток, что вполне реально.

Я снова нажал «Forgot Password» и повторно указал свой телефон. Получив новый одноразовый код, я ввел случайные данные и отправил запрос в Burp Suite «Intruder». Там я настроил автоматический перебор всех числовых комбинаций от 0000 до 9999.

Тут началось самое интересное: оказалось, что сервер ограничивает доступ к учётной записи уже после тридцати неудачных попыток ввода, блокируя IP-адрес на одну минуту.

Кроме того, сам одноразовый код действителен всего десять минут.

Тут возник вопрос: как успеть перебрать все возможные варианты кода?

Мне пришла идея: почему бы не воспользоваться прокси-сервером? Ведь я мог использовать сразу сотню разных прокси, каждый из которых отправлял бы по тридцать запросов.

Я обратился за советом к ChatGPT...

Получается, нужно минимум 300 прокси-серверов, а лучше побольше.

Я начал искать бесплатные быстрые прокси, потому что медленные не принесут должной пользы.

Свежие списки бесплатных прокси можно найти на GitHub, я отобрал только новые и собрал их в текстовый файл.

Теперь у меня более тысячи прокси-серверов, и моя задача — выбрать из них самые быстрые.

Для этого я обратился к ChatGPT с просьбой подготовить скрипт, который сможет проверять работоспособность каждого прокси и определять его скорость. Скрипт должен обращаться к серверу приложения XYZ по адресу «https://api.xyz.iq/api/v1/».

Скрипт сработал успешно: он проверил все прокси, отобрал самые быстрые и сохранил их в новом файле «fast_proxies.txt».

После этого я обратился к DeepSeek (так как он выдаёт более качественные результаты).

Запрос:

I have this request:

POST /api/v1/vendor/auth/verify-password HTTP/2

Host: xyz.com

User-Agent: Dart/3.8 (dart:io)

Content-Type: application/json

X-Heeiz-Api-Key: h#SDMqUFmFn)rrHj,VEVS19h,[@etW

Accept-Encoding: gzip, deflate, br

Content-Length: 44

{"phone":"+9647818xxxxxx","otp_code":"1111"}

Write me a script in Go language that allows me to try OTP codes from 0000 to 9999.

Each IP has 30 attempts, then it switches to another IP, and so on in a loop.

The proxies should be taken from a file named fast_proxies.txt in the format: IP:PORT.

When the response status is 200, stop the attack.

Скрипт прошёл тестирование и успешно отработал.

Я вновь воспользовался функцией «Forgot Password»: ввёл свой номер телефона и получил одноразовый код подтверждения (OTP) — 8638.

Затем я запустил подготовленный скрипт через ранее отобранные прокси.

Блокировка по IP-адресу была успешно обойдена, а одноразовый код правильно подобран.

Таким образом, я смог получить уникальный идентификатор (UUID), благодаря которому можно изменить пароль любого зарегистрированного пользователя буквально за считанные минуты.

Еще больше познавательного контента в Telegram-канале — Life-Hack - Хакер

Комментарии (0)