The Jerusalem PostYemeni forces withdraw from Bab el-Mandeb Strait, leaving Iran-backed Houthis in controlPunchFULL LIST: Teams leading AFCON 2027 qualifying groupsInquirer EntertainmentActress-politician faces license suspension from LTO after dancing while drivingInquirerRomualdez’s congressional aid continues despite suspension – AcidreSky TG24Perù, Papa Leone XIV a Zaña: appello contro la criminalitàCNN TürkKörfez yine alarmda! İran'dan ABD'ye misilleme: Bahreyn’deki üssü 6 İHA ile hedef aldı…Daily MaverickThe baboons are doomed, and welfare groups just missed the last chance to save themCapital FMIndia and UAE deepen energy ties with proposed strategic oil storage dealColliderJulia Roberts’ $205M Romance Hit Is Officially a Global Streaming Sensation3DNewsКитайская Bilibili Gaming cтала чемпионом World Championship 2026 по League of Legends, прервав многолетнее доминирование корейских командZDF heuteEntdecken Sie das ZDF-NachrichtenstudioIl Fatto QuotidianoYouTube blocca 16 canali russi in Ucraina: stop anche per Masha e Orso, considerato “strumento di propaganda del Cremlino”
The Daily Newsstand · Free, Always
Sunday, November 15, 2026

[Перевод] Мы нашли способ взломать любой подключенный автомобиль компании X в крупнейших странах

Translate

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

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

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

На сей раз весь путь начался с простого вопроса «С какой инфраструктурой связывается приложение, когда я дистанционно разблокирую авто?» Чтобы это выяснить, я скачал APK и декомпилировал его, в конечном итоге воссоздав запросы к API, которые отправляет приложение.

Разбирая код, я заметил, что главной точкой связи выступают ресурсы в поддомене *.redacted-telematics.com.au:

dartExecutor.executeDartEntrypoint(createDefault, CollectionsKt.r(gson.toJson(new Global
ConfigParams(false, g11, com.redacted.app.xcapp.a.f69866f, "X", str)),new Gson().toJson(new 
ApiConfig("https://api.redacted-telematics.com.au", "https://api.redacted-telematics.com.au", 
"https://api.redacted-telematics.com.au" ...

Почти все части клиентского приложения обращались обратно к redacted-telematics.com.au. Мне стало интересно, что ещё происходит на этом домене?

Админка

Поддержание структуры для подключенных автомобилей — дело непростое. Чтобы конечные пользователи получали чистый продукт, требуется нескольких админок под разные задачи, а также среды для staging, dev и QA. А вот вопрос о том, должно ли всё это торчать в интернет, доступное для любого, кто пожелает провести базовую разведку, уже заслуживает отдельного внимания.

Один из ресурсов показался мне особенно интересным. Поддомен admintool.redacted-telematics.com.au возвращал страницу с заголовком TEST HARNESS. Ну разве можно пройти мимо поддомена с admintool в адресе?

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

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

Кто вообще читает JS-бандлы?

Кто вообще читает JS-бандлы?

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

Например, мы смогли находить аккаунты пользователей по адресам e-mail:

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

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

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

И к нашему везению, там как раз нашёлся нужный API:

Зная GUID подписчика, через эндпоинт /v1/account можно было вытянуть все детали аккаунта, включая e-mail пользователя:

Итак, первый этап цепочки атаки готов: госномер -> VIN -> GUID подписчика -> персональные данные пользователя (e-mail), зарегистрированного на платформе идентификации (ForgeRock OpenIDM).

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

Платформа идентификации

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

Когда пользователь проходит аутентификацию в мобильном приложении, запросы отправляются к login.redacted-identity.com.au, и после прохождения MFA ему выдаётся токен авторизации. Впоследствии этот токен используется для последующих запросов к api.redacted-telematics.com.au (как через REST API, так и через GraphQL). Как только вы получили этот токен, дело в шляпе — вы имеете полный контроль над машиной (можете удалённо разблокировать/блокировать её, сигналить, запускать двигатель и так далее).

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

Этот концерн активно использует ПО идентификации от ForgeRock (OpenAM/OpenIDM). На нём держится вся их система аутентификации. Подтянув поддомены для *.redacted-identity.com.au, мы быстро нашли их экземпляр OpenIDM на openidm.redacted-identity.com.au. Именно эта система управляет всеми учётками, зарегистрированными на платформе подключенных автомобилей.

И пазл окончательно сложился, когда мы прочёсывали JS-файлы на поддоменах *.redacted-telematics.com.au. Там мы наткнулись на совершенно дикий сторонний JS-бандл, в котором лежали учётные данные админа для OpenIDM 😱:

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

Борьба с WAF

При более внимательном изучении OpenIDM мы так и не смогли понять, знал ли производитель о том, насколько хрупкая у него система. Но одно было очевидно: они хорошенько вложились в правила WAF (Web Application Firewall) для защиты доступа к чувствительным API, которые ForgeRock обычно позволяет вызывать через /openidm/*.

Даже через реальный IP-адрес сервера любое обращение к /openidm/ тут же приводило к блокировке со стороны Nginx WAF. Кто-то знатно заморочился укреплением этих ресурсов, пусть даже они и оставались доступными извне.

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

Не припомню, удалось ли правилами WAF хоть раз остановить нас в порыве намерения. В итоге мы несколько дней искали лазейку, используя проверенные трюки с обходом каталога (Path Traversal). Сложно ли, умеючи?

Проверить учётные данные, которые мы нашли в бандле, оказалось нетрудно. В австралийском инстансе OpenIDM несколько путей вроде /XUI/ и /UI/ были внесены в белый список, а символы обхода каталога не блокировались. Так что простая конструкция типа /XUI/..%2fopenidm/endpoint как минимум частично сработала:

По крайней мере мы поняли, что учётные данные работают в продакшене

По крайней мере мы поняли, что учётные данные работают в продакшене

Но ведь не может всё быть так просто? Из-за особенностей обработки маршрутизации в OpenIDM обход пути всё равно не позволял нам добраться до эндпоинтов в /openidm/. Всякий раз мы получали ошибку вроде:

Чёрт, мы уже так близко?!

Чёрт, мы уже так близко?!

В мире OpenIDM для путей, содержащих в себе символы Path Traversal, попросту не было зарегистрировано никаких сервлетов (или ресурсов). Из-за этого система сыпала ошибками, хотя и выписывала нам админский JWT.

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

Всё это заставило нас задуматься: «А зачем вообще понадобилось раскрывать инстансы OpenIDM?» Наверняка же был какой-то весомый повод держать эти ресурсы открытыми для интернета? Тогда мы вернулись к собранным с них JS-бандлам и начали искать в них упоминания запросов к OpenIDM. Затем мы декомпилировали приложение для Android и нашли в нём вот что:

А может, часть эндпоинтов внесена в белый список?

Это явно были эндпоинты ресурса OpenIDM, с которыми связывалось приложение. Так может, к ним можно достучаться в обход WAF?

  • /openidm/endpoint/aaa -> 403 WAF blocked

  • /openidm/endpoint/pinService -> 404, no WAF block

Интересно!

А какие ещё кастомные эндпоинты тут есть? Погоняв облегчённый вариант брутфорса и опробовав собственные догадки, мы быстро нашли getUser. Затем через подстановку разных параметров мы выяснили, что он принимает mail, guid и phone. Какие же возможности нам это даёт в сочетании с уже имеющимися учётными данными?

Упс…

Упс…

В ответе мы получили хэш пароля, хэш PIN-кода, пуш-токены устройств и персональные данные, включая номера телефонов и полные имена. На этом эндпоинте не было никакой защиты WAF, так что обход пути не потребовался — ответил нужный сервлет.

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

Пришлось снова отступить. Как же нам получить доступ к сервлету /openidm/managed/user с помощью обхода пути так, чтобы OpenIDM этот адрес корректно распознал? Мы взяли исходники OpenIDM максимально близкой версии и скормили их GPT 5.6 Sol Ultra, которая пропотела над ними целые шесть часов.

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

Когда мы пробовали /XUI%2f..%2fopenidm/, то получали жёсткую 403 и по своей человеческой природе решили, что так будет с любым префиксом. Агент же выяснил, что /static%2f..%2fopenidm/ вообще не фильтровался WAF, и это дало нам заветный доступ к OpenIDM API без путаницы в сервлетах.

Захват аккаунтов

Имея такой обходной путь, захват учётных записей стал простой задачей. Мы могли прописывать новый пароль для профиля любого пользователя:

PATCH /static%2f..%2fopenidm/managed/user/f7ba554REDACTED HTTP/1.1
Host: openidm.redacted-identity.com.au
X-OpenIDM-Username: idmadmin
X-OpenIDM-Password: REDACTED
X-OpenIDM-NoSession: true
Content-Type: application/json
If-Match: "0000000abc123..."
Cache-Control: no-store
Accept: application/json
 
[{"operation":"replace","field":"/password","value":"Testing123!"}]

На что система отвечала:

HTTP/1.1 200 OK
{“_id”:“f7ba554REDACTED”,“_rev”:“0000000def456…”}

Хорошо, теперь мы можем менять пароль любого пользователя. Но как быть с мультифакторной аутентификацией?

Пропуск MFA

В конфигурации австралийской инфраструктуры концерна была ещё одна брешь, позволявшая полностью пропустить этап MFA. Сначала мы запросили токен аутентификации у login.redacted-identity.com.au, используя механизм Resource Owner Password Credentials (ROPC), и сервер вернул нам чистый id_token, который мы уже могли обменять на что-то, пригодное для использования в приложении:

POST /oauth2/realms/root/realms/REDACTED/access_token HTTP/1.1
Host: login.redacted-identity.com.au
Content-Type: application/x-www-form-urlencoded

grant_type=password&username=admin@shubs.io&password=Testing123!&client_id=REDACTED_PORTAL
&client_secret=REDACTED

> HTTP/1.1 200 OK
> {
>   "access_token": "...",
>   "id_token": "eyJ0eXAiOiJKV1Qi...",
>   "token_type": "Bearer",
>   "expires_in": 3599
> }

Далее мы перешли ко второму шагу — запуску по этому токену сессии:

POST /json/realms/REDACTED/authenticate?authIndexType=service&authIndexValue=IDTokenROPC 
HTTP/1.1
Host: login.redacted-identity.com.au
Content-Type: application/json
Accept: application/json
Accept-API-Version: resource=2.0, protocol=1.0
idtoken: eyJ0eXAiOiJKV1Qi...
 
> HTTP/1.1 200 OK
> {
>   "tokenId": "AQIC5wM2LY4Sfcy...*",
>   "successUrl": "/openam/console",
>   "realm": "/REDACTED"
> }

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

POST /oauth2/realms/root/realms/REDACTED/authorize HTTP/1.1
Host: login.redacted-identity.com.au
Content-Type: application/x-www-form-urlencoded
Accept-API-Version: resource=2.1, protocol=1.0
x-fr-version: 2025.05.05
Authorization: Basic <REDACTED>
iPlanetDirectoryPro: AQIC5wM2LY4Sfcy...*
Cookie: iPlanetDirectoryPro=AQIC5wM2LY4Sfcy...*
 
client_id=REDACTED_APP&redirect_uri=com.redacted.app:/oauth2Callback&scope=openid%20profile
%20write&response_type=code&state=<state>&code_challenge=<S256_challenge>&code_challenge_met
hod=S256&decision=allow&csrf=AQIC5wM2LY4Sfcy...*

> HTTP/1.1 302 Found
> Location: com.redacted.app:/oauth2Callback?code=<authorization_code>&state=<state>
 
POST /oauth2/realms/root/realms/REDACTED/access_token HTTP/1.1
Host: login.redacted-identity.com.au
Content-Type: application/x-www-form-urlencoded
Accept-API-Version: resource=2.1, protocol=1.0
Authorization: Basic <REDACTED>

grant_type=authorization_code&code=<authorization_code>&redirect_uri=com.redacted.app:/
oauth2Callback&client_id=REDACTED_APP&code_verifier=<pkce_verifier>

> HTTP/1.1 200 OK
> {
>   "access_token": "<app_access_token>",
>   "refresh_token": "...",
>   "token_type": "Bearer",
>   "scope": "openid profile write",
>   "expires_in": 3599
> }

Знаю, схема выглядит очень запутанной, с OAuth иногда до боли сложно работать. Но эти шаги позволили нам обойти MFA для любого пользователя.

Разблокировка авто

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

POST /v1/remote/route/command HTTP/1.1
Host: api.redacted-telematics.com.au
Authorization: Bearer <app_access_token>
X-API-KEY: REDACTED
X-GUID: f7ba554REDACTED
X-BRAND: REDACTED
X-APPBRAND: REDACTED
X-CHANNEL: REDACTED
X-LOCALE: en-AU
X-APPVERSION: REDACTED
X-OSNAME: Android
X-OSVERSION: 14
X-DEVICE-TIMEZONE: AEST
X-CORRELATIONID: 6f1a2b3c-4d5e-6f70-8192-a3b4c5d6e7f8
X-GENERATION: REDACTED
VIN: XXXXXXXXXXXXXXXXX
Content-Type: application/json
Accept: application/json
User-Agent: okhttp/4.12.0

{"command": "door-unlock", "autoFixPopup": false, "beepCount": null}

И двери магическим образом открылись!

Естественно, всё это мы проделывали на собственных авто или на тех, с которыми нам разрешили поэкспериментировать.

Но давайте на секунду приостановимся и подумаем, чего нам удалось добиться. В конечном итоге мы смогли отправлять команды на любой автомобиль концерна в Австралии — причём на обе выпускаемых им марки — зная только номерной знак. Общая цепочка атаки выглядела так:

Номер авто -> VIN -> GUID подписчика -> учётные данные админки OpenIDM в стороннем JS-бандле -> обход WAF через Path Traversal -> обход MFA через ROPC-флоу -> выпуск токена для клиентского приложения -> вызов API удалённого управления.

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

Вы можете спросить, мол, Шабс, ты же говорил про взлом любой машины этого производителя в мире, а здесь пример только с Австралией. Как так?

Мы с Сэмом разработали ещё более сложную цепочку, о которой он писал в своём блоге. Для её реализации потребовалось намного больше усилий, чем в случае с Австралией, так как системы OpenIDM для США, Канады и Европы производитель защитил гораздо лучше.

В конечном же итоге, объединив результаты обоих экспериментов, мы смогли отправлять удалённые команды — разблокировать машину, запускать двигатель и не только — на любой авто этого концерна в Австралии, США и Канаде.

View the original on Хабр →

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.