Автор оригинала: Robin M.
Эта история начинается у кофейного автомата вроде этого…
Кто-то обронил, что в кофемашине есть микрофон, и мне стало интересно. Я скачал сервисное руководство той марки, перед автоматом которой стоял.
И вот он, на схеме: обозначение микрофона на плате! Я написал в сервисную компанию и спросил, зачем он нужен. Мне ответили, что это задел на будущее: датчик присутствия и движения для энергосбережения и доступности, который не реализован и не используется. Все просьбы разрешить изучить вопрос подробнее отклонили 🙁
Но на помощь пришёл eBay! Там продавался такой модуль, и не слишком дорого, так что я решил рискнуть. Ник продавца, mrhankey91, стал забавным бонусом к этой истории.
Экран приехал в мою «лабораторию», посмотрим, что там внутри.
Разобрав руководство, надписи на плате и кое-что додумав, я пришёл к таким выводам:
-
RS485 — питание 24 В и модуль заваривания кофе;
-
MDB — модуль (бесконтактной) оплаты;
-
CUP — модуль подачи стаканчиков;
-
CAN — модуль энергосбережения;
-
RS232 и инфракрасный порт: EVA-DTS — стандартизованный Европейской ассоциацией вендинга интерфейс для считывания данных автомата через трёхконтактный джек или IrDA;
-
Escrow+door — датчик двери, обнаружение стаканчика, подсветка, приём денег и выдача сдачи;
-
AUX — датчик движения (PIR), динамик, микрофон;
-
Micro-HDMI — дополнительный экран;
-
Mini USB-B — Ethernet-гаджет для загрузчика через TFTP;
-
Ethernet — связь с базой: статистика и неисправности;
-
карта Micro SD — дополнительное хранилище или обновление ПО;
-
USB-A — порт для обновления ПО;
-
процессор i.MX 6: ARM Cortex A9;
-
старое ядро Linux 2013 года;
-
сборка Yocto;
-
ПО автомата и дисплея 2021 года;
-
ПО для учёта и передачи данных об использовании, ошибках, перерывах в обслуживании и т. п.;
-
есть микшер ALSA для обработки звука;
-
ПО для GSM-модема;
-
скрипты обновления через USB;
-
слот в стиле Mini PCIe / mSATA: под GSM-модуль (тоже для связи с базой: статистика и неисправности).
Проследив дорожки от нескольких конденсаторов, мы подали 24 В на нужные контакты, и плата с экраном включилась:
Через некоторое время появилось сообщение об ошибке: плата (что понятно) не может найти остальную часть автомата.
Немного покопавшись, мы нашли отладочный порт:
Щупами можно выяснить, на каких контактах во время загрузки появляется сигнал.
Проверка разъёма показала нечто похожее на сигнал UART 3,3 В во время загрузки:
-
RX — контакт 4, TX — контакт 5, GND — контакт 8;
-
скорость 115200, 8N1.
Чтобы получить консоль устройства, хватило подключить UART от Raspberry Pi с подходящими уровнями 3,3 В.
Видео загрузки: https://www.youtube.com/watch?v=w7k3NLBj1to
Консоль U-Boot во время загрузки не была защищена паролем и позволяла менять командную строку ядра. Ничто не мешало загрузиться с init=/bin/sh.
Достаточно в нужный момент нажать клавишу, чтобы прервать U-Boot. Через setenv можно попасть в оболочку сразу после загрузки ядра:
setenv bootargs console=ttymxc0,115200 root=ubi0:imx66 rootfstype=ubifs init=/bin/sh
После этого можно смонтировать файловую систему, сменить пароль root, перезагрузиться и войти под root…
[хакерским голосом] Я внутри…
Что я нашёл:
-
/etc/udev/rules.d/automount.rules— что делать, когда вставлен USB-накопитель; -
/etc/udev/scripts/mount.sh— проверяет, есть ли на USB-накопителеautorun.sh; -
/usr/setupscripts/validate_autorun.sh— проверяет, чтоautorun.sh— допустимый скрипт обновления:
#!bin/shAUTORUNPATH=$1CONSOLE_OUTPUT=/dev/ttymxc0ORG_MD5="$(md5sum $AUTORUNPATH/autorun.sh)"set -- $ORG_MD5NEW_MD5="$1"“[REDACTED_SECRET]"RESULT="$(echo -n "$NEW_MD5" | md5sum )"set -- $RESULT#echo "calc hash: $1" > $CONSOLE_OUTPUTCMP_MD5="$(cat $AUTORUNPATH/hash.txt | cut -b-32)"#echo "read hash: $CMP_MD5" > $CONSOLE_OUTPUTif [ "$1" = "$CMP_MD5" ]; then echo "executing $AUTORUNPATH/autorun.sh" > $CONSOLE_OUTPUT if [ ! -x $AUTORUNPATH/autorun.sh ]; then chmod a+x $AUTORUNPATH/autorun.sh fi $AUTORUNPATH/autorun.shelse echo "authentication failed, ignored" > $CONSOLE_OUTPUTfi
Обратите внимание на $AUTORUNPATH и на то, что hash.txt ожидается в той же папке, что и autorun.sh. Значит, и сам autorun.sh, и хеш для его проверки лежат на USB-накопителе! Вместо нормальной криптографической подписи кода механизм обновления использует самодельную проверку целостности с ключом. Секрет, зашитый в файловую систему, склеивается с MD5 от autorun.sh, результат хешируется ещё раз и сравнивается со значением из hash.txt. Поскольку секрет для проверки лежит на самом устройстве открытым текстом, доступ к файловой системе позволяет атакующему повторить вычисление и собрать валидный пакет обновления.
Но как добраться до USB-порта?
Видео: вскрываем замок автомата — https://www.youtube.com/watch?v=QJYCAjgUM0g
И что же мы сделали с этой новообретённой силой?
Проверим, не подслушивает ли нас автомат. Для этого напишем простой shell-скрипт на инструментах, которые уже есть на устройстве. Но нужно проследить, чтобы не сработал watchdog, обработать ошибки, как-то показывать ход работы и момент, когда скрипт закончил проверки, записал результаты на USB-накопитель и его можно вынимать. Скрипт должен:
-
приостановить штатную программу (иначе автомат может зависнуть или перезагрузиться);
-
выяснить, какое оборудование и ПО установлено (драйверы, номера версий и т. п.);
-
проверить, есть ли модем, Wi-Fi или другое сетевое подключение;
-
проверить, может ли устройство воспроизводить звук;
-
проверить, может ли оно записывать звук;
-
показывать ход работы набором картинок и сохранить все результаты на USB-накопитель;
-
возобновить штатную программу.
Видео: скрипт с USB-накопителя проходит свои проверки — https://www.youtube.com/watch?v=XPitV76NglE
Так подслушивала кофемашина или нет?
Ничто на это не указывало. На оборудовании, которое мы изучили, в большинстве конфигураций нужного звукового железа не было вовсе. Более крупный вариант дисплея и контроллера, судя по всему, звук поддерживать мог, отсюда и упоминания микрофона в сервисной документации, но признаков того, что запись звука реально используется, мы не нашли.
Но… теперь пора ответить на извечный вопрос…
Совместимость программ зависит в первую очередь от архитектуры процессора, пользовательского ABI и библиотек, которые есть в системе. Здесь на плате процессор ARM Cortex-A9 и довольно старое пользовательское окружение с glibc 2.18. Старое ядро Linux 3.10.17 само по себе проблема меньшая: обычные пользовательские программы не нужно собирать под конкретную версию ядра, если они обращаются только к тем интерфейсам ядра, которые оно поддерживает.
Обычно для такого встраиваемого железа берут родной BSP (Board Support Package) или SDK с подходящим кросс-компилятором, библиотеками и заголовками. К сожалению, исходной среды разработки для этой заказной платы у нас нет. Пересобрать исходное окружение Yocto тоже оказалось непрактично: старые рецепты ссылаются на множество сторонних проектов и адресов с исходниками, часть которых по прежним адресам уже недоступна.
К счастью, DOOM портирован практически на всё. Есть порт fbDOOM, который рисует прямо в кадровый буфер Linux, а на этой плате рабочее устройство кадрового буфера есть. Зависимостей в пользовательском окружении у fbDOOM очень мало, так что для такой старой системы он хороший кандидат.
Остаётся libc. Бинарник, собранный в современной системе Linux, обычно ждёт glibc намного новее, чем версия 2.18 на кофемашине. Поэтому один вариант — кросс-компилировать fbDOOM в статически слинкованный бинарник с совместимой libc, чтобы он почти не зависел от библиотек, установленных на автомате. Другой — привезти с собой совместимое пользовательское окружение и явно вызвать его динамический загрузчик. В любом случае так можно собирать программу в современной системе и всё равно получить бинарник, который запустится в этом куда более старом окружении ARM.
И вот результат.
DOOM на тестовом экране в лаборатории: https://www.youtube.com/watch?v=G0dT6XedYFo
А ещё он запускается с подготовленного USB-накопителя. DOOM на кофейном автомате: https://www.youtube.com/watch?v=-mg8aKatJZE
ссылка на оригинал статьи https://habr.com/ru/articles/1106406/