通过逆向API接口黑掉宝马i3-

七彩网络

昔年博客
首页>> 系统安全 >>通过逆向API接口黑掉宝马i3

目标

我们的终极目标是获取通过API暴露出的所有汽车功能。

设备

为了完成这个相对简单的任务,你需要这些东西:

一辆BMW i3;
一个BMW联网驾驶账户;
BMW I 远程安卓应用程序(我使用的是非美国版本);
一部安卓手机或平板;
设备中需要具备一种拦截加密通信的方法——我推荐使用Grey Shirts的Packet Capture。

安装了Packet Capture之后,关闭其他所有应用程序,启动日志,然后登陆i Remote应用程序。

你将会看到一堆被抓获的API调用接口。

点击一个,你便会看到全部的API调用接口,以及JSON响应。我已经打码了一些我的个人信息。

重要的是你需要得到授权:无记名令牌。这是一个32个字符的字母数据字符串。

描述

BMW i Remote的最新版本总是可以从GitHub上得到。

这些API调用接口允许你与BMW i3进行交互,通过从官方BMW i Remote安卓应用程序逆向工程后获得。

https://play.google.com/store/apps/details?id=com.bmwi.remote

你使用这些API调用接口的风险完全由你自己承担。它们既不被官方提供也不被制裁。

服务器

这里有三个API服务器:

https://b2vapi.bmwgroup.cn:8592 中国

https://b2vapi.bmwgroup.us 美国

https://b2vapi.bmwgroup.com 欧洲/及其他

授权

为了验证API,你需要在宝马连接驱动服务注册

需要你提供:

1、你的ConnectedDrive注册邮件地址;
2、ConnectedDrive注册密码;
3、i Remote API Key;
4、i Remote API Secret。

你可以从反编译安卓应用程序或者拦截你手机与BMW服务器之间的通讯来获得i Remote细节。这就当作是留给各位读者的一个练习题吧。

首先,我们使用Basic身份验证。这意味着利用API Key和Secret,并用Base64进行解码。

因此,key:secret变为 a2V5OnNlY3JldA==

同时,我们需要发送以下参数

内容类型:应用程序/x-www-form-urlencoded

grant_type=password
&username=whatever%40example.com
&password=p4ssw0rd
&scope=remote_services+vehicle_data

这里描述了如何处理curl:

curl \
   -H "Authorization: Basic a2V5OnNlY3JldA==" \
   -H "Content-Type: application/x-www-form-urlencoded" \
   -d "grant_type=password&username=whatever%40example.com&password=p4ssw0rd&scope=remote_services+vehicle_data" \

如果所有东西都正常运行,你应该可以得到以下JSON:

{
  "access_token": "RCQ1hLP4AFaUBW9BjcPUN3i4WgkwF90R",
  "token_type": "Bearer",
  "expires_in": 28800,
  "refresh_token": "7WgKmEJ2kD1ydl9Hefp01eS8qDGzKnzjeORpA6vtsoFIEanz",
  "scope": "vehicle_data remote_services"
}

每次你去发包请求的时候,都要带上以下信息:

授权:不记名

RCQ1hLP4AFaUBW9BjcPUN3i4WgkwF90R

API

每次你去发包请求的时候,都要带上以下信息:

授权:不记名

RCQ1hLP4AFaUBW9BjcPUN3i4WgkwF90R

获取汽车数据

/webapi/v1/user/vehicles/

记住授权:不记名请求报头信息 

最重要的是VIN-Vehicle Identification Number。你需要的所有其他API调用以及Authorization Bearer。

响应

{
    "vehicleStatus": {
        "vin": "WAB1C23456V123456",
        "mileage": 1234,
        "updateReason": "VEHICLE_SHUTDOWN_SECURED",
        "updateTime": "2015-10-30T18:45:04+0100",
        "doorDriverFront": "CLOSED",
        "doorDriverRear": "CLOSED",
        "doorPassengerFront": "CLOSED",
        "doorPassengerRear": "CLOSED",
        "windowDriverFront": "CLOSED",
        "windowDriverRear": "CLOSED",
        "windowPassengerFront": "CLOSED",
        "windowPassengerRear": "CLOSED",
        "trunk": "CLOSED",
        "rearWindow": "INVALID",
        "convertibleRoofState": "INVALID",
        "hood": "CLOSED",
        "doorLockState": "SECURED",
        "parkingLight": "OFF",
        "positionLight": "OFF",
        "remainingFuel": 8.9,
        "remainingRangeElectric": 73,
        "remainingRangeElectricMls": 45,
        "remainingRangeFuel": 126,
        "remainingRangeFuelMls": 78,
        "maxRangeElectric": 134,
        "maxRangeElectricMls": 83,
        "fuelPercent": 99,
        "maxFuel": 9,
        "connectionStatus": "DISCONNECTED",
        "chargingStatus": "INVALID",
        "chargingLevelHv": 58,
        "lastChargingEndReason": "UNKNOWN",
        "lastChargingEndResult": "FAILED",
        "position": {
            "lat": 51.123456,
            "lon": -1.2345678,
            "heading": 211,
            "status": "OK"
        },
        "internalDataTimeUTC": "2015-10-30T18:47:44"
    }
}

参数

mileage is in Km.
remainingFuel is in Litres.
maxRangeElectric is in Km.
maxRangeElectricMls is in miles.
chargingLevelHv is the percentage of charge left in the (High voltage?) battery.
maxFuel is in Litres.
heading is in degrees.

有效充电状态:

CHARGING
ERROR
FINISHED_FULLY_CHARGED
FINISHED_NOT_FULL
INVALID
NOT_CHARGING
WAITING_FOR_CHARGING

有效连接状态:

CHARGING_DONE
CHARGING_INTERRUPED [sic]
CHARGING_PAUSED
CHARGIN_STARTED [sic]
CYCLIC_RECHARGING
DOOR_STATE_CHANGED
NO_CYCLIC_RECHARGING
NO_LSC_TRIGGER
ON_DEMAND
PREDICTION_UPDATE
TEMPORARY_POWER_SUPPLY_FAILURE
UNKNOWN
VEHICLE_MOVING
VEHICLE_SECURED
VEHICLE_SHUTDOWN
VEHICLE_SHUTDOWN_SECURED
VEHICLE_UNSECURED

获取最后的历程

获取你最近一次旅行的详情。

·/webapi/v1/user/vehicles/:VIN/statistics/lastTrip

·地点:VIN 便是你汽车的VIN。

不要忘记授权:不记名请求报头信息

响应

{
   "lastTrip":{
      "efficiencyValue":0.53,
      "totalDistance":141,
      "electricDistance":100.1,
      "avgElectricConsumption":16.6,
      "avgRecuperation":2,
      "drivingModeValue":0,
      "accelerationValue":0.39,
      "anticipationValue":0.81,
      "totalConsumptionValue":0.79,
      "auxiliaryConsumptionValue":0.66,
      "avgCombinedConsumption":1.9,
      "electricDistanceRatio":71,
      "savedFuel":0,
      "date":"2015-12-01T20:44:00+0100",
      "duration":124
   }
}

参数

距离似乎是公里数,而非英里,因此需要进行响应换算,乘以0.621371就能得到英里数。

totalDistance is in Km.
electricDistance is in Km.
avgElectricConsumption is in kWh/100Km.
avgRecuperation is in kWh/100Km.
duration is in minutes.

充电时间

显示了汽车充电安排。

/webapi/v1/user/vehicles/:VIN/chargingprofile

不要忘记授权:不记名请求报头信息

响应

{
   "weeklyPlanner":{
      "climatizationEnabled":true,
      "chargingMode":"DELAYED_CHARGING",
      "chargingPreferences":"CHARGING_WINDOW",
      "timer1":{
         "departureTime":"07:30",
         "timerEnabled":true,
         "weekdays":[
            "MONDAY"
         ]
      },
      "timer2":{
         "departureTime":"13:00",
         "timerEnabled":false,
         "weekdays":[
            "SATURDAY"
         ]
      },
      "timer3":{
         "departureTime":"08:00",
         "timerEnabled":false,
         "weekdays":[
 
         ]
      },
      "overrideTimer":{
         "departureTime":"07:30",
         "timerEnabled":false,
         "weekdays":[
            "MONDAY"
         ]
      },
      "preferredChargingWindow":{
         "enabled":true,
         "startTime":"05:02",
         "endTime":"17:31"
      }
   }
}

参数

离开时间似乎是汽车的地方时

获得车辆目的地

显示了你之前汽车之前去过的地方。

/webapi/v1/user/vehicles/:VIN/destinations

地点:VIN便是你汽车的VIN

授权:不记名请求报头信息

响应

{
   "destinations":[
      {
         "lat":51.53053283691406,
         "lon":-0.08362331241369247,
         "country":"UNITED KINGDOM",
         "city":"LONDON",
         "street":"PITFIELD STREET",
         "type":"DESTINATION",
         "createdAt":"2015-09-25T08:06:11+0200"
      }
   ]
}

参数

地址的数组。

获取全部历程详情

可以得到汽车所有行程的统计数据

/webapi/v1/user/vehicles/:VIN/statistics/allTrips

地点:VIN便是你汽车的VIN

授权:不记名请求报头信息

响应

{
    "allTrips": {
        "avgElectricConsumption": {
            "communityLow": 0,
            "communityAverage": 16.33,
            "communityHigh": 35.53,
            "userAverage": 14.76
        },
        "avgRecuperation": {
            "communityLow": 0,
            "communityAverage": 3.76,
            "communityHigh": 14.03,
            "userAverage": 2.3
        },
        "chargecycleRange": {
            "communityAverage": 121.58,
            "communityHigh": 200,
            "userAverage": 72.62,
            "userHigh": 135,
            "userCurrentChargeCycle": 60
        },
        "totalElectricDistance": {
            "communityLow": 1,
            "communityAverage": 12293.65,
            "communityHigh": 77533.6,
            "userTotal": 3158.66
        },
        "avgCombinedConsumption": {
            "communityLow": 0,
            "communityAverage": 1.21,
            "communityHigh": 6.2,
            "userAverage": 0.36
        },
        "savedCO2": 87.58,
        "savedCO2greenEnergy": 515.177,
        "totalSavedFuel": 0,
        "resetDate": "1970-01-01T01:00:00+0100"
    }
}

参数

chargecycleRange is in Km.
totalElectricDistance is in Km.

我并不确定其他值的单位。

得到地图范围

生成一个预测汽车范围的多线显示。

/webapi/v1/user/vehicles/:VIN/rangemap

地点:VIN便是你汽车的VIN

授权:不记名请求报头信息

响应

{
    "rangemap": {
        "center": {
            "lat": 51.123456,
            "lon": -1.2345678
        },
        "quality": "AVERAGE",
        "rangemaps": [
            {
                "type": "ECO_PRO_PLUS",
                "polyline": [
                    {
                        "lat": 51.6991281509399,
                        "lon": -2.00423240661621
                    },
                    {
                        "lat": 51.6909098625183,
                        "lon": -1.91526889801025
                    },
                    ...
                ]
            },
            {
                "type": "COMFORT",
                "polyline": [
                    {
                        "lat": 51.7212295532227,
                        "lon": -1.7363977432251
                    },
                    {
                        "lat": 51.6991496086121,
                        "lon": -1.73077583312988
                    },
                    ...
                ]
            }
        ]
    }
}

参数

ECO_PRO_PLUS driving using the efficient Eco mode.
COMFORT driving using comfort mode.

给汽车发送信息

这一步稍微有点复杂。

你的app通过API与汽车联系,然后API与汽车3G模式相连,你便可以等待响应。

如果你的汽车信号比较弱,你最好准备好会等得久一点。

基本层面上,你能够发送一个请求(例如锁好车门或进行一次非峰值的充电)。

获取请求状态

展示了一个POSTed请求。

/webapi/v1/user/vehicles/:VIN/serviceExecutionStatus?serviceType=:SERVICE

地点:VIN便是你汽车的VIN

授权:不记名请求报头信息

响应

{
   "executionStatus":{
      "serviceType":"DOOR_LOCK",
      "status":"EXECUTED",
      "eventId":"[email protected]"
   }
}

参数

有效状态为:

DELIVERED
EXECUTED
INITIATED
NOT_EXECUTED
PENDING
TIMED_OUT

以下都是有效的:服务类型,但你的车辆可能并不支持。

CHARGE_NOW
CHARGING_CONTROL
CLIMATE_CONTROL
CLIMATE_NOW
DOOR_LOCK
DOOR_UNLOCK
GET_ALL_IMAGES
GET_PASSWORD_RESET_INFO
GET_VEHICLES
GET_VEHICLE_IMAGE
GET_VEHICLE_STATUS
HORN_BLOW
LIGHT_FLASH
LOCAL_SEARCH
LOCAL_SEARCH_SUGGESTIONS
LOGIN
LOGOUT
SEND_POI_TO_CAR
VEHICLE_FINDER

Post一个命令

指导汽车执行一个动作。

/webapi/v1/user/vehicles/:VIN/executeService

地点:VIN便是你汽车的VIN

授权:不记名请求报头信息

可用命令

这些命令通过API可进行利用,但是可能无法被你的汽车支持。

这些只是我目前探寻到的。

数据必须被POST到服务器上。

启动充电

如果汽车接入之后,不进行充电(可能由于非高峰设置?),则有可能强迫汽车进行充电。

serviceType=CHARGE_NOW

气候控制

这将激活汽车上的气候控制。

它似乎局限于你上一次在车内设定的温度。我还没找到一个方法来将汽车设定到指定温度。

serviceType=CLIMATE_NOW

锁门

执行中心锁定。

serviceType=DOOR_LOCK

解锁

这将打开车上所有的门。

请在发送这个命令时保持极度谨慎。确保汽车在你的视野范围之内,并且在必要时可以将其上锁。

serviceType=DOOR_UNLOCK

闪光

如果你无法找到车了,或者需要它把附近照亮,你可以简略地激活前灯。

serviceType=LIGHT_FLASH&count=2

我认为这个count值与保持灯亮的秒数有关?!

充电时间

设置峰值/非峰值充电时间表。

serviceType=CHARGING_CONTROL

我并没有把这个搞清楚,但是返回的错误可能会给你一点指示:

{
   "error":{
      "code":500,
      "description":"(SmartPhoneUtil-A-102) Bad value(s) for parameter(s): Invalid chargingProfile, expected weeklyPlanner or twoTimesTimer"
   }
}

车辆仪

serviceType=VEHICLE_FINDER

我并不清楚这是做什么的。

响应

对所有POST命令的响应示例:

{
    "executionStatus": {
        "serviceType": "LIGHT_FLASH",
        "status": "INITIATED",
        "eventId": "[email protected]"
    }
}

接下来会是什么呢?

通过这些命令你便能够复制官方应用程序的功能。

正如你看到的,我设法让我的车发了推特:

如果BMW决定开放他们的官方API,那一定非常有趣,人们便能随意摆弄自己的汽车。API似乎是安全,对车辆的破坏十分有限。

我已经将全部文档上传到了GitHub。有兴趣的欢迎交流。

转载FreeBuf


×

感谢您的支持,我们会一直保持!

扫码支持
请土豪扫码随意打赏

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

打赏作者
版权所有,转载注意明处:昔年博客 » 通过逆向API接口黑掉宝马i3
标签: 系统漏洞
分享本文至:
点击评论 您阅读这篇文章共花了: 

发表评论

路人甲 表情
Ctrl+Enter快速提交

网友评论(0)