Cross-origin PDF content leak via multipart/x-mixed-replace response
Categories
(Firefox :: PDF Viewer, defect, P1)
Tracking
()
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)
1.08 KB,
text/plain
|
Details | |
1.09 KB,
text/plain
|
Details | |
48 bytes,
text/x-phabricator-request
|
tjr
:
sec-approval+
|
Details | Review |
48 bytes,
text/x-phabricator-request
|
Details | Review | |
48 bytes,
text/x-phabricator-request
|
phab-bot
:
approval-mozilla-beta+
|
Details | Review |
48 bytes,
text/x-phabricator-request
|
phab-bot
:
approval-mozilla-esr115+
|
Details | Review |
48 bytes,
text/x-phabricator-request
|
phab-bot
:
approval-mozilla-esr128+
|
Details | Review |
270 bytes,
text/plain
|
Details |
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:
- 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.
- On the displayed HTML page, check that
window.origin
ordocument.domain
returnresource://pdf.js
orpdf.js
. This suggests that there is a confusion in the execution context. - 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. - 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.
- 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. - 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.
Reporter | ||
Updated•11 months ago
|
Updated•11 months ago
|
Reporter | ||
Comment 1•11 months ago
|
||
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.
Assignee | ||
Comment 2•11 months ago
|
||
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 ?
Comment 3•10 months ago
|
||
(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 skipapplication/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?
Assignee | ||
Updated•10 months ago
|
Assignee | ||
Comment 4•10 months ago
|
||
Updated•10 months ago
|
Assignee | ||
Updated•10 months ago
|
Assignee | ||
Comment 5•10 months ago
|
||
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
Reporter | ||
Comment 6•10 months ago
|
||
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.
Assignee | ||
Comment 7•10 months ago
•
|
||
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 ?
Reporter | ||
Comment 8•10 months ago
|
||
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.
Updated•10 months ago
|
Comment 9•10 months ago
•
|
||
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.
Comment 10•10 months ago
|
||
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.
Assignee | ||
Comment 11•10 months ago
|
||
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.
Comment 12•10 months ago
|
||
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:
- Set
fission.webContentIsolationStrategy
to0
inabout:config
. - Open any PDF, e.g. https://mozilla.github.io/pdf.js/web/compressed.tracemonkey-pldi-09.pdf.
- 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:
- Dialog with message: "https://research.mozilla.org/files/2020/05/hardening_firefox_against_injection_attacks.pdf"
Updated•10 months ago
|
Comment 13•10 months ago
|
||
Looks like you found the right people for help here.
Comment 14•10 months ago
|
||
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 15•10 months ago
|
||
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
Assignee | ||
Comment 16•10 months ago
|
||
:dveditz, I updated the patch to remove the test, so it should be ok now.
Assignee | ||
Comment 17•10 months ago
|
||
Updated•10 months ago
|
Updated•10 months ago
|
Assignee | ||
Comment 18•10 months ago
|
||
Original Revision: https://phabricator.services.mozilla.com/D222122
Updated•10 months ago
|
Comment 19•10 months ago
|
||
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
Assignee | ||
Comment 20•10 months ago
|
||
Original Revision: https://phabricator.services.mozilla.com/D222122
Updated•10 months ago
|
Comment 21•10 months ago
|
||
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
Assignee | ||
Comment 22•10 months ago
|
||
Original Revision: https://phabricator.services.mozilla.com/D222122
Updated•10 months ago
|
Comment 23•10 months ago
|
||
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
Comment 24•10 months ago
|
||
Comment 25•10 months ago
|
||
Updated•10 months ago
|
Updated•10 months ago
|
Comment 26•10 months ago
|
||
uplift |
Updated•10 months ago
|
Updated•10 months ago
|
Comment 27•10 months ago
|
||
uplift |
Updated•10 months ago
|
Updated•10 months ago
|
Comment 28•10 months ago
|
||
uplift |
Updated•10 months ago
|
Updated•10 months ago
|
Updated•10 months ago
|
![]() |
||
Comment 29•10 months ago
|
||
Comment 30•10 months ago
|
||
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).
Updated•10 months ago
|
Updated•10 months ago
|
Updated•10 months ago
|
Comment 31•10 months ago
|
||
Updated•10 months ago
|
Updated•10 months ago
|
Comment 32•8 months ago
|
||
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.
Assignee | ||
Comment 33•8 months ago
|
||
:tjr, is it fine to land the test ?
Updated•8 months ago
|
Comment 35•8 months ago
|
||
![]() |
||
Comment 36•8 months ago
|
||
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 -
Comment 37•5 months ago
|
||
![]() |
||
Comment 38•5 months ago
|
||
Backed out for causing bc failures @browser.toml.
TEST-UNEXPECTED-FAIL | leakcheck large nsDocShell | toolkit/components/pdfjs/test/browser.toml
Updated•4 months ago
|
Description
•