Comment 0 for bug 1420942

Revision history for this message
Paul McMillan (paul-mcmillan) wrote :

This is a follow-on to https://bugs.launchpad.net/nova/+bug/1197459, where it was decided that the issues raised there were best practice hardening, but not practically exploitable.

The noVNC websocket token cookie is not set as secure-only. This is practically exploitable by an attacker who can read user traffic.

The setup is as follows:

Nova and horizon configured to serve from https. Nova is patched to resolve #1409142.

User is accessing the cloud through a man in the middle who controls all traffic to and from the user. [1]

user -> attacker -> cloud(https)

Here's what happens:
1) User logs into cloud securely via https://yourcloud.com/
2) User securely accesses a server via websocket VNC and logs in. User (optionally) closes this window.
3) User opens a new browser tab to an insecure site (it can be any insecure site at all)
4) On receiving the request for the insecure site, the attacker fetches it from the source, and rewrites it to include an invisible attack iframe before serving it to the user. [2]
5) The attack iframe directs the user's browser to open http://yourcloud.com:6080 inside the hidden iframe (even if you don't serve that site insecurely)
6) When the user's browser requests http://yourcloud.com:6080, the attacker logs the request including the cookies, and responds with a blank page.
7) The attacker now has access to the auth token used to open the VNC socket (since the most recent one is sent in a cookie), and can stay connected to that socket indefinitely in any browser.

A clever attacker will cycle the iframe contents repeatedly, and steal every VNC socket a user opens as the token cookies change, rather than just the most recent one. As long as the attacker stays connected to the socket, the connection stays open indefinitely.

Fixing this is going to involve letting noVNC know when it is supposed to be behind TLS, and modifying cookie setting behavior accordingly. Django's documentation on this is a good starting place for a fairly standard approach to telling an application it is receiving HTTPS traffic:
https://docs.djangoproject.com/en/1.7/ref/settings/#secure-proxy-ssl-header

-Paul

[1] As a practical aside, it is easy to become this mitm on most local network segments, so users who connect to any network with any untrusted users are vulnerable. An attacker who can only read user traffic (without the ability to block or modify it) can usually become a full mitm by spoofing DNS responses.
[2] the attacker can actually do this step at any point in the process, even before step 1.