September 11, 2019

Топ тупых лазеек для исследования конкурентов: mobile API

Введение

Почему-то последнее время я все чаще встречаюсь с тем что бэкенд разработчики не особо парятся об своих мобильных API. Может быть они считают что никто туда не полезет? Если вы считаете так же, то зря.

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

Изначально я не планировал писать о Кинопоиске, а хотел поигратся с мобильным апи сервисов такси. Банально выводить на карту в режиме онлайн машинки, но то что я нашел превзошло все ожидания. А история была бы совсем скучной и настолько тупой что и не заслужила бы попасть даже в эту подборку. Сказ о ней возможно будет в другой статье, после исправления уязвимости.

Пока я сидел и тихо офигевал от увиденного, один мой друг написал, что очень бы хотел базу фильмов (ну как у Кинопоиска, ага). Почему бы и нет? Так как у меня было всего 2 банки сидра, пачка сигарет, тупенький ноут, телефон не лучше и приблежающаяся ночь за окном... Я решил что рассказ об этом будет куда интереснее и взялся за дело! Под катом я расскажу как можно получить эти данные и не возится с парсингом HTML.

Классика MITM атаки

Само название подхода (man-in-the-middle) говорит само за себя. Грубо говоря, мы просто вклиниваемся в общение между приложением и API на сервере. Так как сейчас не 2007, и все уже научились устанавливать Let’s Encrypt, то нам понадобится добавить наш сертификат на устройство как доверенный, чтобы проксировать HTTP(S) трафик.

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

Для таких "интимных дел" мой люибый инструмент это mitmproxy. Качаем, ставим и поднимаем свой прокси. Да еще и сертификаты генерит! Что еще нужно? А когда-то я со squid'ом мучался... Кстати, после запуска сертификаты будут в ~/.mitmproxy, их нужно поставить на ваше устройство. Для андроида мне понадобится mitmproxy-ca-cert.cer. Перекидываем любым известным вам способом и добавляем в доверенные.

Подключаемся к одной сети с обоих устройств, вписываем IP адрес (порт не забудьте) нашего компютера. Теперь HTTP(S) запросы будут проходит через наш прокси, и мы легко сможем их мониторить\копировать и все такое. Вот мы и готовы к поискам золота и приключений.

Мониторим запросы

Открываем интересующие нас приложения, в моем случае это кинопоиск. Года 2 назад я уже игрался с ним, за это время они поменяли версию API и ключ.

Кстати раньше у них было что-то душевное, для версии 3.4.1 ключем было samuraivbolote.Тогда за ночь я выкачал всю базу с помощию домашних серверов и пула из 200 прокси. Использовал ее для игр с нейронными сетями.

Смотрим запрос на информацию о фильме. Что это тут у нас? Инкрементальные id. Божечки, как я люблю инкрементальные id. Пытаемся повторить запрос.

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

Отметил красными точками

Чудесно этой информации нам хватит для начала исследования. Мы уже знаем что можем перебирать id фильмов, что запросы подписываются, в подписи участвует время и судя по всему кусок самого запроса. А это значит что на сервере есть метод проверки этого ключа, и теперь мы его хотим. Пора разобратся со всем этим и заглянуть, что же там происходит внутри приложения.

Разбираем APK

Качаем apk файл этого приложения с любого более менее нормального сайта, найденного в гугле по запросу "download apk".

Вот этот вроде ничего, сойдет

Сверяем вресии. Вроде то, что нужно. Приступем к распаковке. Для этого я использую несколько инструментов, давайте начнем с самого простого и удобного - Jadx. Переходим по ссылке и ставим. Так как я счастливый пользовать Arch, то поставлю его из пакетов.

Распаковываем apk, и получаем древо директорий с декомпилированным и поэтому обфусцированным кодом. Вроде как декомпиляторы для Java не очень стабильные (может кто расскажет больше?), и некоторые части могут быть с ошибками или не восстановлены или восстановленны не верно. Что порождает кучи мусора.

Это та еще помойка, но мы уже знаем, что будем искать. Разбираем наш запрос по уникальным кусочкам. Думаю вы согласитесь что самое актуальное и уникальное это имя метода. Грепаем...

grep -r "getKPFilmDetailView" ./unpack/sources/

Отлично! Что-то нашли. Открываем и смотрим, что там...

Ага, список методов. Беглый осмотр соседних файлов не дал никаких результатов. А раз не дал, значит, мы не нашли место формирования запроса. Что же, мы зашли немного не туда, но эта ситуация подсказыват нам следующий шаг. Грепаем по request в уже интиресующей нас директории.

grep -r "request" ./unpack/sources/ru/

Среди всего мусора находим что-то интересное. Я, конечно, не эксперт, но это похоже на функцию подписи URL запроса.

grep -r "UrlSigner" ./unpack/sources/ru/

Вынесли в отдельный пакет. Похоже мы нашли, что искали. Переходим в директорию и изучаем содержимое.

Ну явно что-то полезное...

Ага, вот и наш сигнер, еще и стратегии есть, неплохо. Смотрим дальше.

Код надо понять. Компилятором. Я его дам. Запрос нужно подписать Ключом. Ключ я не дам.

Ага это явно то что мы искали. Сначала я испугался множеств кривых операций, и хотел подключить этот метод из jar файла. Но потом поработав с Procyon и CFR, все встало на свои места. Не буду расскрывать какой секретный ключ, намекну лишь что если вы знаете некоторые известные алгоритмы и немного увлекались необратимым хэшированием, то быстро поймете что делать.

Кстати, javadecompilers.com вам в помщь, там есть все основные инструменты и даже ничего не нужно ставить.

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

Мы были правы в функции генерации подписи участвуют URL запроса с GET параметрами, timestamp и ключ. Проверяем:

Кто сказал что php ни на что не годен?

Подпись совпадает с подписью из запроса! Это хороший знак. Давайте проверим это в действии. Так как время уже позднее, то мне лень писать код. Воспользуемся возможностями Postman и напишем небольшой "Pre-request script". Поместим необходимые параметры в переменные и используем их в заголовках. Кусок с URL просто захардкодим, и так сойдет.

В комментарии метод генерации md5 скопированный с stackoverflow
Расскажите потом как вам фильм (:

Чтож это победа. Ключ подходит, методом тыка можно исключить кучу не влияющих на ответ заголовков. Что касается параметра uuid, я сгенерировал пару случайных, и ничего не изменилось. Перебрал парочку ID фильмов, все хорошо работает. Теперь можно писать скрипт для обхода и собирать свою базу фильмов. А я пожалуй пойду спать.