freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

汽车黑客揭秘:我是如何通过逆向API接口黑掉宝马i3的
2015-12-16 13:43:54

我(原作者)真的很享受驾驶BMW i3的美好时光。

我可以让这款车发个推介绍自己的驾驶效率,或者将它的坐标上传到我的服务器,当温度太高时我可以打开空调——我能想象出利用汽车数据完成100件有意思的事情。官方应用程序同样具备了一些功能——但是那个APP很慢、极丑,总之非常难用。

BMW曾为“黑客马拉松”提供了可利用API,但是在那之后他们便关闭了它。

那么,现在只有一件事可以做了:黑掉这个大块头!

目标

我们的终极目标是获取通过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":"123456789012345AB1CD1234@bmw.de"
   }
}

参数

有效状态为:

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": "123456789012345AB1CD1234@bmw.de"
    }
}

接下来会是什么呢?

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

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

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

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

*原文地址:shkspr.mobi,空白编译,转载请注明来自FreeBuf黑客与极客(FreeBuf.COM)

本文作者:, 转载请注明来自FreeBuf.COM

# 逆向工程 # 汽车安全 # API # bmw i3 # 宝马 # 汽车API
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
评论 按时间排序

登录/注册后在FreeBuf发布内容哦

相关推荐
  • 0 文章数
  • 0 评论数
  • 0 关注者
登录 / 注册后在FreeBuf发布内容哦
收入专辑