Hacking the traffic light of the future

Hacking the traffic light of the future

Nowadays we are connecting everything we can think of to the internet. Usually to make our lives easier or more comfortable. Some of the new upcoming innovations are related to making our traffic smart with the goal to improve safety, comfort and the traffic flow. We dived into this technology to analyze the inner workings and identify potential security risks.

TLDR: watch our DEFCON talk on YouTube.

Recently we stumbled upon videos and information that got our attention. In the Netherlands, a project was launched to connect traffic lights to the internet. There were multiple initiatives to do so, started by different vendors in various cities. A use case would be to turn the lights green faster as a vehicle or cyclist approaches. Or allowing emergency vehicles instantly green if their blue light is turned on.

This is already done for decades using physical solutions on the road (“loops”) or by using short range communication (e.g. radio, microwave, infrared), but by incorporating the internet allows for a range of new opportunities and flexibility.  The overall idea of the innovation is to improve the accessibility, traffic flow, traffic safety and quality of life on the road network through real-time information exchange.

When we saw the project for the first time, instantly the question popped up: how does this work and what happens if this would be manipulated by a malicious actor?

After diving into the subject, it appeared that multiple traffic lights, located in the Netherlands, were already connected to the internet. These traffic lights recognize cyclists running a specific app on their phone. After detecting an approaching cyclist, the Traffic Light Controller on the intersection will decrease the time to green if possible.

There are different apps to cover several types of road users, for example:

  • Pedestrians
  • Cyclists
  • Trucks

We decided to continue our research with the cyclist apps because in that domain multiple apps were already publicly accessible to us.

Important note for the people outside of the Netherlands: in the Netherlands we do have a lot cycling infrastructure (about 35.000 kilometres) and about 22.8 million bicycles (which is more than citizens). This results in almost every intersection having traffic lights that are specificly placed for cyclists, which we’ve learned is not so common in other countries. If you’ve ever been to Amsterdam you know cyclists are everywhere: an (environmental) blessing in (chaotic) disguise.

Diving into the first application

One of the first “smart” traffic lights we found was clearly a proof of concept environment: there was even a separate indicative “Cyclist Seen” light showing whether a cyclist with active app was recognized by the system.

We started off by downloading and unpacking the Android application to get insights into the code of the application. The first interesting thing we saw in the application was code indicating that MQTT (Message Queueing Telemetry Transport) was being used. We discovered a server MQTT IP-address, username and password were hardcoded in the apps. So, we concluded MQTT was the protocol our app used to communicate with the traffic lights.

MQTT is a protocol that is widely used in the Internet-of-Things. In a nutshell: it is a lightweight protocol that consists of channels. The MQTT Clients can subscribe and/or publish to these channels, to read or share messages on the channels. For instance, a user of the app would share a message to a certain channel, which a traffic light would be subscribed to and triggered a workflow. We decided to do more in-depth investigation.

ETSI CAM objects

After a while we found the next rabbit-hole: Cooperative Awareness Message (CAM) objects, which were distributed using the MQTT protocol. CAM objects were introduced as part of a standard developed by ETSI to improve data exchange among technology providers.

The CAM standard was specifically developed to share traffic related information. A CAM-object contains a wide range of information about a vehicle, such as:

  • longitude / latitude (GPS location)
  • vehicle type
  • speed
  • lane position
  • siren / light bar status

The CAM objects were sent to the backend system over MQTT. This allows a vehicle to report, in a very detailed way, the properties of itself while passing the traffic light. The nature of CAM objects got us excited: we might be onto something here. The openness of CAM objects allowed us to manipulate a lot of properties describing a vehicle. If the backend system would accept our manipulated CAM objects, unexpected behaviour might occur.

Manipulating the CAM object station type

At this stage we wanted to manipulate the CAM objects and verify whether the backend performs any checks to prevent manipulation. Initially we were trying to connect to the MQTT channel ourselves and craft our own CAM object. However, CAM objects were very specific to the automotive sector and quite exotic (at least unknown to us). We ended up in a rabbit hole, trying to re-use code used by the original app for Android. Our goal was to figure out how to craft CAM objects and encode them in the correct way (protobuf and ASN encoding). It was a terrible experience ;-)…

So, after a while we decided to take another approach. We figured to use the functionality in the app itself to manipulate the CAM objects from there. A great tool to accomplish this is Frida, an incredible powerful tool to hook into (Android) applications. It basically allowed us to hook into the application at a specific point, modify some values and let the application handle the rest.

It was the first time for us using Frida, so it was a great learning adventure. The first attempt we performed was to hook into the application at the correct function in order to view the CAM objects that are being sent by the application. After some trial and error, we successfully hooked into the correct function to print out the current CAM object just before it was sent onto the MQTT channel:

CAM-object content snippet

value basicContainer ::= {
  stationType cyclist,
  referencePosition {
    latitude 51xx,
    longitude 50xx,
    positionConfidenceEllipse {
      semiMajorConfidence unavailable,
      semiMinorConfidence unavailable,
      semiMajorOrientation unavailable
    },
    altitude {
      altitudeValue 4000,
      altitudeConfidence unavailable
    }
  }
}

We got insights into the CAM object contents. Is it possible to manipulate these contents? We succeeded in writing a script that calls a function that modifies the stationType (which contains the type of road user sending the message), to whatever value we want. For example, in the following CAM object we were able to modify the stationType from our CAM objects from ‘cyclist’ to ‘tram’ just before publishing the CAM object:

Modified the CAM-object

value basicContainer ::= {
  stationType tram,
  referencePosition {
    latitude 515623160,
    longitude 50737430,
    positionConfidenceEllipse {
      semiMajorConfidence unavailable,
      semiMinorConfidence unavailable,
      semiMajorOrientation unavailable
    },
    altitude {
      altitudeValue 4000,
      altitudeConfidence unavailable
    }
  }
}

So, it was possible to modify the CAM object properties before sending it onto the MQTT channel.

Manipulating the CAM object GPS coordinates

The CAM object contains so many properties to manipulate. One of them which should be easier to debug are the GPS-coordinate properties. After all: the separate “cyclist seen” light we mentioned earlier, could be used to confirm whether the system responded to our input. We created a Frida script that modifies the following properties in the CAM object:

  • longitude
  • latitude
  • speed
  • bearing
  • accuracy
  • altitude

The script keeps on repeating two different GPS coordinates to fake a cyclist that is continuously passing the traffic light.

Two coordinates are required in order to look like a legit cyclist. The system will only respond if a cyclist is actually cycling. By running this script, the cyclist-seen-light turns on one-time, which proofs that the system sees our fake cyclist as a legit one. However, we wanted to trigger as much green as possible, to determine how far we could manipulate the light.

In order to do so, we created another script. During the research we discovered that every new MQTT connection was identified as a new cyclist. So, we created a new script: that just reconnects every time just before publishing our CAM object :-). We were hoping that the backend would see the following behaviour:

At the traffic light location, we could verify that the thing we expected occurred 🙂

By running both scripts, we emulate a continuously ongoing flow of cyclist passing the traffic light. This results in the actual traffic light controller to decrease the waiting time to green as much as it is allowed to. The behaviour that we trigger can be compared with a person pushing the physical button located at the traffic light all the time. The safety systems stay intact. So if the cyclists light turns green, the other lights (e.g. car lights), will be red and vice versa.

Diving into the second application

Later we found another project with traffic lights connected in 10 municipalities. An application was publicly available, so we were able to download and investigate it. This application was easier to investigate: we were able to configure an Android phone with the application proxying all of its request through our Burp proxy. This allowed us to see all the HTTPS connections that were sent to a cloud service.

We found out that the actual requests being sent by the application were quite simple. Information was sent to the cloud service using a POST-request. The POST-request contained data similar to this:

POST-request example

[{“heading”:<DIRECTION>,”latitude”:<LATITUDE>,”longitude”:<LONGITUDE>,”speed”:<SPEED>}]

As seen in above POST data, the application sends information such as speed, heading and GPS-coordinates to the cloud server. After debugging at a actual connected traffic light, we discovered the following:

  • Just one HTTP request was enough to influence the traffic light;
  • No authentication was required;
  • No way to distinguish different cyclists from each other was available (a unique identifier or something like that).

We were able to convert our findings in an exploit, a Python scripts that sends one POST request to the cloud service. By running the script, the following behaviour occurs at the traffic light:

  • if there is other traffic at the intersection: it decreases time to green of the cyclists light
  • if there is no traffic at the intersection: it instantly turns green

In order to show above situations, we recorded two demo’s:

Impact

We found something interesting in both implementations. Both platforms are not really able to distinguish the cyclists from each other. One application is seeing every MQTT connection as a new cyclist, the other one is seeing every new HTTP connection as a new cyclist.

That is an interesting fact: this allows us to imitate a lot of cyclist at once. Imagine: just request all the cycling traffic lights in a city to turn green continuously in a loop. That would result in the cyclist light turning green as much as the local traffic light system / configuration allows it to. Whenever the cyclist light is turned green, the other traffic will get a red light. This will be quite annoying for the other road users.

In order to show how this could look like while attacking many traffic lights in a city, we created the following fictional visualization:

Luckily that’s the current impact: annoying. Two lights will never turn green simultaneously. The built-in security system prevents this to happen. On the other hand we can influence the traffic flow (one of the goals of smart traffic) in a negative way, letting a lot of people wait for nothing. Or let them stop all the time for no reason. And by talking to people involved we did understand that annoyed road users are dangerous road users, so there does seem to be an indirect safety impact.

Conclusion

Our proof of concepts allow us to remotely influence the affected traffic light systems. From any remote location, we can simulate cyclists approaching, causing the system to decrease the time to green (or even get instant green). Currently, this attack could be performed on traffic lights in about 10 municipalities.

The current findings are limited to the cycling traffic lights. This does have an effect on the car lights, it will turn them red whenever the cyclist light goes green, but we cannot do it the other way around yet with the current implementations.

We investigated the standards being used. These standards describe and support security measurements to prevent our findings. For example, the CAM standard supports signing. In the real life implementations we investigated, these standards are not or not used correctly.

The consequences of these kinds of attack would be bigger if an attacker succeeds to use the same trick to influence the car traffic lights or even simulate emergency vehicles (instant green). This would have a much greater impact on the regular traffic flow: just consider how car drivers respond now to an ambulance approaching.

It is a really cool innovation that’s going on. Smart traffic lights to increase the usability of the traffic light system. However, we really have to build these systems with security in mind. These systems can directly impact people’s lives. At Zolder we get excited by these kinds of innovations. We believe the innovations are both important as well as inevitable. We just need to figure out how to do this safely. We performed this investigation to create some awareness on this topic. However, finding the correct solution is not that easy, because in the end we do have to trust input from road participants.

At Zolder we believe these innovations are on one hand generally beneficial to society and on the other hand simply unavoidable and that the amount will rapidly increase the upcoming years. We reported our findings to both developers so they could fix the issues in their implementations. With sharing our findings at the DEF CON conference we hope to inspire others to contribute to a safer smart traffic future.