HexBrain

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.

This report was disclosed publicly on HackerOne and belongs to its author and the program. See the original