Введение

В данном отчете представлены результаты исследования головного устройства Mercedes-Benz, проведенного нашей командой. Последняя версия головного устройства (информационно-развлекательной системы) Mercedes-Benz называется Mercedes-Benz User Experience (MBUX). Мы проанализировали версию MBUX первого поколения.

Система MBUX уже была ранее проанализирована компанией KeenLab. Ее отчет можно использовать в качестве отправной точки в изучении внутреннего устройства MBUX и архитектуры системы.

В нашем исследовании мы сосредоточились на детальном анализе подсистем MBUX первого поколения, которым не было уделено должное внимание в исследовании KeenLab: диагностика (CAN, UDS и т. д.), подключения с использованием USB и специализированные протоколы межпроцессного взаимодействия (IPC).

В основе этого отчета лежат результаты профессиональной исследовательской работы Раду Моцпана, Кирилла Нестерова, Михаила Евдокимова, Полины Смирновой и Георгия Кигурадзе, которые провели исследование и обнаружили уязвимости.

Отдельная благодарность компании Mercedes-Benz Group AG за профессионализм и оперативный подход к работе с выявленными уязвимостями.

Диагностическое программное обеспечение

Чтобы получить первое представление об архитектуре автомобиля, полезно воспользоваться диагностическим ПО (доступным только лицензированным пользователям) для сканирования электронного блока управления (ЭБУ), определить его версию и протестировать работу диагностических функций, предлагаемых этим ПО. Существует несколько диагностических инструментов, позволяющих подключаться к автомобилю с использованием различных схем связи. В нашем исследовании мы воспользовались комбинацией диагностических инструментов: специальным аппаратным интерфейсом и соответствующим ПО для связи с автомобилем при помощи дополнительного устройства. Такой набор позволяет установить связь по протоколу DoIP (Diagnostic Over Internet Protocol):

Связь между диагностическим ПО и аппаратным обеспечением

Связь по протоколу TCP между диагностическим инструментом и диагностическим устройством осуществляется по Ethernet с использованием определенных протоколов (Protocol Data Unit, PDU). На первом этапе диагностическое устройство использует специальный протокол на основе ASCII (CSD). Он служит для аутентификации пользователя, проверки версий, настройки конфигурации и предоставляет исходную среду для работы протокола верхнего уровня (PDU).

Протокол верхнего уровня имеет бинарный формат. Он используется для отправки сообщений Universal Diagnostic Services (UDS), установления связи по протоколу DoIP и т. д. Для анализа этого протокола мы использовали скрипт на языке LUA:

[pduparser.lua]. Этот скрипт позволяет легко отличить команды UDS от обычного сетевого трафика между диагностическим ПО и аппаратным обеспечением:

Мы изучили интерфейс диагностического инструмента и расшифровали трафик, что позволило нам выявить различные команды UDS, такие как сброс параметров ЭБУ, выключение двигателя и блокировка дверей.

Архитектура

MBUX имеет следующую структуру:

Основными компонентами MBUX являются:

MMB (Multi Media Board) — основной модуль головного устройства (ГУ), содержащий все подсистемы;
BB (Base Board) — модуль с микросхемами, реализующими различные виды коммуникации по сети;
CSB (Country Specific Board) — отдельный модуль, взаимодействующий с MMB через внутренний канал Ethernet;
RH850 — модуль, предназначенный для обеспечения связи между низкоуровневыми шинами.

Полная информация об архитектуре MBUX приводится в исследовании KeenLab.

Тестовые стенды

Для нашего исследования мы использовали:

реальный автомобиль — Mercedes B180;

установку для тестирования — нашу собственную платформу для тестирования аппаратного и программного обеспечения, которую мы разработали для целей данного исследования.

Защита от угона

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

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

Встроенное ПО

Модуль MMB работает под управлением Linux, а его файловые системы расположены на карте eMMC. Нам потребовалось выпаять eMMC из печатной платы. Чип содержал несколько разделов:

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

Распаковка обновления

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

Несколько устаревших файлов обновлений все еще можно найти в интернете. Типы файлов обновлений можно разделить на следующие группы по их названиям:

файлы с *ALL* содержат файлы *.CFF, *.SMR-F и *.bin.
файлы с *CFF* содержат только файлы *.CFF.
файлы с *SMR-F* содержат только файлы *.SMR-F.

Как правило, файлы *.bin являются контейнерами с определенной файловой структурой и могут сжиматься с помощью zlib или других методов.

Файлы *.SMR-F сжаты, а также имеют собственную файловую структуру. Помимо обычных текстовых метаданных, они также содержат зашифрованные данные, для расшифровки которых диагностический инструмент использует свои общие библиотеки. После расшифровки результирующий файл будет содержать метаданные и контейнер, как и файлы *.bin.

Файлы *.CFF содержат ту же полезную нагрузку, что и файлы *.SMR-F, но в несжатом виде. Они применялись в предыдущих поколениях головных устройств.

Специализированные протоколы IPC

Внутри головного устройства службы встроенного ПО используют специализированные протоколы межпроцессного взаимодействия (IPC) для обмена данными со своими потоками выполнения, другими службами и другими ЭБУ. Чаще всего используются три основных протокола:

thriftme;
MoCCA;
GCF.

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

thriftme

Этот протокол удаленного вызова процедур (RPC) основан на протоколе с открытым исходным кодом Apache Thrift. Его главная отличительная особенность заключается в том, что thriftme позволяет уведомлять подписчиков о тех или иных событиях. В качестве транспорта для этого протокола могут использоваться сокеты UNIX, TCP, UDP, SSL и т. д. Основные функциональные возможности этого протокола реализованы в библиотеке libthriftme.so.2.7.2.

Базовым классом в thriftme RPC является thrift::TServiceBroker, который изолирует взаимодействие с транспортами и интерфейсами вызова служб и клиентов. В thriftme версия брокера служб — это экземпляр thrift::lisa::CTLisaServiceBroker, который наследуется от thrift::TServiceBroker.

Службы в thriftme наследуются от thrift::lisa::TLisaServerBase (который, в свою очередь, наследуется от thrift::TServiceProcessor). Службы регистрируются в брокере через thrift::TServiceProcessor::registerService. Транспорт, используемый клиентами, регистрируется через thrift::lisa::CTLisaServiceBroker::addServers (обертка для thrift::TServiceBroker::addServer). Интерфейсные функции службы регистрируются через thrift::TServiceProcessor::tmRegisterCallback. Обработчик передается этой экспортируемой функции в аргументах и будет вызываться при обработке клиентского запроса. Таким образом, экземпляр службы в памяти будет выглядеть следующим образом:

Поле interface1 содержит функции, которые обрабатывают API службы и их обертки, зарегистрированные ранее через thrift::TServiceProcessor::tmRegisterCallback. Поле interface2 содержит функции, которые будут вызываться для уведомления подписчиков данной службы.

Клиенты в thriftme наследуются от thrift::lisa::TLisaClientBase (который, в свою очередь, наследуется от thrift::TClient). Фактически экземпляры клиентов создаются брокером служб, когда транспорт успешно создан. В нашем случае брокер служб использовал фабрику клиента, которая регистрируется в брокере через thrift::TServiceBroker::tmRegCli. Фабрика помогает клиентам регистрировать обработчики уведомлений о событиях через thrift::TClient::tmRegisterCallback. Примерная схема экземпляра клиента thriftme выглядит следующим образом:

Поле interface1 содержит обработчик, который будет вызван после соединения с транспортом. Обычно этот обработчик используется для подписки на уведомления о событиях. Поле interface2 содержит функции, отправляющие запросы к API службы. Поле interface3 содержит функции, которые будут вызваны перед запуском операции уведомления подписчиков данной службы. Их обертки ранее регистрировались через thrift::TClient::tmRegisterCallback.

MoCCA

Этот RPC-фреймворк был разработан компанией Harman и основан на фреймворке DSI с открытым исходным кодом. Основные функции реализованы в библиотеке /opt/sys/lib/libSysMoCCAFrameworkSharedSo.so.11. Этот фреймворк широко используется для межпоточного взаимодействия.

Во время запуска служба создает экземпляры компонентов с помощью фабричных функций, например CHBApplicationBuilder::theCDiagnosisComponentCreator. Этот экземпляр наследуется от класса CHBComponent. Глобальная переменная CHBComponentInfo::spMap содержит дополнительную информацию о компонентах в связке с их именами. Фреймворк позволяет компонентам иметь собственные псевдонимы для доступа к другим компонентам через CHBComponentInfo::addComponentMapping: CHBComponentInfo::addComponentMapping(&unk_581498, «FsActionHandler», «FilesystemMainActionHandler»). Компоненты могут содержать несколько служб и клиентов и взаимодействовать с собственными службами или службами других компонентов. Ниже представлена архитектура компонентов:

Для связи используются следующие события:

Примером объекта клиента является CTraceServiceClientBase. Он наследуется от CHBClientBase и использует прокси-объект CTraceServiceProxy для транспорта. Прокси-объект наследуется от CHBProxyBase и создается с помощью метода фабрики CTraceServiceProxy::findOrCreateInstance. Он пытается повторно использовать ранее созданные прокси-объекты внутри этого компонента. Общая структура объекта клиента выглядит следующим образом:

Интерфейс IHBEventConsumer используется для обработки событий ответа в CTraceServiceClientBase. Точкой входа для обработки является метод processEvent. Он использует два значения для поиска обработчика, которые вызываются следующим образом:

используется поле status для идентификации ответа: стандартный ответ службы, ошибка или недействительный ответ;
используется поле internalID для идентификации функции API.

На стороне службы в нашем примере мы использовали класс CTraceServiceStub. Ниже приводится его структура:

Событие запроса обрабатывается в методе processEvent. Он идентифицирует обработчик функции API с помощью поля internalID и затем вызывает его.

GCF

GCF — это специализированный протокол, используемый для RPC. Он позволяет регистрировать службы в маршрутизаторе. Маршрутизатор обрабатывает следующие сообщения от служб и клиентов:

Сообщение управления (CTRL):
REGS — используется для регистрации службы;
REGF — используется для регистрации RPC-функции службы;
EVNT — используется службой для оповещения клиентов о событии;
CALL — используется клиентами для вызова функций службы;
и т. д.

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

CALL <ServiceName>:<Number> <ServiceCallName> <Params>

Внутренняя сеть

Как упоминалось в исследовании KeenLab, на головном устройстве имеется несколько контрольных точек, которые используются CSB для подключения к MMB. Мы отсоединили стандартный разъем и подключили кабель RJ45 для доступа к внутренней сети головного устройства. Это соединение, обозначенное как

eth0, имеет некоторые ограничения, как указано в соответствующих правилах сетевого экрана в файле firewall_prd.policy:-A INPUT -s [IP]/32 -d [IP]/32 -i eth0 -m state —state NEW -j ACCEPT
-A OUTPUT -s [IP]/32 -d [IP]/32 -o eth0 -j ACCEPT
-A OUTPUT -s [IP]/32 -d [IP]/32 -o eth0 -m state —state NEW -j ACCEPT

Доступ к службам на MMB осуществляется по IP-адресу, который является адресом по умолчанию для подключения CSB к MMB. Результаты сканирования TCP-портов на MMB выглядят следующим образом:

Подключившись к контрольной точке, мы обнаружили огромную поверхность атаки и доступ к диагностической подсистеме Diagnostic Log and Trace (DLT), что весьма полезно при тестировании и отладке:

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

Выявленные уязвимости

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

CVE-2024-37600 (MoCCA)

Служба servicebroker является частью фреймворка DSI, который используется в MoCCA. Эта служба используется для мониторинга служб и клиентов.

Она настраивает HTTP-серверы, используя порты TCP. Существует несколько доступных для обработки POST-команд. Одна из них —

disconnect — принимает в качестве аргумента строку.

Код в функции

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

В журналах DLT можно обнаружить информацию о сбоях:

CVE-2023-34404 (GCF)

MonitorService — это служба, доступ к которой предоставляется по протоколу GCF. Эта служба инициализируется и запускается в службе scp. Последняя, в свою очередь, является службой systemd и запускается в следующей конфигурации:


[Service] ExecStart=/opt/comm/swmp/wicome/bin/scp -f /var/opt/swmp/pss_config.cfg -s
wicome_config -r /opt/comm/swmp/wicome/bin -k VerboseLevel=5
ExecStop=/bin/kill $MAINPID
Environment=LD_LIBRARY_PATH=/opt/sys/lib:/opt/comm/swmp/wicome/lib
Environment=LOGNAME=root
EnvironmentFile=/opt/etc/lisa_env
Type=simple
Restart=on-failure
RestartSec=2
WatchdogSec=240

MonitorService использует для настройки своей работы следующий конфигурационный файл /var/opt/swmp/pss_config.cfg:

MonitorService.TimestampEnable = 1
MonitorService.ReceiveEnable = 1
MonitorService.MonitoringEnable = 1
MonitorService.MessageBufferSize = 1000
MonitorService.MessageBufferMemory = 512000
#1-file, 2-dlt, 3-both
MonitorService.LogMode = 2
#MonitorService.LogMode = 0
MonitorService.LogFileSize = -1
MonitorService.LogFileName = /tmp/wicom.log
MonitorService.LinefeedEnable = 1
MonitorService.HeaderEnable = 1
MonitorService.FileHeaderEnable = 1
#RH
MonitorService.Port = 2021

В переменной MonitorService.Port задается номер порта TCP, который будет использоваться сервером. Переменная MonitorService.ReceiveEnable определяет, способен ли сервер обрабатывать запросы от клиентов. Соответственно, служба MonitorService, содержащая конфигурацию головного устройства, может получать сообщения GCF от клиента и передавать их через маршрутизатор.

В список зарегистрированных служб в маршрутизаторе GCF входит NetworkingService. У нее имеются следующие зарегистрированные обработчики:

Обработчик NWS_PF_setMacAddrExceptionIP добавляет правила в политику сетевого экрана. Он использует следующие аргументы:

macAddress — MAC-адрес для правила;
direction — определяет направление правила: для входящих или исходящих;
fate — определяет тип правила: разрешить или запретить;
command — действие, которое будет выполнено: добавить правило или удалить его из политики.

Поток управления обработкой этого запроса находится в следующих бинарных файлах: MonitorService, libwicome_monitorservice.so и libwicode_gcf_core.so. Стек вызовов выглядит следующим образом:

sub_EE6E8 (NWS_PF_setMacAddrExceptionIP)
sub_E9D0C (sNWS_PF_setMacAddrExceptionIP)
sub_F275C (CGCFStub_PF::setMacAddrExceptionIP)
sub_F7AF4 (CGCFStub_PF::_int_setMacAddrExceptionIP)
snprintf
sub_F7EB4 (systemExec)
system

Функция

sub_F7AF4 вызывает system() с аргументами для утилиты iptables:/* … */
if ( v10 )
{
v11 = (const char *)PAL::CString::raw(direction);
v12 = (const char *)PAL::CString::raw(mac);
if ( snprintf(v22, 0xFFuLL, «iptables -%s %s -m mac —mac-source %s -j
%s «, (const char *)&v21, v11, v12, v20) < 0 )
{
/* … */
v18 = 0;
}
if ( v18 )
{
if ( (unsigned __int8)systemExec(a1, v22) != 1 )
{
/* … */
return 0;
}
}
}
/* … */

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

iptables.

Повышение привилегий

В головном устройстве используется устаревшая система Polkit, которая подвержена уязвимости CVE-2021-4034. Это уязвимость локального повышения привилегий, в результате эксплуатации которой непривилегированные пользователи могут получить права администратора в целевой системе. В открытом доступе имеется множество эксплойтов, позволяющих выполнять произвольные команды от имени пользователя phone группы comm.

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

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

USB

USB — самый популярный вектор атаки при наличии физического доступа. В основе головного устройства лежит микросервисная архитектура, где каждый сервис в определенной мере изолирован и взаимодействие с ним производится через API. Каждый микросервис головного устройства предоставляет определенный набор внутренних функций и одну или несколько thriftme-служб, через которые другие микросервисы могут взаимодействовать с ним. Это позволяет выполнить эмуляцию USB-подсистемы с помощью версии QEMU в пользовательском режиме.

Подготовка

Служба DeviceManager отвечает за обработку событий USB: добавление, удаление, монтирование или обновление. Остальные службы могут подписываться на DeviceManager; они используют обратные вызовы для уведомлений, чтобы выполнять действия при возникновении событий USB. Например, такая служба может запускать поиск определенных файлов при монтировании файловой системы USB.

Служба GDVariantCodingService — это фронтенд для кодирования вариантов. Другие службы используют его для определения параметров головного устройства и автомобиля.

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

Подготовить сеть под IP-адреса, используемые службами.
Службы DeviceManager и GDVariantCodingService используют для передачи данных сокеты UNIX. Для их эмуляции проще использовать TCP-сокеты, чтобы не зависеть от файловой системы. Далее необходимо настроить переадресацию с помощью socat.
Запустить эмулированные службы thriftme. В нашем случае мы создали файлы devicemgr.py, vehicle.py и varcoding.py. В devicemgr.py эмулируется монтирование файловой системы USB по пути /opt/sys/bin/aaaa.
Использовать эмуляцию QEMU в «прозрачном» режиме.
В окружении chroot подготовить папки и устройства.

Эмуляция подсистемы USB выполнена.

Эмуляция экспорта, импорта и отслеживания данных

Головное устройство поддерживает экспорт файлов пользовательского профиля (положение сиденья, любимые радиостанции и т. д.) на USB-накопитель или импорт с него. За это отвечает служба UserData, а точнее, служба thriftme под названием CSystemProfileServiceImpl.

Резервная копия профилей пользователей выглядит как папка со следующей структурой:

.
└── MyMercedesBackup
├── shared
├── system
│ ├── rse.ud2
│ └── system.ud2
└── udxprofiles
├── profile0
│ ├── commuterroute.ud2
│ ├── emotions.ud2
│ ├── navidata.ud2
│ ├── pud.ud2
│ ├── uapreds.ud2
│ ├── vt_ab.ud2
│ └── vt_tuner.ud2
└── profileindex.xml

Некоторые из этих файлов создаются самой службой UserData, но большинство из них генерируются и обрабатываются другими службами, например CAPServer. Важнейшим звеном в процессах импорта и экспорта данных является служба thriftme UserDataExchangeService в UserData. Службы подписываются на уведомления об импорте и экспорте данных в UserDataExchangeService.

CSystemProfileServiceImpl выполняет следующие действия в случае экспорта резервной копии профилей:

Запускает таймер на 100 секунд.
Уведомляет клиентские службы через UserDataExchangeService с помощью событий, запрашивающих экспорт данных. Такие события содержат информацию об экспортируемых данных.
Службы вызывают функции API, которые проверяют завершение экспорта данных. В качестве аргументов они принимают ключ данных и путь к файлу.
UserData собирает все полученные файлы, кодирует их и сохраняет в смонтированной файловой системе USB.

Эта схема аналогична импорту резервной копии профилей:

Служба UserData копирует файлы с USB-носителя в локальную систему и декодирует их.
Она уведомляет клиентские службы с помощью событий, запрашивающих импорт данных.
Если клиентская служба обрабатывает ключ данных, то выполняется импорт данных.
Службы вызывают функции API, которые проверяют завершение импорта данных.

Резервная копия содержит файлы XML и бинарные файлы. Бинарные файлы считаются более удобными для поиска уязвимостей:

Ключ данных
Имя файла в резервной копии
Содержимое

PUD_COMMUTER
commuterroute.ud2
Текст в формате ISO-8859, без символов конца строки

PUD_UAPREDICTIONSDATA
uapreds.ud2
База данных SQLite 3.x

PUD_VT_TUNER
vt_ab.ud2
Данные в проприетарном бинарном формате

PUD_VT_ADDRESSBOOK
vt_tuner.ud2
Данные в проприетарном бинарном формате

Для запуска импорта (восстановления) и экспорта (резервного копирования) резервных копий были подготовлены следующие скрипты:

triggerRestore.py и triggerBackup.py.

Практически все службы головного устройства поддерживают систему трассировки 

HBTracePersistence, которая позволяет включать и выключать трассировку для определенного модуля или функции.

Файл hbtc содержит конфигурацию системы трассировки и определяет метод трассировки функций. Ниже приводится пример файла hbtc:

HBTracePersistence 1.0.0
imp 00 08
imp_userdata_private_CSystemProfileManager ff 08
imp_userdata_private_CUserDataVehicleInformationAdapter ff 08
imp_userdata_private_CUserDataIF2Impl ff 08
imp_common_streamhelper_StreamHelper ff 08
imp_userdata_private_CUDXStructure ff 08

Как уже упоминалось, файлы в резервной копии кодируются с использованием проприетарного алгоритма. Этим занимается класс CPUserDataEncodingHandler. Скрипт

ud2codec.py предназначен для кодирования и декодирования файлов.

Выявленные уязвимости

Наличие следующих уязвимостей было протестировано на реальном автомобиле.

CVE-2024-37601

Процесс декодирования файлов с расширением

*.ud2 содержит уязвимость, приводящую к переполнению буфера на куче.

UserData представляет закодированные данные через объект CHBString, который обрабатывает данные как строку в кодировке UTF. Затем символы декодирования, специфичные для UD2, следует удалить, но их индексы должны остаться неизменными. Мы использовали функции CHBString::const_iterator::incrementSteps для помещения указателя на нужный символ и CHBString::remove для удаления символа из строки. CHBString::const_iterator::incrementSteps некорректно обрабатывает символ с кодом

0xe7: тот декодируется как 1 байт. Но согласно таблице UTF8LookUpTable, которая используется в CHBString::remove и CHBString::CHBString, символ с кодом 0xe7 кодируется 3 байтами.
В результате при выполнении функции CHBString::remove вычисленный указатель может оказаться за пределами выделенного буфера после декодирования в UTF с помощью UTF8LookUpTable. Функция memmove будет вызвана с третьим аргументом (размер буфера), равным -1.

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

CVE-2023-34402

Как упоминалось ранее, файл

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

Файл

vt_ab.xml содержит еще один файл, описывающий, какая служба будет доставлена во время обработки. Для этого в нем содержится имя доставляемого файла. Следующие действия выполняются в функции UserDataExchangeServiceClient::unpackVoiceTagArchiveOptimized:

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

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

CVE-2023-34399

После декодирования файл

uapreds.ud2 в папке профиля MyMercedesBackup/udxprofiles/profile0 принимает вид uapreds.db. Система распознает его как базу данных SQLite, анализ которой выполняется в службе, использующей машинное обучение для создания эффективных маршрутов. Декодированный файл обрабатывается в capthrift::CapServer::requestImportBinaryData, после чего вызывается capthrift::CapServer::setProfile для загрузки базы данных.

Все значения в таблицах базы данных SQLite сериализуются в виде архива для использования вместе с библиотекой boost. Форматом этого архива может быть как XML, так и обычный текст. Мы использовали режим обычного текста. Вот пример архива в строке

learning_kernel таблицы kvpair_table:22 serialization::archive 11 0 2 0 1 0 0 1 0 1 0 0 0 0 1
0.00000000000000000e+00 0 0 0 0 0 0 0 0 1.00000000000000000e+00

Последняя общедоступная версия библиотеки boost, 1.81 (на момент исследования), содержит уязвимость, приводящую к целочисленному переполнению. Эта уязвимость может быть использована при обработке указателя на сущность:

В блоке (1) из данных, контролируемых злоумышленником, было получено значение

cid. В блоке (2) это значение используется уже как индекс массива для получения объекта cobject_id. В блоках (3.1) и (3.2) вводятся ограничения для cid:

если значение cid равно -1;
если значение cid больше размера массива cobject_id_vector.

Эти ограничения можно обойти, присвоив определенное значение

cid. Это возможно, потому что согласно объявлению тип class_id_type является целым числом со знаком:

Поэтому если присвоить

cid значение -3, то указатель co.bpis_ptr (2) будет поврежден.

Сработавшая уязвимость в отладчике выглядит следующим образом:

Thread 63 hit Breakpoint 2, 0x0000004002f3cea4 in ?? ()
# cid value
(gdb) i r x2
x2 0xfffffffffffffffd -3
# cobject_id_vector size
(gdb) x/1hx $x20 + 0x58
0x405c01b278: 0x000e
# cobject_id_vector pointer
(gdb) x/1gx $x20 + 0x60
0x405c01b280: 0x000000405c017f00
# 1 element in the cobject_id_vector
(gdb) x/3gx *(void **)($x20 + 0x60) + 0 * 0x18
0x405c017f00: 0x000000400147f1c8 0x0000000000000000
0x405c017f10: 0x0000010000000002
# refferenced element
(gdb) x/3gx *(void **)($x20 + 0x60) + -3 * 0x18
0x405c017eb8: 0x5f72696170766b5f 0x00315f656c626174
0x405c017ec8: 0x0000000000000035
(gdb) c
Continuing.

Thread 63 received signal SIGSEGV, Segmentation fault.

Замечания по эксплуатации

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

изменяя id, мы можем перемещать указатель (сдвигая его на отрицательное смещение относительно начала массива в куче);
перемещая указатель, мы попадем туда, где будет находиться другой адрес, содержащий объект для bis_ptr;
адрес для bis_ptr должен содержать адрес виртуальной таблицы вызовов.

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

Мы можем реализовать такой сценарий с помощью техники heap spraying («распыление кучи»), используя DDL-записи в базе данных SQLite, которые мы можем контролировать. Для проведения подобной атаки нам нужно создать множество таблиц с длинными именами. В результате в куче появятся структуры нужного формата, и отрицательный индекс позволит нам добраться до таких структур.

Ниже приведен пример такого файла на основе SQLite (запись в

sqlite_schema — это запрос на создание таблицы):

Таким образом, мы можем создать множество таблиц с длинными именами, что позволяет осуществить атаку heap spraying.

Используя технику heap spraying, злоумышленник может получить полный контроль над выполнением:

Чтобы импортировать базу данных

uapreds.db в службу CAPServer, нам нужно скопировать ее в рабочий каталог этой службы. Затем CAPServer пытается загрузить базу данных из своего рабочего каталога. В результате, если злоумышленнику удается импортировать базу данных, эксплуатирующую уязвимость в головном устройстве, то при каждом запуске служба CAPServer будет пытаться загрузить ее, что приведет к аварийному завершению. Служба CAPServer запускается с помощью systemd и настроена следующим образом:[Service] ExecStart=/opt/prediction/bin/CAPServer /var/opt/prediction/
ExecStop=/bin/kill $MAINPID
Environment=LD_LIBRARY_PATH=/opt/sys/lib
EnvironmentFile=/opt/etc/lisa_env
Type=notify
WatchdogSec=30
Restart=on-failure
RestartSec=2

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

Внутри базы данных SQLite есть раздел pragma, содержащий SQL-команды для создания таблиц. Они могут использоваться для создания контролируемых данных на основе таблиц в базе данных на основе текущего времени. Приведенный ниже скрипт можно использовать для автоматизации создания базы данных SQLite, способной вызывать эту уязвимость с учетом текущего времени:

#!/bin/bash
DBPATH=test.db
STOP_TIME=$(date —date=’-2 hours +10 seconds’ +»%H:%M:%S»)

echo «Trigger until < $STOP_TIME, clean after >= $STOP_TIME»;

poc_value=»CRASH the system»
clean_value=»system work»

check() {
sqlite3 $DBPATH << EOF
SELECT strftime (‘Time of database: %H:%M:%S’, ‘now’);
select * from target_table;
.exit
EOF
}

rm $DBPATH

sqlite3 $DBPATH << EOF
CREATE VIEW target_table AS SELECT «key» AS varkey, «$poc_value» AS varval
WHERE TIME() < «$STOP_TIME» UNION SELECT «key» AS varkey, «$clean_value» AS
varval WHERE TIME() >= «$STOP_TIME»;
.exit
EOF

check

sleep 10

check

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

Векторы атак

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

Компрометация модели для тестирования может оказаться полезной в трех сценариях:

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

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

Список уязвимостей

В процессе изучения уязвимостей были зарегистрированы следующие идентификаторы CVE:

CVE-2024-37602
CVE-2024-37600
CVE-2024-37603
CVE-2024-37601
CVE-2023-34406
CVE-2023-34397
CVE-2023-34398
CVE-2023-34399
CVE-2023-34400
CVE-2023-34401
CVE-2023-34402
CVE-2023-34403
CVE-2023-34404

Подробная информация по CVE будет опубликована здесь: https://github.com/klsecservices/Advisories.

​  

​Securelist

Read More

Ваша реакция?
+1
0
+1
0
+1
0
+1
0
+1
0
+1
0
+1
0
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x