How a Charge Point Operator accidentally leaked authentication information of all its potential customers

Harm van den Brink
8 min readNov 30, 2023

--

TLDR: I’m a volunteer at the Dutch Institute for Vulnerability Disclosure (DIVD), and in my spare time I try to make the internet more secure. In october 2023 I found a massive leak in the cloud platform (via an application programming interface) of one of the bigger charge point operators (CPOs) in The Netherlands. This API disclosed practically all valid RFID UIDs, which can for example be used to clone a card and charge at another driver’s expense. I followed the charge point operator’s responsible disclosure guidelines, and consequently, the issue was successfully resolved.

Introduction

In my daily work I’m focussing on cyber security in the electric vehicle charging infrastructure, mainly the charge station, the communication and the cloud based management and billing platforms.

In my spare time I’m a volunteer at the Dutch Institute for Vulnerability Disclosure (DIVD). At the DIVD we aim to make the digital world safer by reporting vulnerabilities we find in digital systems to the people who can fix them. We have a global reach, but do it Dutch style: open, honest, collaborative and for free. I’m always looking for ways to make things more secure, analysing with a hacker’s perspective. If issues arise, I report those issues in a responsible disclosure.

Responsible disclosure is the process of responsibly making ICT vulnerabilities public between the researcher and the organization. Anyone can make a responsible disclosure report to a company, government agency, or other organization. The organization then has the opportunity to resolve the vulnerability to avoid abuse by criminals.

This write-up aims to teach developers who use and create APIs how to avoid disclosing excessive information, and outlines measures to minimize necessary disclosures.

I’m omitting the name of the charge point operator as per their request. They responded professionally and resolved the issue promptly. Besides that, they consulted their legal department and their verdict is basically not to mention the name of the company.

Ultimately, our shared goal is to ensure a more secure internet!

How I found the leak

I wanted to add my own RIFD charge card to my charge station at home, so I could charge without any payment at my own charger. My home charger is connected to a charge point operator because I’ve opened it to others to charge. While I was trying to add my RFID card, by using the contract ID (or sometimes refered to as printed number), I found out that the website of the Dutch Charge Point Operator (CPO, the one operating the charge station, for payments, authorization, etc.) reported to me that the contract ID of my card was valid.

A contract ID looks something like this: NL-ABC-E123ABC

Where NL is the country the card is from, ABC is the company who supplied the card, and E123ABC is the ‘unique’ ID in the contract ID. The contract ID alone does not really disclose anything, or cannot be used to charge for free, since it’s only used as a reference. Although some EV apps accept the contract ID as a authorization mechanism.

The fact that the website told me the contract ID is valid or not, made me think that there should be some API (application programming interface) supplying that information about the card.

Using the developer tools in the browser (Chrome in my case), and specifically the Network tab, I quickly found out that the request for the check for the contract ID was sent to an API (application programming interface), with the contract ID as an input. The API responded with information about the card. This looked interesting…

Why it’s a leak at all

The response of the API mostly contained harmless information about the card, the provider of the card, whether the card is valid, and similar information of limited potential for damage. However, they also disclosed the UID of the charge card belonging to the contract ID, the very ID that is used to authorize charging sessions.

In the context of RFID (Radio-Frequency Identification) cards, a UID (Unique Identifier) is a specific code assigned to each card that uniquely identifies it from all others. This UID is embedded in the RFID chip within the card and is used to distinguish one card from another in RFID systems.

The UID is the unique identifier of an RFID card, essentially a serial number. Since only this UID is used by a charge station to determine whether a card is valid or not, this means that one could easily create a copy or clone of that card using an ID obtained from the API leak.

It has been known for years that the charge cards are not secure, since one can easily copy or clone the UID. This was also shown by the Chaos Computer Club in 2017: The convenient charging cards are currently so insecure that it is not advisable to use them.

But to be able to clone the UID, you need to know the UID, as simply guessing a valid UID, while possible, would be highly unlikely to yield a result. This means you usually need to have phyiscal access to somebody’s card to be able to read the UID, so there is a very basic level of protection.

The issue with the API disclosing also the UID, is that you can now clone charge cards without needing physical access to other’s cards by simply iterating through easily guessed contract IDs (see below). And the API even confirms for you whether a card is currectly valid or not.

The response of the API looked something like this

{“uid”:”0123456789ABC”,”printedNumber”:”NL-ABC-E123ABC”,”providerId”:”ABC””, “valid”: “yes”}

(Ab)using the API to get charge card UIDs from other customers

The input for the API was only the contract ID, and since contract IDs are easily guessable you can just try different combinations. If your ID is NL-ABC-E123456, you just try to add one more: NL-ABC-E123457. If you automate this, you can run through thousands and thousands of IDs within minutes. I easily found another (valid) card, and corresponding UID, by just changing the last number of my own card. Like said before, the contract ID alone is not really an issue. But, the UID that was sent with the response of the API basically allows you to get thousands of valid cards within minutes. And copying or cloning those UIDs is a piece of cake 🍰.

I verified the issue, with permission, using the contract ID of a colleague. I fed the contract ID to the API. In response I could see that it was a valid card, and it also gave me the UID.

Using a Flipper Zero, I manually filled in the UID , and pressed “Emulate”. In that way the Flipper Zero starts emulating the cloned UID. By holding the Flipper Zero to a charge station, as if it were a charge card, the charge station was verifying the card: VALID

This told me that the UIDs that were sent in the response, were the actual UIDs of the corresponding charge cards.

Impact of the leak

The API of the Dutch Charge Point Operator basically leaked all the charge cards of all the connected E-mobility Service Providers (the organization who give out cards). This means that a malicious hacker could’ve potentially fetched all charge card UIDs, of all companies giving out cards (in NL or abroad).

The only way to resolve this would be (in the first place using more secure cards!!! and secondly), by replacing all charge cards from all the connected service providers. This would mean that hundreds of thousands of cards, or even more, would need to be replaced. This is extreme costly, and extremly inconvinient for the user as well as the companies.

The responsible disclosure

The charge point operator in this case had a responsible disclosure policy.
A responsible disclosure policy is a set of guidelines provided by an organization that outlines how individuals should report security vulnerabilities found in their products or services. This policy encourages ethical reporting of vulnerabilities by researchers or the public.

I sent them an extended mail with my findings, also date and time, and used IP addresses for verifying the issues. They responded within a week to my mail, and a day after their response the issue was resolved.

How to prevent such a leak in the future?

The API simply discloses more information than needed, it was accessible by anyone who was logged in to the website and was it not rate limited. By only responding with the necessary information, and limiting disclosure of information, this issue could be avoided.

Looking at the OWASP (Open Worldwide Application Security Project), the vulnerabilities found can be classified as:

Insecure Direct Object References

Insecure Direct Object References (IDOR) occur when an application uses user-supplied input to access objects directly, like database records or files, without adequate authorization checks. This vulnerability allows attackers to modify a parameter value, for example in the URL, to access restricted resources, bypassing authorization. It typically happens when the application insufficiently verifies user input before retrieving objects.

Broken Object Level Authorization

Broken Object Level Authorization (BOLA) is when attackers can take advantage of API endpoints with broken object-level authorization by altering the object ID in the request. These IDs, which might be sequential integers, UUIDs, or generic strings, are easily located in the request’s target (like path or query parameters), headers, or even within the request payload. This manipulation enables unauthorized access regardless of the ID’s format.

What should we do next?

The issue with the API shows that an already vulnerable system, gets even weaker when security by obsecurity is also gone. Which should never be a security measure anyway ;)

It’s crucial to thoroughly test APIs for security vulnerabilities, and one effective approach is to use the methodologies and tools recommended by the Open Web Application Security Project (OWASP). OWASP provides a comprehensive set of guidelines, best practices, and tools specifically designed to identify and mitigate security risks in APIs. By adopting OWASP standards, developers and security teams can ensure a more robust security posture for their APIs. This includes testing for common vulnerabilities like SQL injection, authentication issues, and exposure of sensitive data. Implementing OWASP’s recommendations helps in creating APIs that are not only functional but also secure against a wide range of cyber threats.

And besides that we should move to a more secure solution in the electric vehicle infrastructure as quickly as possible, because that fixes a lot of current issues in the infrastructure.

--

--

Harm van den Brink

Cyber security, smart grids, electric vehicles, distributed ledger technology, hardware, DIVD. Owner of Innoshift B.V. Articles on personal title.