Last month I was over in Norway doing training for ProgramUtvikling, the good folks who run the NDC conferences I've become so attached to. I was running my usual “Hack Yourself First” workshop which is targeted at software developers who’d like to get up to speed on the things they should be doing to protect their apps against today’s online threats. Across the two days of training, I cover 16 separate discrete modules ranging from SQL injection to password cracking to enumeration risks, basically all the highest priority security bits modern developers need to be thinking about. I also cover how to inspect, intercept and control API requests between rich client apps such as those you find on a modern smart phone and the services running on the back end server. And that’s where things got interesting.
One of the guys was a bit inspired by what we’d done and just happened to own one of these – the world’s best-selling electric car, a Nissan LEAF:
What the workshop attendee ultimately discovered was that not only could he connect to his LEAF over the internet and control features independently of how Nissan had designed the app, he could control other people’s LEAFs. I subsequently discovered that friend and fellow security researcher Scott Helme also has a LEAF so we recorded the following video to demonstrate the problem. I’m putting this up front here to clearly put into context what this risk enables someone to do then I’ll delve into the details over the remainder of the post:
We elected for me to sit outside in a sunny environment whilst Scott was shivering in the cold to demonstrate just how remote you can be and still control feature of someone else’s car, literally from the other end of the earth. Following is a complete walkthrough of the discovery process, how vehicles in other countries can also be controlled and a full disclosure timeline of my discussions with Nissan.
The LEAF is an electric car which is particularly popular in countries like Norway which offer massive financial incentives to stay away from combustion engines. It does all the things you’d expect of a modern EV and because it’s here in the era of the internet of things, it also has a companion app:
Back at my workshop in Oslo and being the curious type, Jan (not his real name – he requested to remain anonymous) goes back to his hotel after the first day of the course and proxies his iPhone through Fiddler running on his PC as we’d done during the day (this was on January 20). This takes a few minutes to setup and effectively what it means is that he can now observe how the mobile app talks to the online services. Jan then fires up the NissanConnect EV app:
I’m using publicly available screen grabs of the app in part so as not to disclose personal information about Jan and part because his app runs in Norwegian. When the app opens, he observes a request like this (I’ll obfuscate host names and the last five digits of VINs throughout this post):
Which returns the following JSON response:
This is pretty self-explanatory if you read through the response; we’re seeing the battery status of his LEAF. But what got Jan’s attention is not that he could get the vehicle’s present status, but rather that the request his phone had issued didn’t appear to contain any identity data about his authenticated session. In other words, he was accessing the API anonymously. It’s a GET request so there was nothing passed in the body nor was there anything like a bearer token in the request header. In fact, the only thing identifying his vehicle was the VIN which I’ve partially obfuscated in the URL above.
The VIN is the Vehicle Identification Number which uniquely identifies the chassis of his LEAF. It is by no means a “secret” suitable for authorisation purposes, the significance of which I’ll come back to shortly.
On the surface of it, it looked like anyone could get the battery status of Jan’s vehicle if they knew his VIN. Not ideal, but not exactly serious either as it’s a passive query (it doesn’t actually change anything on the vehicle) and there’s also nothing of a personal or sensitive nature returned in the response beyond potentially telling you when it was last driven based on the OperationDateAndTime field. So Jan kept looking.
He found he could check the status of the climate control using this request:
Which then returned a similar status result:
This is reflected within the app on this screen:
But again, it’s passive data – is the climate control on or off and as a result, what should the buttons say. But then he tried turning it on and observed this request:
That request returned this response:
This time, personal information about Jan was returned, namely his user ID which was a variation of his actual name. The VIN passed in the request also came back in the response and a result key was returned.
He then turned the climate control off and watched as the app issued this request:
All of these requests were made without an auth token of any kind; they were issued anonymously. Jan checked them by loading them up in Chrome as well and sure enough, the response was returned just fine. By now, it was pretty clear the API had absolutely zero access controls but the potential for invoking it under the identity of other vehicles wasn’t yet clear.
Connecting to other vehicles
When Jan came into the workshop the following day, he also brought in a picture he’d managed to locate by searching the web:
This was the vehicle's VIN which clearly, left us curious (obfuscation is mine, it’s legible in its entirety on the web).
Let me clarify something before going any further and it’s something I harp on about in my workshops too; when a potential security flaw is identified, you’ve got to think very carefully about how you proceed with verification. You need to have a sufficient degree of confidence that it’s a legitimate flaw before reporting it ethically (which is what we ultimately did), but you also need to ensure you don’t breach someone else’s privacy or impact them adversely in any way. We wouldn’t, for example, want to start operating mechanical features of someone else’s car such as turning on the climate control nor would we want to retrieve personal information about them, even if it was just their username.
The VIN above differed merely by the last 5 digits. We grabbed the number and plugged it into the request to get the battery status – a request that didn’t change anything nor disclose anything private – and got this response:
This appeared to indicate that the response couldn’t be processed but it wasn’t clear why. On reflection, it’s possible that the VIN hadn’t been registered for the app. It could also be possible that one of the query string parameters in the first URL I shared above wasn’t valid for that VIN. For example, the RegionCode field may not have matched with the vehicle’s location. Without a positive result from the API, we couldn’t emphatically conclude that there was indeed a lack of authorisation.
The thing about VINs though is that they’re easily enumerable. Both Jan’s and the VIN found on the web were identical except for the last 5 digits which meant we could easily test for other matches using a tool like Burp suite. We proxied Chrome through Burp then issued the battery status request again:
We then sent it over to the Intruder feature and added one position for payload insertion:
This was the last five digits of the VIN, those being the ones which differed across both Jan’s and the number found online. (Note: not all LEAF VINs necessarily differ by just the last 5 digits, the VIN specification allows for the range to be broader, i.e. it may be the last 6 digits. Our test simply kept the range constrained between known numbers for the sake of time.) We then configured Burp to randomise those last 5 digits and choose integers between 10,000 and 30,000 which is the range both Jan’s and the VIN online fell within:
This gave us the ability to issue requests one after the other, each differing only by a unique VIN in the payload column. We didn’t need to test all 20,000 possible VINs within that range, we just had to issue requests until we found one that returned the battery status of another vehicle. We started Burp issuing the requests:
Request 0 in the screen above is the one to Jan’s car which returned a response size of 631 bytes. The subsequent responses with the randomised VINs mostly returned 288 bytes and the response you see in the screen above. Until we found one that didn’t:
This wasn’t Jan’s car; it was someone else’s LEAF. Our suspicion that the VIN was the only identifier required was confirmed and it became clear that there was a complete lack of auth on the service.
Of course it’s not just an issue related to retrieving vehicle status, remember the other APIs that can turn the climate control on or off. Anyone could potentially enumerate VINs and control the physical function of any vehicles that responded. That’s was a very serious issue. I reported it to Nissan the day after we discovered this (I wanted Jan to provide me with more information first), yet as of today – 32 days later – the issue remains unresolved. You can read the disclosure timeline further down but certainly there were many messages and a phone call over a period of more than four weeks and it’s only now that I’m disclosing publicly, right after I received an email from a Canadian follower…
Vulnerable LEAFs in Canada
By pure coincidence, just as we hit the four-week mark since initial disclosure and I was about to revert to Nissan yet again, an email landed in my inbox from a Canadian follower titled “weird Nissan api”. It started out like this:
I read your Vtech article and though that you would be well placed to appreciate this.
Im a Nissan Leaf owner and I found out that Nissan security is pretty abismal. They have an App to remote start charging, start/stop the AC/Heat, and get updated on current state of the vehicule.
This came in just last weekend on 20 Feb and it went on to explain the following:
I found out that the whole API is unauthenticated and only require the VIN to target a vehicle. To add insult to injury those action are from simple http Get request.
details on how to: (site in french) http://menu-principal-forums-aveq.1097349.n5.nabble.com/Nissan-Canada-Leaf-Carwings-td37239i20.html#a38494
This is precisely what Jan had found in Oslo and what’s more, it was being discussed openly on a forum. Browsing through the discussion courtesy of Google translate, clearly people were not happy with the Nissan app. In fact, they were so unhappy that one post suggests taking the app out of the picture altogether and controlling the vehicle’s functions by making requests directly to the APIs:
For hard-core, the following information:
URL to activate / deactivate air conditioning / heating. Put your VIN in the URL, this works very well in your browser. Create bookmarks with these 2
They go on to conclude precisely what we had earlier on:
In all this, it works for me without being authenticated, which is very surprising, and not safe at all, this means that anyone can act on any vehicle, provided it knows the VIN (in more is it not written down the visible windshield everyone?). Looks like the authentication uses has get the VIN in the user profile.
Now this was back in December so we’re talking a couple of months ago already. Note also that the URLs above are different to the API endpoints we saw for the Norwegian instance (I obfuscated the other host names as I’ve not seem them discussed publicly, but even the paths are different). It’s an odd design decision for a global car manufacturer to segment their app in this way. There are always local idiosyncrasies to be considered (particularly in the auto industry), but there appears to be very little reuse across Canada and Norway in terms of how the API is implemented. It has me wondering if perhaps the build of these apps is delegated to local groups who perhaps don’t pass through the same levels of rigour you’d expect at the global level.
The person who reported the Canadian finding to me finished up by saying this:
My hypothesis on this is that it was bound to surface due to the poor quality of the app, the more tech savvy "with free time" users will thinker with broken things to get them working for them. The fail was probably discovered soon after the app change and multiple times but by people that didn't fully appreciate the greater implication or by people like me that didn't know what to do with that knowledge.
His first sentence is spot on – the ease of discovery of this risk is high as is evidenced by three separate parties already finding it independently (my Norwegian student, the Canadian follower and the folks in the forum). The Norwegian case alone was cause for concern and the Canadian one showed that the issue was now well and truly out there in the public domain, but I wanted further verification which is where Scott Helme came into the picture.
Nissan LEAFs in the UK
It was by pure coincidence that Scott Helme from the video in the intro has a LEAF, that he’s a security professional and that I spent some time with him in the UK just after my Oslo workshop. It was then that the penny dropped and we both realised that he could be of assistance. He’s proofed everything I’ve written here and obviously also offered up his own car to verify that indeed, it’s only the VIN required to operate the functions described in this blog post. Given his involvement, I asked him if he wouldn’t mind sharing his own view of the situation and he gave me this paragraph:
Fortunately, the Nissan Leaf doesn't have features like remote unlock or remote start, like some vehicles from other manufacturers do, because that would be a disaster with what's been uncovered. Still, a malicious actor could cause a great deal of problems for owners of the Nissan Leaf. Being able to remotely turn on the AC for a car might not seem like a problem, but this could put a significant drain on the battery over a period of time as the attacker can keep activating it. It's much like being able to start the engine in a petrol car to run the AC, it's going to start consuming the fuel you have in the tank. If your car is parked on the drive overnight or at work for 10 hours and left running, you could have very little fuel left when you get back to it... You'd be stranded
Of course the other thing we covered in the video was pulling the driving history from the vehicle which looks like this:
These are two trips he took on Feb 21 when he dropped his son off at his parents. He took two other trips that day, one to go snowboarding and another one to return. They were all recorded by the vehicle and are publicly accessible if you know his VIN which again, is displayed in his windscreen or can simply be guessed by enumerating through those last five digits.
This gives you details on movements per day which raises all sorts of privacy risks. Scott gave me a comment on that too.
The other main concern here is that the telematics system in the car is leaking *all* of my historic driving data. That's the details of every trip I've ever made in the car including when I made it, how far I drove and even how efficiently I drove. This could easily be used to build up a profile of my driving habits, considering it goes back almost 2 years, and predict when I will be away from home. This kind of data should be collected and secured with the utmost respect for my privacy.
Whilst it’s not specifically personally identifiable information such as the individual’s address, by the time you have a VIN which you know belongs to a LEAF registered within a specific country, it may not take too much effort to fill that gap. For example, down here in Australia we have services such as revscheck.com.au which can report on a pretty extensive set of data based on nothing more than a VIN. Jan sent me an equivalent service for Norway at vegvesen.no. I suspect that there are multiple other avenues where additional data about the vehicle and the owner can be retrieved once the VIN is known and that opens the door to a raft of other possible privacy risks.
Rectifying the risk and opting out of the service
The underlying risk is simple and I’ll quote Scott’s comments on it:
This API thing is just nuts. It's not even like they just missed auth or didn't check, it's actually not implemented.
It was built, intentionally, without security...
Clearly the answer is to implement appropriate authorisation on all API calls, which when building an app in the first place would be a trivial feature to add. It’s trickier to add to a “brownfield” app though and in Nissan’s case, even trickier again because of the design of it. What’s unique about their approach is that Norway and the UK seem to be hitting a completely different set of APIs to Canada. In fact the European API is on a host not even owned by Nissan, it’s registered to “ZENRIN DataCom CO.,LTD.” which may mean that we’re looking at multiple API endpoints controlled by different parties that need to be rectified. Then of course the apps have to be updated across different client devices (iOS, Android, etc) and for different languages then pushed out to consumers. Whilst waiting for this to happen, LEAF owners remain at risk.
Because the question would inevitably arise, I asked Scott how he’d opt out of the service and he provided some steps:
Given the ease with which someone can enumerate valid VIN numbers, this issue raises a few concerns. It could be a huge inconvenience to have someone run my car flat by using the heating and accessories all day and the exposure of my entire driving history poses quite the privacy concern too. To disable CarWings, owners need to login to the service form their browser, it can't be done through the mobile app. Once logged in, select 'Configuration' from the menu and there is a 'Remove CarWings' button. It appears to be greyed out but the button does work. Once clicked you will receive a prompt to confirm that you wish to disable CarWings and asked to provide a reason why. Click 'Validate' when the appropriate option has been selected and you will get a confirmation message that CarWings has been disabled. You should also receive a confirmation via email. Once Nissan have resolved this issue it should be safe to re-enable your CarWings account and resume using features associated with it. Simply login to your account and follow the prompts on screen.
Existing public domain knowledge
One of the key factors in publishing this now is the existence of multiple other public discussions about the unauthenticated API. The fact that only the VIN is required to invoke these services has been covered at length and published in locations including:
- A GitHub repository documenting the API including the observation that “All other operations take the DCMID and the VIN of your vehicle as parameters for authorizing the requested operation” (although the DCMID value is not actually required and is empty in many of the examples above)
- Another GitHub repository, this time a Python script to connect to and manage vehicle features via the API (also includes region codes for managing vehicles in other parts of the world)
- Yet another GitHub repository built to target an earlier generation of the service and referenced as inspiration for the previously mentioned project
- A blog post on reverse engineering the API which observes that “curiously, it seems like you just need the constant DCMID and VIN fields” (again, the DCMID parameter wasn’t actually used in our tests)
- A forum post on integrating the data into Domoticz (a home automation system) which makes this observation: “No other authentication necessary!”
Whilst I haven’t linked directly to the resources, they’re easily discoverable via Google and demonstrate that there is ongoing public discussion via multiple channels, each documenting the lack of authorisation on the services.
I made multiple attempts over more than a month to get Nissan to resolve this and it was only after the Canadian email and French forum posts came to light that I eventually advised them I’d be publishing this post. Here’s the timeline (dates are Australian Eastern Standard time):
- 23 Jan: Full details of the findings sent and acknowledged by Nissan Information Security Threat Intelligence in the U.S.A.
- 30 Jan: Phone call with Nissan to fully explain how the risk was discovered and the potential ramifications followed up by an email with further details
- 12 Feb: Sent an email to ask about progress and offer further support to which I was advised “We're making progress toward a solution”
- 20 Feb: Sent details as provided by the Canadian owner (including a link to the discussion of the risk in the public forum) and advised I’d be publishing this blog post “later next week”
- 24 Feb: This blog published, 4 weeks and 4 days after first disclosure
All in all, I sent ten emails (there was some to-and-fro) and had one phone call. This morning I did hear back with a request to wait “a few weeks” before publishing, but given the extensive online discussions in public forums and the more than one-month lead time there’d already been, I advised I’d be publishing later that night and have not heard back since. I also invited Nissan to make any comments they’d like to include in this post when I contacted them on 20 Feb or provide any feedback on why they might not consider this a risk. However, there was nothing to that effect when I heard back from them earlier today, but I’ll gladly add an update later on if they’d like to contribute.
I do want to make it clear though that especially in the earlier discussions, Nissan handled this really well. It was easy to get in touch with the right people quickly and they made the time to talk and understand the issue. They were receptive and whilst I obviously would have liked to see this rectified quickly, compared to most ethical disclosure experiences security researches have, Nissan was exemplary.
The ethics of discovery and disclosure
Just one last thing on how these vulnerabilities are discovered and reported because the ethics of this often comes up in my workshops. Risks like the one above were discovered by doing nothing more than using the app as it was intended to be used and observing the traffic going backwards and forwards. This is the mobile equivalent of opening your browser’s dev tools and watching the network tab. Sometimes (such as with the realestate.com.au vulnerability I reported last year), this is all that’s required. Other times and as was the case with the LEAF, it meant testing that the theory of one user being able to access another user’s resource could be proven. In a situation where it’s a car involved, you can’t exactly head out and buy a second one in order to prove that when accessing one you can change a parameter to access another and whilst the proof above did involve checking the battery status of another vehicle, it didn’t involve accessing any personally identifiable information or disadvantaging anyone in any way.
To me, it’s this simple: if the intent is ethical and any findings are reported privately and immediately the moment you’re confident a serious risk is present – and especially if it can be done without viewing anyone else’s private data – then I’m comfortable that’s in everybody’s best interests. If you report before being confident there’s a risk you end up wasting people’s time and if you don’t report, then you end up leaving people – and the organisation involved – at risk. A post such as this one is reviewed dozens of times over by myself and where possible, a peer or peers (Scott, in this case) to ensure fairness and accuracy.
Nissan need to fix this. It’s a different class of vulnerability to the Charlie Miller and Chris Valasek Jeep hacking shenanigans of last year, but in both good and bad ways. Good in that it doesn’t impact the driving controls of the vehicle, yet bad in that the ease of gaining access to vehicle controls in this fashion doesn’t get much easier – it’s profoundly trivial. As car manufacturers rush towards joining in on the “internet of things” craze, security cannot be an afterthought nor something we’re told they take seriously after realising that they didn’t take it seriously enough in the first place. Imagine getting it as wrong as Nissan has for something like Volvo’s “digital key” initiative where you unlock your car with your phone.
By pure coincidence, this week Nissan unveiled a revised LEAF at the GSMA Mobile World Congress. Clearly, like many car makers, their future involves a strong push for greater connectivity in their vehicles:
In a fully connected, fully mobile world, in-vehicle connectivity is an absolute must for today’s drivers. That is why Nissan is proud to be at the forefront of developing efficient and reliable in-vehicle connected technologies that are available and accessible to all
Amongst the list of features the media release talks about being added to the NissanConnect app is the ability to remotely show the vehicle position on a map and analyse your driving. Whilst there are obvious upsides to drivers having access to these features, seeing them presented within the security implementation of the current app would be very worrying for obvious reasons.
I would have preferred to see faster action from Nissan. In my view, this is the sort of flaw that needs to have the service pulled until it can be fixed properly and restored; it’s not a critical feature of the vehicle yet it has the potential to impact its physical function and there’s the privacy risk as well. Plus of course it’s already being discussed publicly via that Canadian forum so the risk is well and truly out in the public domain already. I want to see Nissan secure this; I own a Nissan myself (albeit not a connected one) which I’m passionate about and am very invested in the brand, both emotionally and financially. But they do need to take action on this because clearly the current state is not satisfactory.
Update 1, 25 Feb, 12:00: Nissan has now taken the service offline.
Update 2, 25 Feb, 14:20: Per the comment below and further correspondence I've had via email, it appears that Canadian resources are still accessible using only the VIN.