Path Traveral in WebSocket/Socket.io-file NPM Module (File-Upload Mechanism)
Path Traversal in Socket.io-file NPM Module
CVE-ID: 2020-15779
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 to initiate the connection between the server and the client. 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. As there were more days for my pentest, I decided to dig deeper and analyze the requests, researching the npm modules used in the web application.
One functionality was a configuration file upload, stored in a folder in the filesystem using the Socket.io-file npm module. Playing around with the requests, I managed to bypass the restrictions and upload a file in a different folder from the expected one.
The upload functionality of Socket.io-file is vulnerable to improper input validation, allowing attackers to bypass upload directory restrictions and upload files to paths of their choice in the underlying system.
Vulnerability Description
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:
42["socket.io-file::createFile",{"id":"u_0","name":"testfile.mp3","size":1,"chunkSize":10240,"sent":0,"data":{}}]In the underlying system, the code in index.js of Socket.io-file merges the file path (supplied by the configuration) with the filename supplied by the user:
if (typeof options.uploadDir === 'string') {
uploadDir = path.join(options.uploadDir, filename);
}For example, if the user uploads a file named "testfile.mp3" and the server is configured to store files in the "/home/Documents/socket-app/data" path, the resulting path will be:
Since there is no check on the file name, the upload request can be intercepted, and the file name can be altered to move to different paths in the system:
This request will generate the following path:
This means the file will be created in:
Example Scenario: Example Web Application
Consider an example web application using Socket.io-file for file uploads.
Setup the Example Application:
Exploit the Vulnerability:
Use Burp Suite or OWASP Zap to intercept the WebSocket request when uploading a file.
Modify the intercepted request to change the file path:
Upload a Malicious File:
Create a file with a name that traverses directories, such as "../../../etc/passwd".
This request will create a file at "/etc/passwd", potentially overwriting the system file and causing severe security issues.
Issue Replication
To replicate the issue, follow these steps:
Setup a proxy to intercept HTTP and WebSocket requests:
Use Burp Suite or OWASP Zap.
Upload a file using the Socket.io-file web application and intercept the WebSocket request.
Change the
nameparameter by adding../and specifying the needed path: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.
Description
A Path Traversal issue was discovered in the socket.io-file package through 2.0.31 for Node.js. The socket.io-file::createFile message uses path.join with ../ in the name option, and the uploadDir and rename options determine the path.
By following these steps, you can reproduce the vulnerability and understand the impact of the path traversal in Socket.io-file.
Last updated