О чем материал
Поговорим о blackbox-атаках на банкоматы, способах защиты от них и обсудим, что происходит в области исследований безопасности банковского оборудования в целом
Защищенность ПО банкоматов увеличивается со временем, однако принцип «безопасность через неясность» накладывает на эту сферу определенный отпечаток. Прошивки не лежат в открытом доступе или шифруются, что, как мы увидим впоследствии, создает препятствия для легитимного аудита безопасности (впрочем, не препятствуя анализу со стороны злоумышленников). Зачастую даже специалисты из компаний, занимающихся аудитами безопасности в рамках платных официальных проектов, сталкиваются с сопротивлением при попытке сотрудничать или хотя бы сообщить о найденных уязвимостях. К счастью, к вендорам, присутствующим на современном отечественном рынке, это не относится.
Если сравнивать современное ПО с прошивкой французского диспенсера купюр от 2017 г., разумеется, прогресс в отрасли на лицо. Раньше можно было легко встретить программное обеспечение, в котором выдача купюр происходила после пары простых команд, не подразумевающих шифрование, знание секретов или аутентификацию. Сейчас производители обязательно закладывают какие-то механизмы безопасности — например, защиту от replay-атак, подпись сообщений или аутентификацию. Появились ИБ-стандарты, которые разработчики пытаются соблюдать.
Однако дьявол, как и обычно, кроется в мелочах. Пожалуй, самые распространенные в наше время проблемы — это ошибки в логике реализации и применении защитных механизмов. Но перед обсуждением деталей проблем безопасности по традиции рассмотрим внутреннее устройство банкомата и взаимодействие устройств в нем.
Как устроен банкомат
На тему устройства банкомата есть много шуток. Например, такая:

Но, к сожалению или к счастью, по факту внутри банкомата находится ворох бездушных машин. Логически он делится на две зоны — сейф и кабинет.
Кабинет находится сверху, в нем располагаются устройства, необходимые для взаимодействия с клиентом: чековый принтер, приемник купюр, презентер, кард-ридер, NFC-модуль, пинпад, камеры и, конечно же, ПК, через который происходит управление всем этим оборудованием.
Сейф находится снизу, он сделан из более толстого и прочного металла, и у него есть отдельная дверца, защищенная замком. В нем, как минимум, располагаются кассеты. Почему как минимум? Потому что мы пока что не упомянули самое важное оборудование — диспенсер и валидатор.
Случается, что диспенсер и валидатор вместе с кассетами полностью располагаются в сейфовой зоне, но так происходит не всегда. Это можно увидеть на фото банкоматов из различных статей (см. рис. 1). Как видите, дверца заканчивается на уровне кассет, а оборудование находится в зоне кабинета.

Валидатор — это техническое средство для проверки купюр на подлинность. Диспенсер — это, по классическим определениям, устройство выдачи купюр, включающее презентер и кассеты. Далее мы также будем использовать понятие «модуль рециркуляции»: в это устройство входят диспенсер, валидатор, кассеты и приемник (он же презентер для выдачи купюр). Оно применяется в банкоматах с опцией ресайклинга, которые позволяют снимать купюры, занесенные другими людьми.
Пока что рассказанное выглядит как мешанина из устройств :) Но, по сути, когда мы задаем вопрос «А что нужно, чтобы выдать наличные?», перечень необходимого оборудования сужается до диспенсера купюр, ПК и процессингового центра.
Взаимодействие ПК и устройств
Кстати, на рис. 2 (взят из другой статьи нашей компании) хорошо показан ответ на популярный вопрос: как получается, что у банка много разных банкоматов, но у них одинаковый интерфейс? Так происходит из-за использования стандартной библиотеки msxfs, являющейся посредником между софтом вендора и софтом банка.
Вендор делает свою прослойку для общения с железом, экспортируя код, который будет вызываться msxfs.dll. Банк делает свой киоск — тоже не с нуля, а используя продукты компаний, которые предоставляют соответствующие решения. Софт от банка при срабатывании определенных условий может достучаться до софта вендора через стандартизированные API к msxfs.
Поверхность атаки
Как же можно атаковать подобные системы? Возможные варианты давно придуманы, классифицированы и много раз описаны (см. рис. 3).
Проверки на возможность атаки с применением грубой силы, конечно, не входят в спектр предоставляемых нашей компанией услуг. Мошенничество не считается чем-то очень сложным технически, поэтому проверка безопасности по этому направлению не требует компетенций наших специалистов — банки и так в курсе об опасности и принимают меры. Мы же в основном концентрируемся на исследовании возможности атак, связанных с кибербезопасностью.
Разумеется, при наличии нескольких звеньев взаимодействия можно атаковать разные уровни и разными способами. Опять же, в нашей статье была чудесная иллюстрация, демонстрирующая разные точки приложения атак — поверхность атаки (см. рис. 4). Отметим, что атаками на сетевое оборудование и ПК занимаются соответственно специалисты по тестированию на проникновение и отдел исследования безопасности банковских систем. Мы же, как приглашенные на проект реверс-инженеры, акцентируем свое внимание на blackbox-атаках. Как видно на рис. 4, атака происходит непосредственно на оборудование при физическом доступе, минуя сеть и ПК.
Как подключиться к устройствам внутри банкомата
Пока что возникает больше вопросов, чем ответов. Почему-то интерфейсы диспенсеров и модулей рециркуляции не принято выводить наружу (к клиентам). Выходит, чтобы демонстрировать атаку, надо как-то забраться в зону кабинета и подключаться к ним оттуда? Зачем тогда исследовать то, до чего по идее нельзя добраться?
Внимательный читатель запомнил, что только сейф обладает защитой повышенного класса. Кабинет же не считается защищенным от взлома грубой силой, металл там более тонкий, иногда вообще бывают какие-то пластиковые заглушки или технические отверстия под устройства, которые можно использовать (на просторах интернета полно демонстраций с просверленными на фронтальной панели отверстиями). Ключи тоже считаются простыми, к тому же были случаи их успешной покупки на ebay. Один исследователь рассказывал, как вскрывал замок кабинета куском проволоки через вентиляционную решетку на задней стенке банкомата.
Заказчик обычно не заставляет нас всем этим заниматься. Для blackbox-атак мы утверждаем модель потенциального нарушителя, согласно которой у него есть доступ к кабинету. А затем, исходя из этой гипотезы, проводим аудит и пытаемся понять, можно ли заставить банкомат выдавать деньги.
По идее, можно еще смотреть векторы, связанные с валидацией купюр, но проекты обычно не очень длительные, поэтому до недавнего времени мы успевали проверять только самый приоритетный и наглядный для заказчика сценарий — выдачу наличных.
Конечно, еще стоит отметить, что для проверки гипотез мы внедряемся на уровень взаимодействия с устройством — всякие антивирусы, SoC и файрволы против такого не помогают.
Как получить прошивку устройства
Итак, с доступом к кабелям в кабинете и устройствам наподобие хабов все понятно. Что делать дальше? Очевидно, нужно анализировать прошивку на предмет наличия уязвимостей.
На самом деле, чтобы понять сам протокол взаимодействия, иногда проще смотреть даже не прошивку, а программное обеспечение, предоставляемое вендором, на ПК. Там могут встречаться символы, файлы с логами или использоваться величины, которые будет сложно восстановить, ориентируясь только на прошивку. Например, какая-то величина сравнивается со значением в NVRAM: откуда мы знаем, что там лежит? А в ПО вендора может оказаться, что передается простая захардкоженная строка — ничего больше.
Но без прошивки, разумеется, при анализе защищенности оборудования не обойтись. Можно пытаться достать ее разнообразными способами:
- Файловая система ПК
- Попросить дистрибутив / попробовать поискать на форумах
- Купить запчасти на Alibaba и т. п.
- Дамп flash-памяти
- Отладочные порты
Ошибки в прошивках устройств банкомата встречаются такие же, как и в других устройствах/системах. Например, встречаются бинарные уязвимости, даже переполнения на стеке и с выполняемым стеком. Криптографические алгоритмы используются, но реализация не всегда хороша (то есть присутствуют криптографические проблемы). И конечно же, встречаются логические уязвимости, позволяющие обходить установленные ограничения или пользоваться функционалом, которым по идее пользоваться должно быть нельзя.
Специфика лишь в том, что у потенциального атакующего цель будет не столько в закреплении в системе или повышении прав (хотя такие сценарии тоже возможны), сколько в моментальном проведении операции по нелегитимным выдаче или внесению денежных средств.
Но не будем голословными и посмотрим практические случаи. Вендоры уже исправили ошибки, и мы получили разрешение на рассказ о них.
Истории из аудитов безопасности
Байка 1
Итак, мы приехали работать и в рамках предварительного анализа нашли на жестких дисках ПК банкоматов файлы прошивок. Что интересно, под аудит было заказано два похожих банкомата (они не отличались по оборудованию в нижней части), прошивки на их ПК лежали идентичные, но в логах вендора мы заметили, что на втором устройстве модуль рециркуляции присылает номер версии, не совпадающий с тем, что значится в прошивке.
Нам повезло: можно было снять прошивку главной управляющей платы с spi-флеша. Это можно сделать с помощью прищепки и программатора — например, такого:

Так мы все-таки считали дамп актуальной прошивки. Так что, господа, лучше перестраховаться и получить прошивку разными способами, чем в середине исследования обнаружить, что разбираешь что-то не то ;)
По скрину из NeoProgrammer (см. рис. 6) реверс-инженеры могут проверить себя и попытаться отгадать прошивку по 40h байтам.

Базовый адрес даже не пришлось как-то специально вычислять. Он, с учетом небольшого смещения, был понятен из заголовков файлов обновления: там лежал адрес начала первой выполняемой инструкции.
Операционной системой оказалась Azure RTOS ThreadX, но крайне усеченная — возможно, очень старая версия. По характерным сигнатурам примитивов ОС ее удалось быстро опознать и восстановить, например, взаимодействие между задачами (что было крайне полезно для анализа).

Далее нас, как исследователей, интересует общение устройства с внешним миром. В рамках инициализации присутствовали менеджеры UART и USB: их можно было опознать по характерным регионам памяти, к которым идет обращение, или строкам (что, возможно, быстрее и проще).

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

И используемый кабель, ведущий к USB-хабу. И активный USB-трафик. И немного логи. Было принято волевое решение рискнуть и разбирать его!
Выяснилось, что при старте системы диспенсер и ПК устанавливают защищенное соединение и далее работают с использование шифрования.
В результате разбора протокола взаимодействия на этапе установления сессии была замечена интересная вещь. Смотрите, что происходит:
- ПК берет набор данных со своей стороны: строчку, две скрупулезно сгенерированные страшнейшей математикой величины для генерации будущего ключа, а еще передает от себя данные, используемые как бы для аутентификации.
- Модуль рециркуляции проверяет данные «аутентификации», генерирует (опять же, с помощью монструозных математических пасов) свои данные для формирования ключа и отправляет их вместе с некой захардкоженной строкой.
- Далее на основании данных ПК и модуля рециркуляции одинаковым алгоритмом генерируется общий ключ. Чтобы удостовериться, что все прошло гладко, отправляется сертификат — сообщение, зашифрованное на общем ключе.
Если все проверки пройдены, открывается доступ ко всем командам модуля рециркуляции.
А теперь, внимание, вопрос: кто мешает потенциальному атакующему сделать то же самое, что делает ПК? В кабинете можно получить используемые аппаратные характеристики, захардкоженные значения не меняются от системы к системе, а временные выставляются в любое произвольное значение? То есть, на первый взгляд, попытка организовать защищенную коммуникацию имеется, но с формированием ключей и взаимной аутентификацией возникает проблема.
Что можно сделать дальше:
- Установить защищенное соединение, отправляя свои данные и используя полученные величины от ресайклера
- По известному алгоритму сгенерировать вместе с ним ключ
- Обменяться сертификатами и отдать команду на выдачу наличных
- Готово: мы продемонстрировали заказчику целевой вектор!
Помимо этого, обычно мы смотрим еще и вектор выполнения произвольного кода — обновление прошивки.
При получении команды на обновление платы из заголовка файла прошивки, присланного в теле сообщения, проверяются:
- Сигнатура файла (разные значения для разных компонентов устройств):

- Имя устройства, чтобы удостовериться — точно пришло то, что надо:

- Размер присланного файла:

Есть еще проверка контрольной суммы, чтобы убедиться, что обновление точно пришло полностью:

То есть особых препятствий для генерации и загрузки своего файла обновления мы не встретили.
Насколько нам известно, после репорта вендор существенно переработал механизм установления защищенного соединения, серьезнее подошел к процессу генерации ключа, а также подписал и зашифровал прошивку.
Байка 2
Во втором случае мы исследовали оборудование вендора, с которым уже встречались раньше, однако это была новая для нас модель. Прошивку, как и в прошлой истории, доставали из файловой системы. Нам повезло: после других проектов у нас уже были наработки в части обновления прошивки, которые подошли к этой модели оборудования. Однако протокол общения с модулем рециркуляции в этой версии был другой, к тому же там не было уязвимости, через которую на схожем банкомате осуществлялась выдача наличных. Надо было срочно что-то придумывать…
Мы срочно восстановили протокол взаимодействия. Что интересного оказалось в этот раз:
- Для аутентификации сообщений использовался 3DES MAC или DES MAC на сессионном ключе. Сессионный ключ генерируется с помощью мастер-ключа. Плюс для защиты от реплей-атак есть секрет, который меняется после каждой успешной транзакции.
- В случае использования алгоритма 3DES MAC код формировался с помощью сообщения, секрета и соли, а для DES MAC — из сообщения и секрета.
- Захардкоженные ключи для 3DES MAC есть, но сброс до них возможен только при открытии сейфа (немного не подходит по модели нарушителя). Для DES MAC мастер-ключ захардкожен всегда, мы не знаем только сессионный, используемый в данный момент. Но по умолчанию использовался именно 3DES MAC.
Выбор алгоритма зависел от значения глобальной переменной mac_mode. Была интересная опция отключить защиту от атаки перебором при выставлении ее в 0.
Итак, мы отметили интересные факты. MAC не требовался для:
- смены сессионного ключа;
- смены целого набора настроек работы диспенсера;
- получения текущего используемого секрета.
А еще проверка при смене сессионного ключа DES MAC была очень интересной:
- банкомат не в сервисном режиме (сейф закрыт);
- mac_mode != 1, то есть текущий используемый алгоритм — не DES MAC (или DES MAC, но с отключенной защитой от атаки перебором).
Итак, следите за руками — что можно сделать:
- изучить структуру сообщений для команд на выдачу наличных (их требуется аж три);
- на всякий случай, мало ли что, изменить mac_mode (например, на 2);
- обновить сессионный ключ с помощью специальной команды.
Для этого необходимо было отправить сообщение, содержащее данные для формирования сессионного ключа. Сам ключ получался как DES MAC на мастер-ключе от этих данных. Кроме того, надо было отправить в том же сообщении преобразованную на новом сессионном ключе, жестко запрограммированную в прошивке строку. В свою очередь, модуль рециркуляции проверял, что результат преобразования над этой захардкоженной строкой с использованием нового сессионного ключа совпадает с присланной величиной (то есть демонстрируется знание мастер-ключа). Сменив режим на 1, можно запросить через штатную команду значение секрета. Затем отправить сообщение на выдачу наличных и полученный секрет вместе с MAC (рассчитанным с помощью установленного нами сессионного ключа). То есть потенциальный нарушитель может:
- Разобрать структуру сообщения для выдачи наличных.
- Отправить команду для изменения mac_mode, выставив его в 0 или 2.
- Обновить сессионный ключ для DES MAC.
- Отправить команду для изменения mac_mode, присвоив ему значение 1.
- Получить текущий используемый секрет.
- Отправить сообщение с командой для выдачи наличных и секрет, добавив рассчитанное от них значение DES MAC на свежеустановленном сессионном ключе.

Байка 3
Переходим к третьему герою нашего рассказа. Как и всегда, мы начали с физического осмотра банкомата и обнаружили внутри сейфа основную управляющую плату ресайклера.
Плата была выполнена на базе микроконтроллера STM32 — для нас это было отличной новостью, так как это распространенный и хорошо задокументированный чип. Более того, нам удалось успешно извлечь прошивку и установить, что она построена на основе операционной системы реального времени microC/OS. Это стало серьезным подспорьем: вместо анализа монолитной «голой» прошивки мы смогли сразу выделить отдельные задачи и быстрее понять, какие функции выполняет каждая из них. Тем самым мы получили понятную «карту» прошивки устройства.
Первоначальный анализ прошивки показал, что устройство использует несколько интерфейсов обмена данными: USART, USB, CAN и I2C. Помимо этого, указанная RTOS запускала около десяти различных задач. Для наших целей наиболее важными показались следующие:
- Main task, которая реализует центральную логику приложения.
- USB_receive и USB_send, которые отвечают за основной канал связи с ПК в кабинете.

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

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

Схема была похожа на ту, что мы анализировали ранее, но имела несколько важных отличий:
- Использовался только один режим работы — 3DES, и изменить его нельзя было.
- Не предусматривался слабый режим DES, который можно было бы использовать для даунгрейда.
- Проверка MAC требовалась только для трех типов сообщений: информация о купюрах, внесение и выдача наличных.
Таким образом, мы столкнулись с непростой задачей: для того чтобы заставить устройство выдать деньги, требовалось либо получить мастер ключ, либо знать текущий nonce и сессионный ключ, чтобы сгенерировать валидный MAC для команды выдачи. При этом прямая криптографическая атака в лоб на 3DES в данном случае выглядела крайне затруднительной.
На этом этапе мы сделали небольшой крюк в анализе. Оказалось, что ресайклер поддерживает функцию обновления прошивки, но по какой то неизвестной причине разработчики не используют проверку MAC для команд обновления прошивки.


Это, конечно же, был критический провал. Мы быстро собрали proof of concept (PoC), который эксплуатировал эту уязвимость, и с его помощью загрузили на устройство кастомную, специально подготовленную прошивку. Причем по своей сути она была до смешного простой: прошивка полностью отключала проверку MAC, всегда возвращая «успех». Одно это изменение уже позволяло произвольно инициировать выдачу наличных.
Когда мы вернулись к анализу самой проверки MAC, то обнаружили еще более серьезную уязвимость. Давайте еще раз пристально взглянем на то, как именно происходит проверка имитовставки сообщения:
- Данные поступают по USB и помещаются в буфер размером 2048 байт.
- Затем они копируются в глобальный буфер того же размера.
- Внутри функции check_mac они копируются третий раз — в локальный стековый буфер размером всего 640 байт.

Это классический, как по учебнику, пример переполнения буфера на стеке. Отправив пакет больше 640 байт, можно перезаписать адрес возврата функции на стеке и перехватить управление потоком выполнения программы.
Значит, пришло время разработать несколько более изощренный proof of concept. Наша цель заключалась не просто в том, чтобы «сломать» устройство, а в том, чтобы аккуратно заставить его выдать деньги.
Полезная нагрузка должна была быть максимально точной, что означало следующее:
- Первая задача: заставить функцию check_mac возвращать 1 (успех).
- Вторая задача: не нарушить работу основного приложения. Оно должно продолжать выполняться в привычном режиме, то есть состояние системы и содержимое стека не должно поменяться после выполнения нашей команды.
- Третья задача: не разрушить внутреннее представление данных и состояние устройства, так как его изменение не позволит произвести выдачу наличных.
Это потребовало более тонкой работы с памятью. В итоге мы разработали комбинированную цепочку с помощью техник Return Oriented Programming (ROP) и Jump Oriented Programming (JOP), которая перехватывала поток выполнения, подделывала успешную проверку MAC и возвращала управление в основной цикл программы. Вуаля — мы имеем работающий и недетектируемый способ извлечения наличных.
***
- Уровень защищенности банковских систем повышается, но производителям есть куда стремиться.
- Наблюдается улучшение во взаимодействии с вендорами, что дает надежду на продуктивное сотрудничество в сфере безопасности банковских систем.
- На фоне повышения уровня безопасности модулей рециркуляции, которым уделялось пристальное внимание на протяжении многих лет исследований, сейчас у ИБ-специалистов может начать оставаться время на изучение более разнообразного перечня устройств, функционирующих в банкоматах.




