Closed Bug 1735923 (CVE-2022-31736) Opened 3 years ago Closed 3 years ago

Leaking size of cross-origin resources by using Range Requests and Service Workers

Categories

(Core :: Audio/Video: Playback, defect)

defect

Tracking

()

VERIFIED FIXED
102 Branch
Tracking Status
firefox-esr91 101+ verified
firefox100 --- wontfix
firefox101 + verified
firefox102 + verified

People

(Reporter: luan.herrera, Assigned: karlt, NeedInfo)

References

()

Details

(Keywords: csectype-sop, sec-high, Whiteboard: [reporter-external] [client-bounty-form] [verif?][adv-main101+][adv-esr91.10+], [wptsync upstream])

Attachments

(7 files)

Attached file index.html (deleted) —

When a cross-origin resource is used in an audio/video tag, a request containing the Range header asking for "bytes=0-" is issued.
If the request is intercepted using a Service Worker and we respond with an arbitrary Content-Range header, e.g:
e.respondWith(new Response("A", {status: 206, headers: { "Content-Range": "bytes 0-1/5000", "Content-Type": "audio/mp4" }}));

Firefox will be tricked into thinking it got the first byte of the audio/video and then ask for the remaining bytes by issuing a new request containing the "Range: bytes=1-" header.

If we decide not to intercept the subsequent request, it will go directly to the server and ask for the remaining bytes, and the response will contain bytes ranging from 1 to the total bytes of the cross-origin response.

If the total number of bytes from the cross-origin response is smaller than the total amount we stipulated when we intercepted the initial ranged request, Firefox will be fooled into thinking it needs to request more bytes, and the target's server will throw a "416 Range Not Satisfiable" error response code as it is not able to fulfill the request (as it already sent all bytes for that particular request).

We can detect when this behavior happens by counting the number of resources in performance.getEntries(), allowing an attacker to leak the exact size of cross-origin resources that accept range requests.

In the PoC, the size of https://www.google.com/robots.txt is being brute-forced starting on byte 7260. In a real attack, it would be trying to get the size through binary search.

This vulnerability is useful for XS-Search attacks. A real-world example is https://medium.com/@luanherrera/xs-searching-googles-bug-tracker-to-find-out-vulnerable-source-code-50d8135b7549 (more on https://github.com/xsleaks/xsleaks/wiki/Real-World-Examples).

This is a variation of a bug I reported to Chrome a few years ago (https://bugs.chromium.org/p/chromium/issues/detail?id=990849).

Here's a video reproducing the issue:
https://youtu.be/pj2tvVRzglg

VERSION
Version: 93.0 (64-bit)
Operating System: Windows 10

REPRODUCTION CASE

  1. Access https://lbherrera.github.io/lab/firefox/range-0553e1f/index.html
  2. Click on the "check" button and after a moment you should see messages about the leaked size of the cross-origin resource.

I have also attached the files used in the PoC - if you prefer, you can reproduce the attack by downloading and hosting index.html and sw.js on a web server.

CREDIT INFORMATION
Reporter credit: Luan Herrera (@lbherrera_)

Flags: sec-bounty?
Attached file sw.js (deleted) —
Group: firefox-core-security → dom-core-security
Component: Security → DOM: Service Workers
Product: Firefox → Core

Looking at the Chromium discussion, it seems that we need to produce performance entries also when the server returns a 416 response. I'm not sure what the right component for that is.

Component: DOM: Service Workers → Performance

I think the fundamental problem here (as also detailed in the Chromium bug mentioned above in a comment by Jake) is https://github.com/whatwg/fetch/issues/144#issuecomment-368040980. There was some work on addressing this in the HTML standard for media elements in https://github.com/whatwg/html/pull/2814 but that has stalled unfortunately. Nevertheless, we need to address it in Firefox. Allowing opaque and non-opaque responses to be mixed is dangerous.

Luan, did you report this bug to Chrome as well? Because it sounds like they didn't go for the fix Jake recommend and instead addressed the symptom, which I would expect not to work long term.

Component: Performance → Audio/Video

(In reply to Anne (:annevk) from comment #3)

I think the fundamental problem here (as also detailed in the Chromium bug mentioned above in a comment by Jake) is https://github.com/whatwg/fetch/issues/144#issuecomment-368040980. There was some work on addressing this in the HTML standard for media elements in https://github.com/whatwg/html/pull/2814 but that has stalled unfortunately. Nevertheless, we need to address it in Firefox. Allowing opaque and non-opaque responses to be mixed is dangerous.

Luan, did you report this bug to Chrome as well? Because it sounds like they didn't go for the fix Jake recommend and instead addressed the symptom, which I would expect not to work long term.

Hey Anne, a few days after submitting this report I found a different variation that works on Chrome and sent a report to them as well. As far as I can tell, the fix they plan will require a spec change (they said they have an agreement from Mozilla and the spec editor to make this change via private communication), but it seems it will tackle the symptom and not https://github.com/whatwg/html/pull/2814.

The severity field is not set for this bug.
:bryce, could you have a look please?

For more information, please visit auto_nag documentation.

Flags: needinfo?(bvandyk)

Paul, any thoughts here, sounds like we might need to wait on some spec changes to address.

Severity: -- → S2
Flags: needinfo?(bvandyk) → needinfo?(padenot)

I don't think we should wait for specifications to change as fixing this there is quite involved and hasn't been prioritized. (This area has been known to be problematic for at least five years.)

  1. Jake's fundamental fix is essentially not allowing mixing of non-opaque and opaque responses in media elements. Arguably one problem here is that the cross-origin request is still made. It seems like it should be possible to network error earlier when we detect a cross-origin request after we've started using same-origin responses.
  2. There's another solution to this problem outside of media elements, which is that we fix Resource Timing along the lines suggested in https://github.com/w3c/resource-timing/issues/165, but it's not clear to me that it could not be exploited in other ways. E.g., it seems timing the cross-origin response might also give the attacker some information about whether it's a 206 or 416. (There's also https://github.com/whatwg/fetch/pull/1311 about exposing network errors to Resource Timing as well, but there's no agreement on that yet.)

(In reply to Anne (:annevk) from comment #7)

It seems like it should be possible to network error earlier when we detect a cross-origin request after we've started using same-origin responses.

Probably, as long as this has no Web Compat implications, it was an issue last time.

Flags: needinfo?(padenot)

Waiting on some spec discussions.

Keywords: stalled
Keywords: stalled

After some discussion, we're going to take a shot at implementing option #1 in comment 7.

Flags: needinfo?(padenot)
Assignee: nobody → padenot
No longer blocks: media-triage
Assignee: padenot → karlt

Firefox adds ResourceTiming entries for both 206 and 416 responses.
In Firefox, a shorter than ServiceWorker-exagerated cross-origin resource is distinguishable due to Firefox making an additional range request when the cross-origin server returns a shorter response than expected.

The expected length is set based on the range total from the initial response (from the ServiceWorker in this case).
The expected length can be increased when a longer response is received, but the final assessment that could have used the total bytes received to correctly shorten the expected length is not reached before the additional request is sent due to a comparison based on the incorrect length.

Status: UNCONFIRMED → ASSIGNED
Ever confirmed: true
Component: Audio/Video → Audio/Video: Playback

(In reply to Anne (:annevk) from comment #7)

  1. Jake's fundamental fix is essentially not allowing mixing of non-opaque and opaque responses in media elements.

That alone is not going to resolve the issue here as the length is already exposed to the ServiceWorker when the media element makes the additional range request (which later happens to respond with 416), so I've split this off into bug 1762068.

Arguably one problem here is that the cross-origin request is still made. It seems like it should be possible to network error earlier when we detect a cross-origin request after we've started using same-origin responses.

Filed bug 1762078 for that, addressing which would require going off spec.

This and bug 1762068 can be addressed without requiring any spec change that has not yet been agreed.

(In reply to Karl Tomlinson (:karlt) from comment #12)

(In reply to Anne (:annevk) from comment #7)

  1. Jake's fundamental fix is essentially not allowing mixing of non-opaque and opaque responses in media elements.

That alone is not going to resolve the issue here as the length is already exposed to the ServiceWorker when the media element makes the additional range request (which later happens to respond with 416), so I've split this off into bug 1762068.

I was wrong here. That additional range request is not made when bug 1762068 is addressed, so I'll fold bug 1762068 into this.

I'll address comment 11 in bug 1765025.

Comment on attachment 9272577 [details]
Bug 1735923 - error on opacity change r?edenchuang

Security Approval Request

This bug report identifies a further exploit, which is similar but different to a public Chrome issue..

The patch changes the results of a test that uses related techniques, but still different from the exploits mentioned here.

  • Do comments in the patch, the check-in comment, or tests included in the patch paint a bulls-eye on the security problem?: Yes
  • Which older supported branches are affected by this flaw?: All
  • If not all supported branches, which bug introduced the flaw?: None
  • Do you have backports for the affected branches?: Yes
  • If not, how different, hard to create, and risky will they be?: The surrounding code has not changed since June 2019, so any conflicts for backports should be limited to expected test results.
  • How likely is this patch to cause regressions; how much testing does it need?: Gecko already has reasonably different behavior with range requests in ServiceWorker, so I'm not expecting sites to be depending on Gecko's vulnerable behavior.
    If any sites are depending on the vulnerable behavior, then I don't know how we could continue to support them.

The key area of risk might be if the patch should error on media element load in an unintentional situation. Existing tests were helpful in identifying flaws in previous iterations of this patch.

  • Is Android affected?: Yes
Attachment #9272577 - Flags: sec-approval?

Comment on attachment 9272577 [details]
Bug 1735923 - error on opacity change r?edenchuang

Approved to land and uplift

Attachment #9272577 - Flags: sec-approval?
Attachment #9272577 - Flags: sec-approval+
Attachment #9272577 - Flags: approval-mozilla-beta+
Group: dom-core-security → core-security-release
Status: ASSIGNED → RESOLVED
Closed: 3 years ago
Resolution: --- → FIXED
Target Milestone: --- → 102 Branch

Landed for 101.0b3.
https://hg.mozilla.org/releases/mozilla-beta/rev/cc3d50e3408b

Please nominate this for ESR uplift too when you get a chance.

Flags: needinfo?(karlt)

Comment on attachment 9275133 [details] [diff] [review]
error on opacity change - for esr91

ESR Uplift Approval Request

  • If this is not a sec:{high,crit} bug, please state case for ESR consideration: sec-high
  • User impact if declined:
  • Fix Landed on Version: 102
  • Risk to taking this patch: Medium
  • Why is the change risky/not risky? (and alternatives if risky): The key area of risk might be if the patch should cause error on media element load in an unintentional situation. Existing tests were helpful in identifying flaws in previous iterations of this patch.
Attachment #9275133 - Attachment is patch: true
Attachment #9275133 - Flags: approval-mozilla-esr91?

Comment on attachment 9275133 [details] [diff] [review]
error on opacity change - for esr91

Approved for 91.10esr.

Attachment #9275133 - Flags: approval-mozilla-esr91? → approval-mozilla-esr91+
Depends on: 1764515

Ah, sorry. We need to uplift the fix for bug 1764515 before landing this on esr91.

Flags: needinfo?(karlt)
Flags: qe-verify+
QA Whiteboard: [qa-triaged]

Verified as fixed on Windows 10 x64, macOS 11.6 and on Ubuntu 20.04 x64.

(In reply to Karl Tomlinson (:karlt) from comment #27)

Ah, sorry. We need to uplift the fix for bug 1764515 before landing this on esr91.

Assuming this needs Ryan's attention then?

Flags: needinfo?(ryanvm)

Verified as fixed on Windows 10 x64, macOS 11.6 and on Ubuntu 20.04 x64.

Status: RESOLVED → VERIFIED
QA Whiteboard: [qa-triaged]
Flags: qe-verify+
Flags: sec-bounty? → sec-bounty-
Whiteboard: [reporter-external] [client-bounty-form] [verif?] → [reporter-external] [client-bounty-form] [verif?][adv-main101+]
Attached file advisory.txt (deleted) —
Whiteboard: [reporter-external] [client-bounty-form] [verif?][adv-main101+] → [reporter-external] [client-bounty-form] [verif?][adv-main101+][adv-esr91.10+]
Alias: CVE-2022-31736
Regressions: 1781063
Regressions: 1780905
Regressions: 1781759
Flags: sec-bounty-hof+
Flags: needinfo?(padenot)
Group: core-security-release
Pushed by ktomlinson@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/84202394415c avoid caching effects with a different query parameter for each subtest r=padenot https://hg.mozilla.org/integration/autoland/rev/7069c85fec77 test mixing of synthesized and network fallback range responses r=edenchuang
Created web-platform-tests PR https://github.com/web-platform-tests/wpt/pull/38020 for changes under testing/web-platform/tests
Whiteboard: [reporter-external] [client-bounty-form] [verif?][adv-main101+][adv-esr91.10+] → [reporter-external] [client-bounty-form] [verif?][adv-main101+][adv-esr91.10+], [wptsync upstream]
Upstream PR was closed without merging
Pushed by ktomlinson@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/9db99c7863bd avoid caching effects with a different query parameter for each subtest r=padenot https://hg.mozilla.org/integration/autoland/rev/041c72f0ce79 test mixing of synthesized and network fallback range responses r=edenchuang
Regressions: 1810922
Upstream PR was closed without merging
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: