This post will describe how I discovered a security flaw in Pod Point’s mobile app API endpoints. It covers bypassing certificate pinning with Frida, and demonstrate how attackers can steal full names, addresses, charging history, and more by simply having a registered account that anyone can obtain.

Pod Point

Pod Point is a UK based company established in 2009 that provides electric vehicle charging equipment to both businesses and individuals. It also operates what’s called the “Pod Point Network” where customers can use charge points across the country with a mobile app.

Initial Discovery

In March 2021, I researched EV charging providers. Most offered similar services and products. But since I didn’t want to spend any money buying physical hardware, I opted to check out their mobile apps instead.

After registering a test account, I then started to look for any interesting features. I quickly noticed that the My Account menu had an option called “Add Home Charger, " allowing users to add Pod Point devices to their account by providing a unique device serial number.

A quick Google image search revealed that serial numbers prefixed with “PSL” require a 6-digit number. As a quick sanity check, I entered a random number of “111111” to see if any devices existed.

alt text

Figure-1: Android mobile app Pod Point “Add Home Charger” menu.

Above is a screenshot of the “Add Home Charger” menu with a randomly chosen device serial. After tapping “Add my home charger”, a confirmation message with a partial email address of the primary account holder is shown.

A device with the serial number “PSL-111111” already exists and belongs to an account. To add this device requires additional permission from the primary account holder in the form of an email confirmation link. It was pretty interesting seeing a partial email address.

Diving Deeper

To continue our research we needed to see how the app communicates with the backend services. To do this we set up a Burp Suite, a proxy listener was configured on a testing machine, and then we updated the test mobile device’s network settings.

I immediately hit a slight road block because the mobile app utilities Certificate Pinning.

alt text

Figure-2: Burp Suite certificate error.

Bypassing certificate pinning

Certificate pinning is a method used by app developers to restrict certificate usage. A Certificate Authority (CA) is usually ‘pinned’ to the app itself, and all other certificates are rejected, including root certificates trusted by the system.

To bypass this security measure, I opted for using the excellent instrumentation toolkit called Frida. Frida can attach to a process (app) and change the return values of functions. For example, it can inject into a function call that checks a certificate’s common name. I used a hook written by Tim Perry.

A quick overview of steps:

  1. Connect to a rooted device using adb
  2. Start a Frida server as root
  3. Locate the Pod Point app package name (com.podpoint)
  4. Launch the Pod Point app with Frida and a Hook.js

Here is the app using Frida with a specific ceritificate pinning bypass hook:

frida -U -l hook.js -f com.podpoint --no-pause

[Pixel 3a::podpoint]->
[+] Bypassing OkHTTPv3 {1}: api.pod-point.com

Frida detected and hooked into an OkHTTPv3 function that checks for a certificate with the common name (api.pod-point.com). It changed the return value to null or false. When going back to Burp Suite, the sitemap in the target menu now shows the website paths, meaning Frida bypassed certificate pinning.

alt text

Figure-3: A list of paths of api.pod-point.com in burp suite site map.

Identifying API endpoints

The app talks to a server called api.pod-point.com. Multiple API endpoints relate to individual actions requested by the app. But not all APIs leak customer information. Some provide standard functionality required for users to log in and manage their accounts.

  • /v4/addresses – public available charge addresses
  • /v4/units – customer data and devices
  • /v4/users/<USER_ID>/charges - customer full charge history
  • /v4/pods – data on pod devices
  • /v4/auth – logged-in user information
  • /v4/sessions – authentication (email and password)
  • /v4/password_reset – reset account passwords

I’ll only be focusing on the first three API endpoints, which leak sensitive customer data or can be abused. The following few sections go into more details of how and what data is actually leaked.

Getting customer data

When adding a Home Charger to your account. A HTTP GET request /v4/units?ppid={DEVICE_SERIAL} is sent to the server address api.pod-point.com. The request header includes an authorisation bearer token which is the user authentication. Any logged-in user can obtain this token.

alt text

Figure-4: A request showing sensitive information of a customer being exposed.

You can see on the right side of the screenshot the server responds with a JSON object. This object contains a nested object called “installation”, which shows customer information and details about the device and its installation.

A list of customer’s data is revealed:

  • Customer’s unique user identification
  • Customer’s full name
  • Customer’s full address
  • Customer’s partial email address

We have also seen other information on Pod Point devices including, the device last contact date, contactless status and unique device identifier. Attackers can use this to gather intelligence to know whether a customer’s vehicle is charging.

Additionally, querying the endpoints with empty values returns a paginated data stream of (5652 pages with 25 records per page), indicating over 141,289 private customer records exposed on the Internet.

Getting customer data via email address

Not only is it possible to retrieve sensitive customer data by enumerating serial number but also using the primary account holder’s email address. The API endpoint /v4/units allows users to query other customers’ data by using a parameter called customer_email.

Here is an example of a HTTP GET request retrieving data using a specific email address:

GET /v4/[email protected] HTTP/1.1
user-agent: POD Point Native Mobile App
[...]
Authorisation: Bearer Token [...]
Host: api.pod-point.com

This is quite scary because if somebody knows your email address and knows that you use a Pod Point device. They can work out your full address by sending a simple HTTP request to the backend API endpoint.

Getting customer charge history

Using a customer’s ID it is possible to retrieve the entire charge history from the day they created their account. Just like with serial numbers the customer ID can be enumerated in the same way.

This API endpoint /v4/users/{USER_ID}/charges is responsible for retrieving charge history of customers. The server responds with a JSON object that shows information such as (start and end times, duration, costs, locations, kW usage) and more.

Here is an an example of a HTTP GET request to retrieve a user’s charge data:

GET /v4/users/{USER_ID}/charges HTTP/1.1
user-agent: POD Point Native Mobile App
[...]
Authorisation: Bearer Token [...]
Host: api.pod-point.com

And the response we get back a JSON object with charge information:

{
    "charges": [
        {
            "id": 17537077,
            "kwh_used": 0.3,
            "duration": 25,
            "starts_at": "2021-05-30T06:13:10+00:00",
            "ends_at": "2021-05-30T06:38:37+00:00",
            "billing_event": {
                "id": 2954682,
                "amount": 0,
                "currency": "GBP",
                "exchange_rate": 1,
                "presentment_currency": "GBP"
            },
            "location": {
                "id": 4522,
                "home": false,
                "address": {
                    "id": 1301,
                    "business_name": "Tesco Extra - Llansamlet"
                }
            },
            "pod": {
                "id": 58782
            },
            "energy_cost": 4
        },
...

The API endpoint /v4/users/{USER_ID}/favourites does exist, which shows favourite charge locations, but access is restricted. However, attackers can still work out favourite locations by cross-referencing the location ID with the API in the next section.

Getting public charge locations

This particular API doesn’t expose any personally identifiable information since it’s used in helping users find local charge points. However, it can be abused by combining the previous example, which could allow attackers a way to figure out charge locations and predict their next location.

This API endpoint /v4/addresses returns a massive collection of Pod Point device addresses. Each page has metadata that shows there are approximately 15,000 devices. Unlike other API endpoints, I was not able to find usable search parameters apart from the page number.

An example of a HTTP GET request sent to /v4/addresses?page=218:

And the response shows an address which belongs to a police station in Wiltshire, GB.

{
    "addresses": [
        {
            "id": 58036,
            "name": "HQ-Front FM hangar (left)",
            "description": "",
            "pod_count": 1,
            "type": "Government",
            "roadside": false,
            "restrictions": true,
            "email": "[email protected]",
            "location": {
                "lat": 51.3562169,
                "lng": -1.9841969,
                "evZone": false
            },
            "address": {
                "business_name": "HQ-Front FM hangar (left)",
                "address1": "London Road",
                "address2": "",
                "town": "Wiltshire",
                "postcode": "SN10 2DN",
                "country": "GB"
            },
...

Summary

The analysis has shown the Pod Point mobile app has several API endpoints which expose customer data. All that attackers need is to have a registered account. In addition, there is no limit to the number of requests a user can make, which makes it possible for an account and device enumeration. As long as the authorisation bearer token is valid, attackers can enumerate device serial numbers and harvest customer data.

Disclosure timeline

  • 15-Mar-2021 – Initial discovery
  • 30-Jun-2021 – The first email sent to Pod Point support (no response)
  • 10-Aug-2021 – A second follow-up email sent to Pod Point support (no response)
  • 02-Sep-2021 – A third email sent to Pod Point app feedback (no response)
  • 21-Sep-2021 – A fourth email sent to Pod Point support (no response)
  • 28-Sep-2021 – Contacted Which? to help with the disclosure
  • 30-Sep-2021 – Pod Point fixes the issue