Shape-Security-protection-reverse-engineering

Использование данного кода разрешено исключительно в рамках действующего законодательства.

Скрипт представляет собой NodeJS код, который эмулирует среду браузера (конкретнее, объект window) и решает защиту Shape Security. На выходе получаем JSON с заголовками для будущего запроса.

Для написания кода были использованы данные, которые предоставляет Starbucks при входе в личный кабинет (первый тег script, актуально на июль-август 2020). В настоящее время (сентябрь 2020) скрипт протестирован не был, возможны изменения. Компания Shape Security в своем решении использует адаптивную нейросеть (о чем сообщает на своем сайте), которая позволяет анализировать данные и эффективно находить аномалии в статистике, после чего успешно блокировать подозрительные запросы (ответ-блокировка сервера 302).

Более подробное описание работы защиты

В исходных данных имеем: несколько массивов, которые отвечают за порядок выполнения команд в обфусцированном коде и хранение зашифрованных строк; массив с элементарными функциями; статические действия. Все указания на код смотрите в shapesourcecode.js Исходные данные, их порядок и названия всех переменных/функций генерируются случайным образом при каждом запросе на страницу входа. Первым делом после запуска основной функции (см. function g(y)) происходит процесс создания среды для выполнения обфусцированного кода. Далее, после объявления всех необходимых переменных, запускается функция (см. function jF(jO)), выполняющая действия по указаниям массивов, содержащих порядок выполнения команд. Происходит дешифровка строк и их запись в объект (см. var x=q(null)). Устанавливается listener на XMLHttpRequest.prototype.send и выполняется первый сбор данных о клиенте.

Данные о клиенте представляют собой объект, который содержит информацию об используемом ПО, ОС и ПК. Проводится обнаружение средств автоматизации и другие тесты (canvas, т.п.)

При отправке запроса выполняется второй сбор данных, который записывает в данные о клиенте информацию о кликах, движении мышью, нажатиях на тачскрин и клавиатуру, прочих событиях. Непосредственно перед запуском данных в сеть производится кодирование SuperPack (с кастомным расширением) (собственная разработка Shape Security с ужасной документацией) и шифровка.

Работа решения защиты

Основная цель: получение объекта данных о клиенте и его подмена. Реализуется это при помощи инъекции в необходимую функцию. Такой подход требует достаточно много ресурсов CPU, поэтому рекомендуется использование worker_threads. Следующие далее кодирование и шифрование при необходимости можно заменить модулями NodeJS. Генерация уникальных данных является основной проблемой решения (возможно также моей как разработчика). Последняя версия скрипта использует примитивную MySQL БД для хранения и комбинирования пресгенерированных данных. Поскольку данное решение оказалось не самым хорошим, включать БД в репозиторий не планирую. Всего для сбора используется 35 элементов в массиве данных, каждый раз они генерируются в случайном порядке, зависящем от массива порядка выполнения команд. Это стало причиной тому, что скрипт Shape выполняется целиком.

Объяснение функциям worker.js

Основных две:

  • getShapeData, которая собственно и выдает решение;
  • generatePayload, находит в данных о клиенте нужные значения и подменяет их на значения с БД.

Дополнительные: тут стоит выделить только deserialize. Эта функция отвечает за преобразование значений с БД. В данных о клиенте используются значения, которые не сохраняет JSON, но которые должны передаваться на сервер (например undefined), поэтому использовалось собственное кодирование в виде строки, полученной от util.inspect.

Установка и запуск

Без БД скрипт требует доработки.

Установите зависимости. Для запуска используйте node API.js. На 127.0.0.1:44694 отправляйте JSON в формате: {"login":"","password":"","toEval":""} Логин и пароль произвольные. В toEval должны передаваться данные Shape (закодированные с помощью encodeURIComponent). Пример данных можно посмотреть в shapesourcecode.js

В ответ получаем JSON с параметрами:

  • status
  • X-DQ7Hy5L1-a
  • X-DQ7Hy5L1-b
  • X-DQ7Hy5L1-c
  • X-DQ7Hy5L1-d
  • X-DQ7Hy5L1-f
  • X-DQ7Hy5L1-z

X-DQ7Hy5L1-* это названия заголовков и их значения, нужно поместить в будущий запрос.

За помощь в реверсинге спасибо sonya75, который выложил в открытый доступ пример для более старой версии Shape Security на Python.