Исследователи информационной безопасности и охотники за багами часто сталкиваются с трудностью перехвата трафика приложений на 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.
Я скачал скрипт и настроил его, указав 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 - Хакер