Closed Bug 1918301 (CVE-2024-9393) Opened 11 months ago Closed 10 months ago

Cross-origin PDF content leak via multipart/x-mixed-replace response

Categories

(Firefox :: PDF Viewer, defect, P1)

defect

Tracking

()

VERIFIED FIXED
132 Branch
Tracking Status
firefox-esr115 131+ verified
firefox-esr128 131+ verified
firefox130 --- wontfix
firefox131 + verified
firefox132 + verified

People

(Reporter: masatokinugawa, Assigned: calixte, NeedInfo)

References

(Depends on 1 open bug)

Details

(Keywords: csectype-sop, reporter-external, sec-high, Whiteboard: [client-bounty-form][adv-main131+][adv-esr128.3+][adv-esr115.16+])

Attachments

(8 files)

If a crafted multipart/x-mixed-replace response is returned, it is possible to execute arbitrary JavaScript in the context of the resource://pdf.js origin. Specifically, if an application/pdf response is retrurned first, and then an text/html response, the JavaScript written in the text/html page will be executed in the resource://pdf.js origin's context. This can be used to read cross-origin PDF contents.

Steps to reproduce:

  1. Navigate to https://vulnerabledoma.in/fx_x-mixed-replace_x-origin_pdf_leak.php . The pdf.js UI will be displayed for a moment, and then the HTML page will be displayed.
  2. On the displayed HTML page, check that window.origin or document.domain return resource://pdf.js or pdf.js. This suggests that there is a confusion in the execution context.
  3. Click "Read cross-origin cross-site PDF" button. A PDF page placed in https://blog.mozilla.org origin will be opened in a new window.
  4. Wait until the PDF window is closed. After being closed, if on Firefox Android, the PDF text will be displayed on the opener's page. If on Firefox desktop, a SecurityError will be displayed.
  5. Click "Read cross-origin same-site PDF" button. A PDF page placed in https://www.vulnerabledoma.in origin will be opened in a new window.
  6. Wait until the PDF window is closed. After being closed, both on the Firefox desktop/Android, the PDF text will be displayed on the opener's page.

As can be seen from the steps above, there are differences in behavior between Android and desktop.
Firefox Android is more serious because it can be exploited across "sites".
On the other hand, the desktop can access only for same-sites. However, it is still possitble to access cross-"origin" same-"site" PDF page. This is a partial SOP bypass and is not the proper behavior.

Flags: sec-bounty?
Attachment #9424323 - Attachment mime type: application/x-php → text/plain
Component: Security → PDF Viewer

Also, address bar spoofing is possible on Firefox Android as long as there is a PDF content on the target page: https://vulnerabledoma.in/fx_x-mixed-replace_addressbar_spoofing_via_pdf.php
If you click on the "Open blog.mozilla.org" button and wait a moment, a fake login form will be displayed on the blog.mozilla.org. I attached the PHP script.

I'm not sure it makes sense to have a pdf in a multipart/x-mixed-replace request so I suppose we should skip application/pdf or whatever which could be sniffed as a pdf.
:valentin, what do you think ?

Flags: needinfo?(valentin.gosu)

(In reply to Calixte Denizet (:calixte) from comment #2)

I'm not sure it makes sense to have a pdf in a multipart/x-mixed-replace request so I suppose we should skip application/pdf or whatever which could be sniffed as a pdf.
:valentin, what do you think ?

I think a multipart response could contain pretty much anything, so I'm not sure if the multipart converter should skip pdf files.
Instead, I think the PdfStreamConverter should either handle multipart files correctly (that seems like an overkill) or simply fail if the channel QIs to nsIMultiPartChannel?
Does that make sense?

Flags: needinfo?(valentin.gosu)
Assignee: nobody → cdenizet
Status: UNCONFIRMED → ASSIGNED
Ever confirmed: true
Priority: -- → P1

Comment on attachment 9424674 [details]
Bug 1918301 - Don't display pdfs in pdf.js coming from a multipart response r=valentin

Security Approval Request

  • How easily could an exploit be constructed based on the patch?:
  • Do comments in the patch, the check-in comment, or tests included in the patch paint a bulls-eye on the security problem?: Unknown
  • Which branches (beta, release, and/or ESR) are affected by this flaw, and do the release status flags reflect this affected/unaffected state correctly?: 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?:
  • How likely is this patch to cause regressions; how much testing does it need?: The only possible regression would be for users getting multipart responses with a pdf inside.
    Since I'm not sure to know how it could be use, I'd be inclined to think that it's very unlikely.
    For the specific content-type: multipart/x-mixed-replace, in considering the first comment in https://issues.chromium.org/issues/41017445, I'm pretty sure that it won't be a problem.
  • Is the patch ready to land after security approval is given?: Yes
  • Is Android affected?: Yes
Attachment #9424674 - Flags: sec-approval?

Is it the intended behavior to be able to access other PDFs across origins when JS is executed at the resource://pdf.js origin?
I feel like ideally it would require a patch here as well if this behavior is not intended. This will reduce the impact when JS is executed on the resource://pdf.js origin.

No it isn't intended.
The different behavior on android and desktop shows that something is wrong somewhere else.
:olivia, could you have a look please ?

After having investigated a bit, I found that the root problem isn't specific to pdf.js since I can reproduce the original issue in replacing the pdf part of the response by:

echo '--boundary
Content-Type: application/vnd.mozilla.json.view

{ "aaaa": "aaaa" }
--boundary
';

and then I get:

window.origin: resource://devtools
document.domain: devtools

I think my patch, at least, avoids to be in a bad situation but it's likely hiding an other problem.
:mccr8, would you know who could help here ?

Flags: needinfo?(ohall)
Flags: needinfo?(continuation)

Oh, I just submitted it at Bug 1918874 xD
In the JSON's case, same-"site" cross-"origin" JSON and parts of request/response headers can be leaked.

See Also: → CVE-2024-9394

Thanks for working on this, Calixte! Thanks, Masato, for filling both this and the JSON one. I'm going to redirect this to :owlish, who does Android security triage and might have context on this situation as well.

Flags: needinfo?(ohall) → needinfo?(bugzeeeeee)

On desktop, the cross-origin exploit breaks because the cross-site PDF is rendered in a different process. If I set fission.webContentIsolationStrategy to 0 (=isolate nothing) on desktop, and load the exploit, it works.

On Android, cross-origin content is loaded in the same process, because Fission is not enabled by default.

Ideally, PDFs for different sites should not be able to script each other. I'll file a separate bug with concrete ideas.

On desktop, the cross-origin exploit breaks because the cross-site PDF is rendered in a different process. If I set fission.webContentIsolationStrategy to 0 (=isolate nothing) on desktop, and load the exploit, it works.

Interesting, so now, with the json stuff, I'm able to script an other json viewer.

Rendering PDFs currently happens by redirecting the channel to a resource://pdf.js/ URL while keeping the address bar's URL at the originally requested URL.

The viewer's principal URI is resource://pdf.js (optionally with additional attributes such as privateBrowsingId if applicable). The problem with this is that any vulnerability (e.g. this bug, bug 1452075, bug 1893645) or feature resulting in code execution in the PDF viewer (e.g. bug 1454760) can then read PDFs from arbitrary other websites, simply by triggering a navigation to the destination PDF. In practice, cross-origin read is rarely possible because Fission forces cross-site content to be rendered in a separate process, which is not visible. Same-site PDFs is currently always readable. The STR below shows that all PDF viewers share the same principal that enables cross-origin read of PDF content (using the pref I mentioned in comment 10).

A solution would be to ensure that the viewer has a unique principal. There is already a bug requesting that at bug 1450443. I described an implementation path at https://bugzilla.mozilla.org/show_bug.cgi?id=1450443#c6

STR:

  1. Set fission.webContentIsolationStrategy to 0 in about:config.
  2. Open any PDF, e.g. https://mozilla.github.io/pdf.js/web/compressed.tracemonkey-pldi-09.pdf.
  3. Open the devtools and run the following snippet. Then click inside the page to open the popup.
onclick = () => {
  w = window.open("https://research.mozilla.org/files/2020/05/hardening_firefox_against_injection_attacks.pdf");
  setTimeout(() => {
    try{ alert(w.document.URL) } catch (e) { alert(e) }
  }, 2000);
};

Expected:

  • Dialog with message: "SecurityError: Permission denied to access property "document" on cross-origin object"

Actual:

See Also: → 1450443
Flags: needinfo?(continuation)

Looks like you found the right people for help here.

It would be nice to fix this and the JSON viewer (bug 1918874) in v131 ASAP, and then follow-up with the defense in depth Rob is describing in comment 12 / bug 1450443 in v132 if all goes smoothly, later if necessary. It's better to solve the problem at its root, but we don't have to leave the door open while we're doing it.

Comment on attachment 9424674 [details]
Bug 1918301 - Don't display pdfs in pdf.js coming from a multipart response r=valentin

We need a clean patch without the testcase for a sec-high security bug. The testcase can be checked in 4-6 weeks later

Attachment #9424674 - Flags: sec-approval? → sec-approval-

:dveditz, I updated the patch to remove the test, so it should be ok now.

Flags: needinfo?(bugzeeeeee)
Attachment #9424674 - Flags: sec-approval- → sec-approval+
Whiteboard: [client-bounty-form] → [client-bounty-form][reminder-test 2024-11-12]
Attachment #9426175 - Flags: approval-mozilla-beta?

beta Uplift Approval Request

  • User impact if declined: sec-high bug
  • Code covered by automated testing: no
  • Fix verified in Nightly: no
  • Needs manual QE test: yes
  • Steps to reproduce for manual QE testing: load the test case in the bug
  • Risk associated with taking this patch: small
  • Explanation of risk level: just avoid to open a pdf in a very specific context
  • String changes made/needed: no
  • Is Android affected?: yes
Flags: qe-verify+
Attachment #9426176 - Flags: approval-mozilla-esr115?

esr115 Uplift Approval Request

  • User impact if declined: sec high bug
  • Code covered by automated testing: no
  • Fix verified in Nightly: no
  • Needs manual QE test: yes
  • Steps to reproduce for manual QE testing: load the test case in the bug
  • Risk associated with taking this patch: small
  • Explanation of risk level: just avoids to open a pdf in a very specific context
  • String changes made/needed: no
  • Is Android affected?: yes
Attachment #9426177 - Flags: approval-mozilla-esr128?

esr128 Uplift Approval Request

  • User impact if declined: sec high bug
  • Code covered by automated testing: no
  • Fix verified in Nightly: yes
  • Needs manual QE test: yes
  • Steps to reproduce for manual QE testing: load the test case in the bug
  • Risk associated with taking this patch: small
  • Explanation of risk level: just avoids to open a pdf in a very specific context
  • String changes made/needed: No
  • Is Android affected?: yes
Pushed by cdenizet@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/13fe925fe8db Don't display pdfs in pdf.js coming from a multipart response r=valentin
Pushed by nfay@mozilla.com: https://hg.mozilla.org/mozilla-central/rev/c60d8651a282 Don't display pdfs in pdf.js coming from a multipart response r=valentin
Group: firefox-core-security → core-security-release
Status: ASSIGNED → RESOLVED
Closed: 10 months ago
Resolution: --- → FIXED
Target Milestone: --- → 132 Branch
Attachment #9426175 - Flags: approval-mozilla-beta? → approval-mozilla-beta+
Attachment #9426177 - Flags: approval-mozilla-esr128? → approval-mozilla-esr128+
Attachment #9426176 - Flags: approval-mozilla-esr115? → approval-mozilla-esr115+
QA Whiteboard: [post-critsmash-triage]
QA Whiteboard: [post-critsmash-triage] → [post-critsmash-triage] [qa-triaged]

Reproduced the issue described in comment 0 using an old Nightly build from 2024-09-14. Verified that using latest Nightly 132.0a1, latest Beta 131, latest esr115 and latest esr128 from Treeherder across platform (Windows 11, macOS 13 and Ubuntu 22.04) the .pdf file is now downloaded and no content is shown in the tab (like in the affected build).

Flags: sec-bounty? → sec-bounty+
Whiteboard: [client-bounty-form][reminder-test 2024-11-12] → [client-bounty-form][reminder-test 2024-11-12][adv-main131+]
Whiteboard: [client-bounty-form][reminder-test 2024-11-12][adv-main131+] → [client-bounty-form][reminder-test 2024-11-12][adv-main131+][adv-esr128.3+]
Attached file advisory.txt
Whiteboard: [client-bounty-form][reminder-test 2024-11-12][adv-main131+][adv-esr128.3+] → [client-bounty-form][reminder-test 2024-11-12][adv-main131+][adv-esr128.3+][adv-esr115.16+]
Alias: CVE-2024-9393

a month ago, tjr placed a reminder on the bug using the whiteboard tag [reminder-test 2024-11-12] .

calixte, please refer to the original comment to better understand the reason for the reminder.

Flags: needinfo?(cdenizet)
Whiteboard: [client-bounty-form][reminder-test 2024-11-12][adv-main131+][adv-esr128.3+][adv-esr115.16+] → [client-bounty-form][adv-main131+][adv-esr128.3+][adv-esr115.16+]

:tjr, is it fine to land the test ?

Flags: needinfo?(cdenizet) → needinfo?(tom)

Yup, go for it

Flags: needinfo?(tom)
Attachment #9426120 - Attachment description: WIP: Bug 1918301 - Add a test to check that the pdf viewer isn't used when the pdf is in a multipart response → Bug 1918301 - Add a test to check that the pdf viewer isn't used when the pdf is in a multipart response r=marco
Pushed by cdenizet@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/58635b019edd Add a test to check that the pdf viewer isn't used when the pdf is in a multipart response r=marco

Backed out for causing mochitest failures @ browser_pdfjs_octet_stream.js:
https://hg.mozilla.org/integration/autoland/rev/24849b560ff9a5dcee5c592c6c32b155f84af21f

Push with failures
Failure log

[task 2024-11-13T10:34:05.965Z] 10:34:05     INFO - TEST-PASS | toolkit/components/pdfjs/test/browser_pdfjs_octet_stream.js | pdf handler defaults to internal - 
[task 2024-11-13T10:34:05.965Z] 10:34:05     INFO - Buffered messages logged at 10:32:35
[task 2024-11-13T10:34:05.966Z] 10:34:05     INFO - Console message: [JavaScript Warning: "This page is in Quirks Mode. Page layout may be impacted. For Standards Mode use “<!DOCTYPE html>”." {file: "data:text/html,<iframe src='http://mochi.test:8888/browser/toolkit/components/pdfjs/test/file_pdfjs_object_stream.pdf'>" line: 0}]
[task 2024-11-13T10:34:05.967Z] 10:34:05     INFO - Console message: [JavaScript Error: "NS_ERROR_FAILURE: Ignore PDF.js for this download." {file: "resource://pdf.js/PdfStreamConverter.sys.mjs" line: 1060}]
[task 2024-11-13T10:34:05.967Z] 10:34:05     INFO - getConvertedType@resource://pdf.js/PdfStreamConverter.sys.mjs:1060:15
[task 2024-11-13T10:34:05.967Z] 10:34:05     INFO - 
[task 2024-11-13T10:34:05.967Z] 10:34:05     INFO - Waiting for download panel to open
[task 2024-11-13T10:34:05.968Z] 10:34:05     INFO - Console message: [JavaScript Warning: "Partitioned cookie or storage access was provided to “file:///builds/worker/file_pdfjs_object_stream.pdf” because it is loaded in the third-party context and dynamic state partitioning is enabled."]
[task 2024-11-13T10:34:05.969Z] 10:34:05     INFO - Buffered messages finished
[task 2024-11-13T10:34:05.970Z] 10:34:05     INFO - TEST-UNEXPECTED-FAIL | toolkit/components/pdfjs/test/browser_pdfjs_octet_stream.js | Test timed out - 
Flags: needinfo?(cdenizet)
Pushed by cdenizet@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/294103e757e6 Add a test to check that the pdf viewer isn't used when the pdf is in a multipart response r=marco

Backed out for causing bc failures @browser.toml.

TEST-UNEXPECTED-FAIL | leakcheck large nsDocShell | toolkit/components/pdfjs/test/browser.toml

Group: core-security-release
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: