Daily Archives: August 4, 2013

Security implications of WebRTC (part 1): The STUN gun

WebRTC compatible browsers use STUN / ICE mechanisms to establish peer to peer connections between endpoints (where possible).

To determine if a direct connection is possible ICE connectivity checks are used. This functionality is encapsulated inside the RTCPeerConnection JavaScript API. A JavaScript application does not require any special permission or consent by the user to use the PeerConnection API (only access to the user’s microphone and camera require the user’s consent).

Receive-only PeerConnections (e.g. for receiving streaming video) use exactly the same STUN / ICE mechanisms as fullduplex connections.

Section 18.5.2 of RFC 5245¬†describes a STUN amplification attack which works by inserting ICE candidates with the victim’s IP address into a SDP offer or answer. Back in the days when this RFC was crafted the attack required the attacker to be in the signaling path to trick ICE agents into flooding the victim with ICE connectivity checks.

The beauty of WebRTC is that there is no defined signaling mechanism, meaning you need to build your own utilizing the PeerConnection JavaScript API. That means now the attacker only needs to be able to inject JavaScript code (e.g. through Cross-site scripting (XSS)) to flood arbitrary hosts with ICE connectivity checks. Appendix B1 of RFC 5235 defines a pacing mechanism limiting the bandwidth used for connectivity checks to the bandwith that the actual media flow would be using (which can be quite significant for video streams).

Tests with Google Chrome have shown that one PeerConnection usually generates around 20 to 25 kbit’s of ICE connectivity checks (no matter how many ICE candidates are provided). By “massaging” the session description passed to the PeerConnection in the SDP answer (e.g. by replacing the short generated ICE credentials with really really really long credentials) this bandwidth generator can be amplified by a factor of 10. After 10 seconds the ICE connectivity checks are stopped by Chrome (FireFox does this a lot earlier creating other problems for regular use cases).

Chrome has a limit of 10 active PeerConnections per browser tab. That means by creating 10 concurrent PeerConnections with long ICE credentials every 10 seconds a malicious script can generate a permanent stream with 2.0 to 2.5 mbit/s of UDP traffic out of thin air, which can be directed at any host (without being bound to any constraints like the usual same origin constraint). The throttling of ICE connectivity checks (in Chrome) is done on each PeerConnection separately which means that all 10 concurrent connections can direct their traffic to the same IP and port.

Fortunately Chrome does not allow ICE candidates with ports less than 1024, so you cannot point your STUN gun towards DNS servers. But there are still some interesting UDP based services running on higher ports (e.g. SIP, OpenVPN, …) and apart from targeting particular services the accumulated bandwidth of a few thousand clients can cause some problems (“plugin-free denial of service”). FireFox does not have any constraints regarding the port of ICE candidates.



By using even longer ICE credentials the amount of generated dos bandwith can be scaled, e.g. an ICE username of 5000 characters and an ICE password of 5000 characters result in around 10 mbit/s of UDP traffic. Shouldn’t there be a length limit for ICE credentials???