Node.js third-party modules · Report #931197
[socket.io] Cross-Site Websocket Hijacking
Validstatus
highseverity
27upvotes
31 Jan 2021disclosed
Summary
How it was found
I would like to report Cross-Site Websocket Hijacking in socket.io
It allows an attacker to bypass origin protection using special symbols include "`" and "$"
Module
module name: socket.io
version: 2.3.0
npm page: https://www.npmjs.com/package/socket.io
Module Description
Socket.IO enables real-time bidirectional event-based communication
Module Stats
[1] weekly downloads: 3,457,682
Vulnerability
Vulnerability Description
I found this vulnerability while testing one of the private bugbounty programs. This vulnerability can be exploited as a typical csrf vulnerability. An attacker can send and receive WebSocket messages on behalf of a user.
Steps To Reproduce:
npm install socket.io expressjs- Put the following code in to
index.js
var app = require('express')();
var http = require('http').createServer(app);
var io = require('socket.io')(http);
io.origins(['http://localhost:80']); //we believe that this module will decline other origins
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
io.on('connection', (socket) => {
console.log('a user connected');
});
http.listen(80, () => {
console.log('listening on *:80');
});
- Put the following code in to
index.html
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io();
</script>
```
- Run it `sudo node index.js`
- Open the burpsuite and navigate to http://localhost
- Open the proxy tab and send following request to repeater - `GET /socket.io/?EIO=3&transport=websocket&sid={{random id}}`
- Run it. We see `HTTP/1.1 101 Switching Protocols`
{F916713}
It means that the connection was successful.
- Try to change origin to `something.io`, we will see `HTTP/1.1 400 Bad Request` and it is good, because we allowed only localhost origin in our index.js
{F916722}
- Now try to change origin to
```localhost`something.io```
{F916727}
As we can see - the module thinks that origin is localhost while Safari thinks that it is a subdomain of something.io. Also, as I identified Safari isn't the only affected browser - this also works on modern firefox `Mozilla Firefox 79.0b8` as well. Try to change Origin to `http://localhost$something.io` The application still thinks that origin is localhost while firefox thinks that it is a domain `http://localhost$something.io` (During my small research I identified that firefox allows $ in domains names).
## Supporting Material/References:
> State all technical information about the stack where the vulnerability was found
- Os: Linux arch 5.7.9-arch1-1
- Node: v14.5.0
- NPM: 6.14.6
- Mozilla Firefox 79.0b8
# Wrap up
> Select Y or N for the following statements:
- I contacted the maintainer to let them know: [Y/N] N
- I opened an issue in the related repository: [Y/N] N
## Impact
After the successful connection from the attacker's domain, the attacker can receive and send websocket messages on behalf of a user.