Categories
Security Research

CANdy – automated CAN bus message mapping framework

Check out CANdy demo

When I was offered to write a bachelor thesis on the topic of CAN bus message mapping, I had no idea how crucial and fascinating such an area actually is and I would like to share with you what I learned and created during the past six months.

First thing first, what exactly is that CAN bus we are talking about? CAN stands for Controller Area Network, a communication protocol usually used in real-time systems to enable data exchange between each controller and electrical devices (engine sensors, brake systems, air conditioning, etc.). We can find it in many industrial domains but most importantly – transportation. CAN bus is a communication backbone of your vehicle’s internal systems and its importance has risen since every new car model is equipped with more electrical controllers and sensors than the previous one. For instance, CAN provides an efficient and cheap way to send data from engine sensors to the automobile dashboard to show you information about the car’s speed or RPM. However, the protocol only tells how each unit should talk to the other, but does not specify the “language” they ought to use. In other words, there are no general rules imposed on the data payload format. What is more, only car manufacturers are in charge of creating the definitions, which are not publicly available. As a result, we cannot simply connect to the bus and send messages or understand what exactly happens in the car. Such a state provides a certain level of security, that can prevent others from modifying the car internals or injecting malicious messages to its CAN network unless they are given some message definitions. This principle is also known as a “security by obscurity” and is generally considered as an insufficient method for securing any system or application.

Therefore, things can go wrong really easily. Lack of encryption or authentication allows us to forge any message we want and send it to the bus. Let’s say we have the format of the message carrying data from a proximity sensor and the car model uses a really advanced driving assistant, which can automatically detect if you are getting too close behind another car and slow down the car to avoid a possible crash. Now, what could happen when made up data were sent to the bus? With the right data, the driving assistant might slow down the car even if there is no vehicle around and vice-versa. In addition, CAN protocol is susceptible to DoS attacks as there is no mechanism preventing an attacker from flooding the bus with messages. As a result, blocking the whole bus can inflict major damage to the car and put the passengers in danger. Scenarios like these illustrate how easily we can affect the behavior of the car only with access to the CAN bus and why is car security more important than ever. Moreover, the next question is how do we obtain the message definitions for a specific car model.

Finally, this is where message mapping plays a key role. Luckily for us, raw CAN messages are not as random as they appear and we can find some certain patterns and characteristics to help us decode them. The process of assigning an unknown CAN message to a specific function or meaning is what we call message mapping. A few academic researchers have proposed solutions to either classify the messages or detect signals and their parameters, which do not fully recognize what exactly the message represents. Unfortunately, there is no universal method yet to map messages only with a message log from the bus and some level of interaction with the car is still required. Finding a message related to opening the door can be divided into three steps:

  1. Find out which messages are sent to the bus when you physically open the door. 
  2. If there is more than one, look at the payload and discover how does it change when you close or open the door. 
  3. Try to describe every possible state or value that is sent in the message.

It does not sound like big of a deal, right? Sadly, the task is a little bit more complicated than that. First of all, accessing the CAN bus itself could be a quite challenging task, because not all cars have their bus exposed to the OBD-II port. For instance, Volkswagen has its CAN bus hidden behind a gateway, therefore another channel needs to be found instead of a direct connection via OBD-II. In that case, you will have to take a more creative approach, which will require taking your car apart a little bit. Some modern cars may even offer ways to gain remote access, but that is way harder to accomplish still. Secondly, there are hundreds of messages sent to the bus every second and without any dedicated software, it would be impossible for us to navigate through all of that. Finally, this is where our tool comes in handy! CANdy can assort and filter out messages and provide useful information for mapping. It also gives you a better idea of what is going on the bus with its plotting modules and a decoder. What is more, you can write your own modules using its API to add some custom functionality. To better illustrate how CANdy works we would rather show you an example of mapping the gas pedal message using our tool.

This is how traffic on the CAN bus in Toyota Auris 2016 looks like in a span of 0.01 second.
One of our modules helped us detect message ID – 0x2c1, which appears when the gas pedal is pressed. We can get rid of all the noise with a message filter and get cleaner data for our analysis.  
The improved output suggests that some bytes of the payload may carry some useful information. Naturally, the most obvious way to examine such data is making a time series graph. And we have a module for it too.

This plot only shows the first and the seventh byte in the payload. But it is sufficient to recognize the data in the first byte as an indicator whether the pedal is pressed or not, while the seventh byte seems to tell us how much. In order to confirm or dispute our theory, one may look up an official definition for the gas pedal message on the internet or compare your results with someone else. One definition we found on the internet for Toyota Corolla 2017, a very similar model to Auris, describes the message like so:

It is not necessary to dive into details about the format, so we will interpret it for you. The message ID for the gas pedal is 705, which is 2c1 in hexadecimal. Then, there are two signals, which are technically just some values placed in the specified position of the payload. Also, the CAN message data field has a fixed length of 64 bits using zero-based indexing. In this case, it means that the fourth bit in the message indicates the gas pedal is released and the last byte of the payload is used for pressure on the pedal (offset 55 bits, length 8 bits). As we can see, our first guess about the indicator was most probably correct. The latter may be still applicable, because we do not have completely matching CAN definitions, but we cannot be sure either. Another way to test this theory is to try to press the pedal and see which bytes are changing accordingly. Such a task could be carried out with another module we wrote for rendering a real-time plot for a particular message and its bytes.

Ultimately, there are a lot of other units to map with their messages like windows, turn signals, etc. And there is nothing stopping you from trying to hack your car’s CAN bus the same way as we did. CANdy is published as an open-source tool for everyone to try out and for the next step, we would like to gather and publish a crowdsourced database of various CAN definitions. Thus, you are more than welcomed to take a look at CANdy, test it out, and share your results with us. For more information, please check out the paper with technical details and resources. Also, the repository with the tool is available at this link.

Categories
Security Research

[CVE-2020-15779] Path Traversal in Socket.io-file NPM module

Title: Path Traversal in Socket.io-file NPM module
Date: 18/05/2020
CVE-ID: 2020-15779
Advisory: https://www.npmjs.com/advisories/1519
Author: Thomas Sermpinis
Versions: <= 2.0.31
Package URL: https://www.npmjs.com/package/socket.io-file
Tested on: node v10.19.0, Socket.io-file v2.0.31, socket.io v2.3.0
Proof of Concept: https://www.exploit-db.com/exploits/48713

During one of my penetration tests for a local military equipment supplier, I faced a web application running on an embedded device that used web sockets in order to initiate the connection between the server and the client. There are several different technologies that can be used in the back-end system in order to make use of web sockets, but the client made use of Socket.io.

The web application was relatively small, with only a few entry points that did not seem to be vulnerable. All the modules were up to date and my enumeration started to go into a dead end. As there were more days for my pentest, I decided to dig deeper and I started analyzing more the request and researching about the npm modules that were included and were in use in the web application.

One of the functionalities was a configuration file upload, that was stored in a folder in the filesystem, by using the Socket.io-file npm module. Socket.io-file (2.0.31) is a node module for uploading files via the Socket.io module. Playing around with the requests I managed to bypass the restrictions and upload a file in a different folder from the expected one (I knew that as I had access to the backend of the system).

Client and project aside, the upload functionality of socket.io-file is vulnerable to improper input validation, allowing attackers to bypass upload directory restrictions and it allows them to upload files to paths of their choice in the underlying system.

Description of Vulnerability

The default configuration of Socket.io-file comes with an upload functionality handled by websockets. When a user tries to upload a file with the web application, the following client side request is created in order for the file to be created:

Figure 1: Normal websocket request for file upload with Socket.io-file

42["socket.io-file::createFile",{"id":"u_0","name":"testfile.mp3","size":1,"chunkSize":10240,"sent":0,"data":{}}]

In order for this file to be created to the underlying system, the code from index.js of Socket.io-file is executed and the following part of the code, manages to merge the file path (supplied by the socket.io-file configuration) with the file name that was supplied by the user:

if(typeof options.uploadDir === 'string') {uploadDir = path.join(options.uploadDir, filename);}

As an example, if the user uploads a file with the name “testfile.mp3” and the server is configured to store files in the 
“/home/Documents/socket-app/data” 
path the resulting path that Socket.io-file will create the file, will be 
“/home/Documents/socket-app/data/testfile.mp3”.

Because the aforementioned code makes no check on the file name, the upload request can be intercepted and the file name altered in a way that will move in certain paths of the system. The following example exploits this issue:

42["socket.io-file::createFile",{"id":"u_0","name":"../testfile.mp3","size":1,"chunkSize":10240,"sent":0,"data":{}}]

This request will generate the following path for the file to be stored 
“/home/Documents/socket-app/data/../testfile.mp3”
which means that the file will be actually be created in the 
“/home/Documents/socket-app/testfile.mp3” 
as the ../ characters will move the path one level lower in the filesystem.

Figure 2: File created in the node_modules directory of the filesystem, outside the intended directory.

From this example we can understand that we can write in several sensitive directories like the ~/ home directory (which includes the .ssh folder which allows us to rewrite the ssh configuration), in the root webserver directory (which can help us get a reverse shell under the right circumstances) and the cron directory (where we can inject cron jobs for code execution). Additionally, if the back-end system runs with superuser privileges (which is not so uncommon), the attacker can use this vulnerability to create files in even more sensitive paths (e.g. /root and /etc). As an example, we can write the /etc/passd file of our implementation like the following:

42["socket.io-file::createFile",{"id":"u_0","name":"../../../etc/passd","size":1,"chunkSize":10240,"sent":0,"data":{}}]

Issue Replication

In order to replicate the issue, the following steps have to be executed:

  • Setup a proxy to intercept HTTP and WebSocket requests (e.g. Burp Suite or OWASP Zap)
  • Upload a file using the Socket.io-file web application and intercept the websocket request
  • Change the “name” parameter by adding ../ and specifying the needed path:
    • 42["socket.io-file::createFile",{"id":"u_0","name":"../../../Downloads/testfile.mp3","size":1,"chunkSize":10240,"sent":0,"data":{}}]
    • This example will create the testfile.mp3 file in the Downloads directory of the current user (our test server stores files in /home/ubuntutest/Documents/socket-app/data)

Remediation

No fix is currently available. Consider using an alternative package until a fix is made available.

Vulnerability Disclosure Timeline

Following the npm guidelines for vulnerability disclosure (“If maintainers are unresponsive after 45 days, npm Security makes the advisory public”), we responsibly disclosed this vulnerability on 18th of May 2020.

  • Initial Disclosure: 18th May 2020
  • Security Team Validation: 18th May 2020
  • Advisory Release: 7th July 2020
  • CVE-ID Assignment: 15th July 2020
  • PoC Release at exploit-db.com: 27th July 2020