[socket.io] Cross-Site Websockets Hijacking

Posted on Nov 29, 2021

The socket.io module was vulnerable to cross-site websocker hijacking attack due to the incorrect parsing of the http Origin header. The vulnerability was found in 2.3.0 version.

Socket.IO enables real-time bidirectional event-based communication

original report.

Proof of concept:

app.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');
});

index.html:

<script src="/socket.io/socket.io.js"></script>
        <script>
                var socket = io();
        </script>

Initial connection:

Request and response in burpsuite

HTTP/1.1 101 Switching Protocols means that the connection was successful.

  • Try to change origin to something.io. HTTP/1.1 400 Bad Request is returned and it is good, because we allowed only localhost origin in app.js.

Bad request with origin like something.io

  • Change origin to localhost`something.io

Bypassed

As we can see - the module thinks that the origin is localhost while Safari thinks that it is a subdomain of something.io. Moreover, Safari isn’t the only affected browser. This works in latest Firefox as well. Just replace ` with $.

Impact

After the successful connection from the attacker’s domain, the attacker can receive and send websocket messages on behalf of a user.