Спойлер: soundtrack
Не удалось прогрузить медиа
Не удалось прогрузить медиа
Всех приветствую, моя вторая статья на этой площадке, но совершенно о другом. Предлагаю начать с маленькой предыстории, перед тем как начинать раскладывать все, что, зачем, да как? Порой, я делаю на заказ всякие финти-флюшки, чекеры, парсеры, и бла-бла-бла..- Список можно продолжать бесконечно, но наверное есть одна из головных болей, как у заказчиков (у них в первую очередь), так и у меня. Особенно при работе с чекерами, это капча, на первый взгляд, безобидная вещь, но знаете поговорку: "Чем дальше в лес, тем больше дров"? Так вот, это именно про неё, с одной стороны кажется, прикрутил простую капча-решалку условного Google RecaptchaV3 и чиллишь, которая по цене для заказчика 0.6$/1000решений, с одной стороны ты сделал свою работу, а заказчику? А заказчику тратить кучу денег на капчу. Да и не всегда, капчасолверы могут решать эту капчу нормально. У них есть понятие внутреннего score (еще внутренняя оценка пройденной капчи, на сколько ты робот, проверить себя можете
тут), а не все решалки гарантирует вам ПРОХОЖДЕНИЕ до нужно этапа, а лишь получени токена (на скор все срали с большой колокольни), и сиди перепроверяй тысячу сервисов капча-солверов, которые подойдут на нужный вам сервис. И меня порой тоже выводит гугл капча, прям бесит, я отмечаю ей все фонарики, велосипеды, гидранты, светофоры, машины, а ей хоть бы хны, говорит следующее:
Не удалось прогрузить медиа
Но ладно, приостановимся мы с этим обсуждением какие проклятые капчи, какой это рак интернета, и прочее, на эту тему можно чтива расписать на пару томов. Так вот, возвращаемся к сути нашей статьи, сегодня мы разберем с вами достаточно вещей, в рамках одного чекера, как и активную работу SOC'а, так и непонятные утечки, и декрипт (не бьемся палками) IOS-приложений и откуда их доставать, и чучуть про снифф (чет, я уже излюбленный нюхач, то карты нюхаем, то траффик поднюхиваем). Подопытным нашим будет, такой замечательный сервис как
optimum (кликабельно), если вкратце кто они, зачем они, то прошу, выдержка from google
Спойлер: что за оптимисты
Optimum is an American telecommunications brand owned and operated by Optimum Communications, formerly Altice USA. It is the fourth-largest cable provider in the United States and a Fortune 500 company. Optimum offers Internet, television, mobile and home phone services in 21 states.
Ну, а если на наш язык, то просто корпа, которая обеспечивает людей интернетом, мобильной связью, и телевизором в 21 штате. Является дочкой компании ALTICE, это важно запомнить, в будущем еще подтвердим это уже с технической части. Суть какова, нужен чекер+парсер, без капчи на валид, и плюсом чтоб еще фулл дату доставал. Ибо по рассчетам объема строк, на капчу можно было отваливать приличную кучу денег. Фантастика! Я в таких случаях обычно приступаю к сразу к делу, но не беру ни денег, ни-че-го, ни сроки не ставлю, ибо мне же надо понять смогу ли я вообще такое осилить или нет, понятное дело, что в таких случаях и я могу наложить в штаны, ибо вдруг потом клиент просто пропадет (а такое бывало), или уже другого найдет. Кароче, лучше остаться хорошим, чем взять денег и потом просто обнадежить человека, или аля кормить французским завтраком. Начать стоит с сайта, это, наверное, самое просто место где можно легко автоматизировать что-либо без каких либо запар и выкручивания себе мозгов. Заходим на сайт, страницу логина, и вроде как всё чисто..
Не удалось прогрузить медиа
Но фенита-ля-комедия, это лишь единоразовая акция, по входу без капчи, дальше нас ждет cloudflare turnstile. Ситуация плачевная, но можно подумать, раз первый раз дает зайти без капчи, может мы просто будем использовать ротационную проксю? Мысль, то верная, но я не видел особо крупных сервисов с пулами по 1кк юсы, и это может привести к бесконечноому кругу. Из разряда, прокси-капчи-ротейт_прокси-капча, кароче, идея херня, надежности 0, стабильности 0. И ничего тут не решишь одним разом по щелчку пальца, по этому этот вариант я отбросил куда подальше. И с моего СУБЪЕКТИВНОГО взгляда остается два варианта, ios app, android app. Так как я счастливая жертва маркетинга и сбора всей информации обо мне (это должно было быть перечеркнуто), то являюсь обладателем айфона, с которым я уже привык работать. Теоретически, идеальный план действий - это поменял регион App Store, скачал приложение, поставил снифф, и дернул (вынюхал) нужный нам запрос. Но знаете, будь все так легко, я бы не писал про это. Про то как сниффать траффик с приложений, я к счастью, или сожалению объяснять не вижу смысла, тема избита-перебита, и изнасилована. По этому приложу лишь пару ресурсов -
первая и
вторая. Если вкратце, то идея везде одна. Пропускам траффик с таким маршрутом:
Телефон <~> Компьютер <~> Сервер. Впринципе, грубо говоря сами себя подвергаем MiTM-атаке, но это очень грубо так говорить, но суть такова. Красивая пикча, которая ПОЧТИ подходит под наше объяснение.
Не удалось прогрузить медиа
Так вот, наш план-то, давайте попробуем реализовать и проверим, что происходит. Траффик я пропущу привычным методом для себя, через HTTP Toolkit. И приложу, так скажем, видео нашей проблемы. Объяснение для совсем маленьких: пока я подключен к WI-FI весь траффик проксируется через мой компьютер, а приложение оптимума при попытке логина кричит, что нихера, мы все видим, и не дадим ничего тебе скомубздить. И в качестве док-ва, что это правда так, переключаюсь на мобильную сеть, где оптимум, говорит, что всё отлично, пароль неверный лишь.
Не удалось прогрузить медиа
Телефон у меня один, ни чем нелегальным не занимаюсь, никого не бью, паяльники в жопу не сую, по этому и нужды во втором нет. По этому джаилбрейк, я себе не ставлю, не очень то уж и хочется рисковать камнем заместо телефона. А патчить приложухи, и тд я пока не умею, не особо сильный я реверсер пока, по этому. Переходим к плану ЦЭ (ну или просто С), осинт, осинт это наше все. Первое место куда я пошел, это гИтХаБ, самым тупым методом, самым прямолинейным по поиску названия приложухи. Нашел вот такое чудо.
Не удалось прогрузить медиа
И кажись, это наше маленькое микро-спасение.
Не удалось прогрузить медиа
Некий -
Abhimanyusinghpanwar , по факту сам за нас сделал всю работу, приложив чуть ли не все исходники приложения, меня, это конечно безмерно обрадовало. Я без понятия каким образом они там оказались, может какой-то индус устроившись в ЮСЕ, решил показать всем творения или еще чего, но это смехотворно, правда. Именно из-за этого я и получил основной толчок в написании чекера. И тут, давайте начнем признавать, что во всем этом сырборе разбираться самостоятельно, можно убить кучу времени, по этому, что было сделано? Правильно, был выкачан репозиторий и засунут нейронке, со словами, а разбериська, что тут, зачем и почему вообще. Наверняка вы начнете меня бить палками, говорить скрипт-кидди, чатгпт, кароче вся вот эта новомодная песня, но, простите, не пользоваться технологией, которая по-факту повышает кпд в разы - идиотизм. Гэпэтэ мне четенько разложил, это туда, это сюда, там сям, как обычно. Ну, и казалось мы на финишной прямой. Но что делать, если индуса не оказалось? А? Плакать и страдать..- А если серьезно, то приложить чуть побольше усилий. Существует такой замечательный сервис как decrypt.day, замечательный, безупречный, по другому не назвать. Вкратце, он отдает вам IPA приложения, которое вам нужно. Вставили ссылку из app-store, получили IPA, реверси, и убивайся до конца своих дней.
Не удалось прогрузить медиа
Я купил там сабку, стоит 3 бакса в месяц, но она 100% полностью окупает себя, ибо вы получаете мгновенный (практически, до 15 минут) декрипт IOS приложух без ограничений, за 3 месяца. Если вы как-либо углубляетесь в мобильный пентест, или еще какие-то такие вещи, то вам 100% нужно сюда, есть конечно и аналогичные сервисы, но там цены чутка подороже. И предлагаю с этого момента начать делать все тоже самое, что и чатгэпэтэ, получив исходники, только мы с вами будем отталкиваться лишь от полученной IPA. Грубо говоря, микрообучение реверсу IPA. Вообще, что такое IPA? Это, по сути, обычный ZIP-архив. Переименовываем расширение, распаковываем, и получаем такую картину.
Не удалось прогрузить медиа
У нас практически, всё, что нам нужно, и ничего лишнего. Я не буду рассказывать про какие-то заоблачные и тяжелые вещи по-типу иды, гидры и тд. Этим можно заняться в контексте уже абсолютной другой статьи более подробно. Нас интересует сейчас конкретно сбилженный бинарник самой приложухи.
Не удалось прогрузить медиа
Дергаем банально все читаемые символы из него, чтоб извлечь хоть какую-то полезную информацию для нас.
Code:
import re
with open('CustSupportApp', 'rb') as f:
data = f.read()
strings = re.findall(rb'[\x20-\x7e]{8,}', data)
for s in strings:
print(s.decode('ascii', errors='replace'))
Не удалось прогрузить медиа
Безусловно, куча мусора, куча всякой дичи, которая нам и даром не нужна. Но в самом бинарнике были зашиты 3 домена, а именно:
Code:
https://dev.cma.alticeusa.com/
https://cma.alticeusa.com/
https://stage.cma.alticeusa.com/
По субдоменам вполне понятно, дев для тестов, цма это прод, стейдж это препрод. Запоминаем стейдж, он нам еще сыграет на руку. И еще мы достаем полезную для себя вещь - ключ шифрования для SHA-256 HMAC, самое смешное, что он был в открытом виде, можно ли это называть дырой или нет, без понятия. Я не работал в биг-техах, тем более юсовских, по этому может быть у них это норма. Хотя по факту, ничего секретнего в нем нет, просто нужен для подписи и дополнительной защиты от таких полудурков как я. HMAC нашли опять же самым прямолинейным и тупым способом, порой не надо думать, что вы слишком много думаете, надо просто пробовать и все. Просто делаем grep в бинарке по hmac, и получаем сразу кучку текста.
Не удалось прогрузить медиа
Не тяжело предположить что, x-authorization-hmac это один из хедеров, а все остальное это свойства и стандартная функция из библиотек самих эпл. Хедер мы уже знаем, по этому давайте поищем, уже вокруг свойств. А именно hmacvalue, и тут уже мы находим сам ключик
Не удалось прогрузить медиа
Теперь давайте еще поищем вокруг нашего хедера x-authorization-hmac. И находим еще парочку заголовков.
Не удалось прогрузить медиа
Затем мне надо было найти, как вообще их выстраивают эти запросы они, немного поресерчив тут, там, по сусекам поскребав, находим, что за это все отвечает в целом _TtC14CustSupportApp14RequestBuilder, ну или просто RequestBuilder.
Не удалось прогрузить медиа
Помотав себя вокруг этих строк, достаем еще кучу информации.
Code:
[4706] _TtC14CustSupportApp14RequestBuilder
[4707] method
[4708] encoding
[4709] jsonParams
[4710] serviceKey
[4711] authHeaderAuthorization
[4712] deviceTokenHeader
[4713] homeBasedAuthentication
[4714] authHeaderMAUI
[4715] deviceMac
[4716] authorizationHmac
[4717] authorizationTime
[4718] firebaseAppCheckToken
[4719] application/pdf, application/octet-stream, application/json
[4720] application/json
[4721] application/zip, application/octet-stream
[4722] Basic Q01BLWlPUzpDTUEtaU9T
[4723] x-device-os-version
[4724] x-device-app-version
[4725] x-device-platform
[4726] kCFProxyTypeNone
[4727] _TtC14CustSupportApp27ProfileDetailsTableViewCell
[4728] imgStatus
[4729] profileIconLottieView
Еще три хедера, и судя по всему хедер для авторизации на 4722 строке. Интереса ради декодим его простым b64, и получаем птичку в клетке.
Не удалось прогрузить медиа
Напомню, ну, и наверное удивлю. Мы ни разу не включали иду, гидру, мы просто погрэпали, и погрэпали с огромным успехом. Собрали куча инфы, куча всего, этого уже хватает на всё, что можно, и всё что нельзя. Подведём микрочерту, микровывод, что мы сделали, и почему сделали. Итого, что мы имеем на данный момент, просто подёргав строки из бинарника. Три окружения - dev.cma.alticeusa.com для тестов, cma.alticeusa.com это прод, и stage.cma.alticeusa.com это препрод, его запоминаем. Готовый заголовок авторизации Basic Q01BLWlPUzpDTUEtaU9T, который декодится в CMA-iOS:CMA-iOS - OAuth2 client credentials для получения bearer-токена. HMAC-ключ n0dplzbsfn37f2s78jf9, который лежал в открытом виде прямо рядом с hmacValue в классе APIRequests, подпись через стандартный _CCHmac из Apple CommonCrypto, заголовок x-authorization-hmac. Рядом с ним ещё x-authorization-time - временная метка подписи, и x-firebase-appcheck - Firebase App Check токен, запомним, ещё аукнется. Плюс device-заголовки: x-device-os-version, x-device-app-version, x-device-platform. И полная структура класса RequestBuilder, который собирает все запросы - method, encoding, jsonParams, authHeaderAuthorization для Basic Auth. И всё это - без единого запуска IDA, Ghidra, или чего-то сложнее блокнота. Просто strings, grep, и голова на плечах. По сути мы уже знаем куда стучаться, чем авторизовываться, чем подписывать, и какие заголовки слать. Не хватает только формата самой HMAC-подписи, то есть что именно мы подписываем, и понимания как работает Firebase App Check. И пока отойдем на небольшой
Не удалось прогрузить медиа
Перекурили? Я лично, да, но как будто не до конца. Так вот, у нас осталось два больших вопроса. Первый, что именно подписывать HMAC-ом, то есть формат строки которая уходит на вход. И второй, что за Firebase App Check и насколько он нам может буквально поломать всю малину. Давайте по порядку. Формат HMAC-подписи из бинарника мы не вытащили. Ну, то есть, ключ есть, заголовок есть, алгоритм есть, а что на вход кидать - непонятно. Тут нам как раз помог тот самый репозиторий индуса, помните его? Abhimanyusinghpanwar, наш герой. В исходниках был файл APIRequests.swift, и там черным по белому написано как формируется строка для подписи. Формат такой - через двоеточие склеиваются HTTP-метод, эндпоинт, версия приложения, логин, пароль, и текущее время в ISO-формате. То есть грубо говоря POST:/api/auth/oauth/token:2.5.1.5:login:password:2026-03-25T12:00:00+0000. Всё это дело подписывается SHA-256 HMAC-ом с нашим ключом n0dplzbsfn37f2s78jf9, и результат летит в заголовок x-authorization-hmac, а время летит в x-authorization-time. Вот и вся магия, ничего сверхъестественного.
Не удалось прогрузить медиа
Оно заработало. Прямо на проде. Никакого Firebase App Check на тот момент не было. Просто шлешь запросы, получаешь ответы, чекаешь аккаунты. Красота, рай на земле, я накидал рабочий прототип, всё проверил, все летало, всё парсилось, аккаунты чекались, фулл дата доставалась, телефоны, вообще всё. Помните x-firebase-appcheck в RequestBuilder? На тот момент это поле просто было пустое, сервер его не требовал и не проверял. Но счастье длилось недолго. Когда начали активно чекать, в один прекрасный день прод начал требовать x-firebase-appcheck заголовок. Запросы без него стали возвращать ошибку. То ли они просто раскатили обновление которое давно планировали, то ли кто-то из SOC-команды заметил аномальную активность и ускорил закрытие дырки - не знаю. Но факт остается фактом - дверь закрылась.
Не удалось прогрузить медиа
И вот тут помните я говорил запоминаем stage.cma.alticeusa.com? Это препрод-окружение, тестовый сервер. И он, в отличие от прода, ещё какое-то время не проверял Firebase App Check. То есть, все тоже самое, тот же API, те же эндпоинты, те же данные (а данные там были боевые, не тестовые), только без этой головной боли. Переехали на стейдж (просто поменял домен), продолжили работать. Но через какое-то время стейдж тоже начал требовать Firebase. Видимо, подтянули конфигурацию под прод. А может и просто заметили кучу запросов с непонятных IP на тестовый сервер и выдернули вилку. В любом случае - второй побег не удался.
Не удалось прогрузить медиа
Обойти App Attest программно из питона - нереально. Это железячная проверка, привязанная к конкретному устройству и конкретному приложению. Нет никакого волшебного ключа который можно вписать в конфиг и все заработает. Капча солверов под такую штуку тоже нет. Единственный вариант который остался - достать этот токен руками. Открываем приложение на телефоне, перехватываем токен. Firebase App Check токен - это JWT, у него есть время жизни, ровно час. То есть раз в час надо обновлять его руками. Не автоматизируешь, не обойдешь, просто сиди и копируй. Звучит как бред, но это работает, а альтернатива - ничего. В итоге в чекер была добавлена простая логика. При старте он парсит JWT из конфига, достает оттуда exp (время истечения), показывает тебе сколько минут осталось до протухания. Пока токен живой - чекает. Как только токен протух - останавливается и говорит на какой строке остановился, чтобы ты мог обновить токен и продолжить с того же места. Костыль? Костыль. Работает? Работает. А что ещё делать, когда Apple, Google, и Altice вместе решили что тебе не надо.
Не удалось прогрузить медиа
Ну что, давайте подводить итоги всего этого безумия. Мы начали с того, что сайт закрыт капчей, мобильное приложение закрыто SSL-пиннингом, и вроде как оба пути в тупике. Пошли самым тупым путем, осинтом, нашли исходники на гитхабе, достали IPA через decrypt.day, выгребли всю полезную инфу через strings и grep без единого реверс-инструмента. Собрали рабочий чекер, покайфовали на проде пока было открыто, когда закрыли - переехали на стейдж, когда закрыли и стейдж - перешли на ручной Firebase-токен. Костыльно? Безусловно. Работает? Ещё как. И главное что я хотел донести этой статьей - не надо усложнять. Не всегда нужна ида, гидра, и три PhD по реверсу. Иногда достаточно strings, grep, и здорового упрямства. Ну и немножко удачи в виде индуса на гитхабе. Спасибо за внимание, не болейте.