Как спрятать мусор в базе Spotify и превратить это в квест

Опасный хакер прячет Spotify-код с секретной информациейОпасный хакер прячет Spotify-код с секретной информацией

Введение

Одной бессонной ночью мы с приятелем разговорились о Spotify-кодах.

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

Пример. Такая грусть у меня играет прямо сейчас.Пример. Такая грусть у меня играет прямо сейчас.

Мы решили разобраться, как же Spotify кодирует в них ссылки.

Как работают коды?

Выяснилось, что помимо меню «Поделиться» в приложении, есть официальный сайт Spotify Codes, который генерирует такие коды.

811929c43b1ba99706d7d2775419cb06.png

Если скопировать ссылку на картинку с этого сайта, получится что-то такое: https://scannables.scdn.co/uri/plain/jpeg/000000/white/640/spotify: track:5jxN9knH0vlfpN2Ft7a5xi

Прекрасно! Динамическая ссылка, которая принимает на вход ID трека и возвращает изображение с баркодом — самое то для наших экспериментов.

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

Числа в поле height — высоты столбиковЧисла в поле height — высоты столбиков

Первый и последний столбик всегда минимального размера, так что он, видимо, используется для ориентирования при сканировании, как и логотип Spotify, который на картинке всегда слева. Без них ничего не работает.

Важные данные выделены краснымВажные данные выделены красным

Получив число 556205622371746371156, приложение превращает его в 58992959842 с помощью таблицы Грея. Именно это делает распознаванием таким быстрым и устойчивым к ошибкам. Как узнали? К этому моменту мы уже набрели на патент Spotify, описывающий принцип работы таких кодов.

Остался последний вопрос: как же приложение превращает лаконичное 58992959842 вspotify: track:5jxN9knH0vlfpN2Ft7a5xi?

Очевидно, такое число не может вместить в себя все комбинации длинного цифро-буквенного ID, а значит никакого алгоритма нет и соответствие между кодом и ID трека хранится где-то в базе.

Можно проверить, подсунув генератору какой-нибудь очень длинный мусор, который точно не влез бы в число: https://scannables.scdn.co/uri/plain/jpeg/000000/white/640/spotify: track: thisisaverylongidentifierwhichwoulddefinitelyoverflowthatnumericcode

Сработало. Печально, а ведь было интересно научиться кодировать/раскодировать такие картинки полностью самостоятельно.

Решила проверить обмен приложения с сервером в момент распознавания и догадка подтвердилась:

На сервер уходит 58992959842, а возвращается трек 5jxN9knH0vlfpN2Ft7a5xiНа сервер уходит 58992959842, а возвращается трек 5jxN9knH0vlfpN2Ft7a5xi

Скука: дальше всё происходит за ширмой бэкенда. Расходимся?

Оченьдлинныймусор

Стоп, что? Генератор сделал картинку для оченьдлинногомусора?

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

Картинка с мусором из примера вышеКартинка с мусором из примера выше

А что будет, если считать такой код приложением?

Будет ошибкаБудет ошибка

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

Эм, что?Эм, что?

Великолепно. Spotify складывает в базу всё, что мы укажем в запросе к генератору, хранит это там, а при сканировании отдаёт обратно в первозданном виде, никак не валидируя.

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

Всё лучше под музыку

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

Я уже собралась реверсить обфусцированный код Android-приложения, чтобы узнать, как работает парсер, но приятель предложил попробовать разделять музыкальный ID и нашу полезную нагрузку знаком вопроса. Идея сработала, но знак пришлось дважды пропустить через urlencode. Например, spotify: track:2ctvdKmETyOzPb2GiJJT53%253Fhi, habr!, выглядит вот так:

Код с двойным дномКод с двойным дном

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

Выводы

Почему Spotify позволяет хранить в базе мусор? Вероятно, потому что генерацией и распознаванием кодов занимается отдельный микросервис, который должен отвечать моментально. Проверка на существование трека потребовала бы обращения к основному бэкенду, а это ресурсоёмкая задача.

Навредит ли это Spotify? Теоретически эта особенность позволяет заполнить таблицу соответствий кодов и исчерпать всю ёмкость, сломав генерацию картинок для настоящих треков, но на практике это займёт очень много времени. Я посчитала.

Полезно ли это на практике? Не знаю, как это использовать. Можете прятать номера телефонов любовниц в кодах с Егором Летовым и обклеивать ими стены, тогда ваша законная женщина покинет вас, сочтя сумасшедшим, будете свободны. Только имейте в виду, что запрос к API для считывания кода, к сожалению, требует авторизационный токен Spotify-аккаунта, в отличие от запроса для генерации картинки.

Оригинальный квест был здесь, послание было в Base64. Кто-то прошёл его за 42 минуты. На большее я не рассчитывала: имеющие привычку лезть в трафик приложений догадались бы сразу.

Помогал думать, предполагал хранение кодов в базе и решил добавить в ID знак вопроса приятель Эль.

© Habrahabr.ru