Stylesheet's CSP bypass via reflected URL in chrome:// directories still broken
Categories
(Core :: DOM: Security, defect, P1)
Tracking
()
People
(Reporter: Gijs, Assigned: emilio)
References
Details
(Keywords: csectype-other, sec-moderate, Whiteboard: [domsecurity-active][post-critsmash-triage][adv-main101+][adv-esr91.11+])
Attachments
(2 files, 1 obsolete file)
48 bytes,
text/x-phabricator-request
|
RyanVM
:
approval-mozilla-esr91+
|
Details | Review |
212 bytes,
text/plain
|
Details |
+++ This bug was initially created as a clone of Bug #1460538 +++
User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:60.0) Gecko/20100101 Firefox/60.0
Build ID: 20180503143129
Steps to reproduce:
By using the reflected URL in some special resource URIs it is possible to inject CSS and bypass CSP: http://demo.vwzq.net/php/ff_chrome.php
Stylesheet injection is not XSS, but still harmful.
Content:
<link rel="stylesheet" href="chrome://browser/content/places/?'{}{color:red}">
Actual results:
The reflected stylesheet is interpreted bypassing the strict CSP policy.
Expected results:
I guess the mitigation here should be to avoid reflecting any user content, or at least avoid loading directories.
This appears to still be broken.
Reporter | ||
Comment 1•3 years ago
|
||
So the fix from bug 1460538 tried to use the content type in comparison with the request type to block requests where the two didn't match.
This didn't work because in a packaged build, we hit Loader::LoadSheet
which explicitly sets the content type "hint" to text/css
, so then the content type is what you'd expect for stylesheets, and the load passes, even though the loaded URL really isn't a text/css
document.
In a non-packaged local build, it turns out we don't hit this code path because we strip the query params in file
URLs so the exploit doesn't work anyway.
We could work around this by having the nsJARChannel code explicitly check for directory entries but that feels very ugly. Emilio, do you know why the stylesheet code is forcing the mimetype here, and/or if there is some other getter we should be using to get a "real" content type? Blame on those lines is nearly 20 years old so I'm not sure where to go from there. :-(
As noted in my last comments in bug 1460538, the change in bug 1488061 then also didn't work because it changes the HTML output but not the indexed stream - to fix things that way we need to change https://searchfox.org/mozilla-central/rev/8f42809e51cb07aa4f5739932a06d14581e9dd4a/netwerk/base/nsDirectoryIndexStream.cpp#100,102-103 to strip query params for file
and/or jar
and/or chrome
(or rather, only include it for... well, for what, exactly?)
Comment 2•3 years ago
|
||
We also escape HTML-entities in the chrome://browser/content/places/?
reflection, but not CSS-relevant characters. That's also something we could change.
Assignee | ||
Comment 3•3 years ago
|
||
So I'm missing some context because I'm not cc'd on those bugs mentioned in comment 1, but IIUC the issue is that directory entries have the whole URI including query string in the response, like:
300: jar:file:///home/emilio/firefox/browser/omni.ja!/chrome/browser/content/browser/places/?fwaefwafwafwafwaefw
200: filename content-length last-modified file-type
201: bookmarkProperties.js 18045 Thu,%2031%20Dec%202009%2023:00:00%20GMT FILE
201: bookmarkProperties.xhtml 7644 Thu,%2031%20Dec%202009%2023:00:00%20GMT FILE
...
And that causes a CSS injection if interpreted as a stylesheet. My question is, why is the load not failing before? For example trying to fetch("chrome://browser/content/places/")
fails with a SecurityError
which comes from here, is any similar check not working?
Anyways, bug 120789 is what introduced that code. From taking a look, if the nsIChannel
overrides the content-type post-response, we'd reject the load here. However it seems the JAR channel is intentionally always respecting the content type set as a hint:
So in terms of potential fixes, the easiest one is to perhaps use the content-type hint only if the guess is unknown?
Assignee | ||
Comment 4•3 years ago
|
||
Make the script loader fail to load non-JS internal loads too, like the
CSS loader does for all cross-origin files.
Reporter | ||
Comment 5•3 years ago
•
|
||
(In reply to Emilio Cobos Álvarez (:emilio) from comment #3)
So I'm missing some context because I'm not cc'd on those bugs mentioned in comment 1,
Gah, sorry, copied you in.
but IIUC the issue is that directory entries have the whole URI including query string in the response, like:
300: jar:file:///home/emilio/firefox/browser/omni.ja!/chrome/browser/content/browser/places/?fwaefwafwafwafwaefw 200: filename content-length last-modified file-type 201: bookmarkProperties.js 18045 Thu,%2031%20Dec%202009%2023:00:00%20GMT FILE 201: bookmarkProperties.xhtml 7644 Thu,%2031%20Dec%202009%2023:00:00%20GMT FILE ...
And that causes a CSS injection if interpreted as a stylesheet. My question is, why is the load not failing before? For example trying to
fetch("chrome://browser/content/places/")
fails with aSecurityError
which comes from here, is any similar check not working?
I'm confused. My understanding is that style and script loads are allowed to be cross-origin, whereas fetch
needs CORS support for that. As a result, I don't think the two are the same.
A lot of the chrome/toolkit packaged styling and script can be referenced from the web because it's marked as contentaccessible
. We should fix that separately but it's not really the root issue here (ie as long as any web-reference-able chrome/resource URI would exist, any of them would facilitate this attack).
Anyways, bug 120789 is what introduced that code. From taking a look, if the
nsIChannel
overrides the content-type post-response, we'd reject the load here. However it seems the JAR channel is intentionally always respecting the content type set as a hint:So in terms of potential fixes, the easiest one is to perhaps use the content-type hint only if the guess is unknown?
Makes sense to me.
Reporter | ||
Comment 6•3 years ago
|
||
Passing the assignee to Emilio as he's put up a patch - thank you!
Comment 7•3 years ago
|
||
@emilio: Can you try and nudge this along? It seems (almost) done?
Comment 8•3 years ago
|
||
(In reply to Frederik Braun [:freddy] from comment #7)
@emilio: Can you try and nudge this along? It seems (almost) done?
Updated•3 years ago
|
Comment 9•3 years ago
|
||
I would lean towards simply making it impossible to load those stylesheets except when they were inserted by privileged callers.
Reporter | ||
Comment 10•3 years ago
|
||
(In reply to Kris Maglione [:kmag] from comment #9)
I would lean towards simply making it impossible to load those stylesheets except when they were inserted by privileged callers.
This would effectively "undo" contentaccessible
, right? And would need a carve-out for some about
pages in addition to the system principal case...
Assignee | ||
Comment 11•3 years ago
|
||
That is, treat it as a hint if called before open, and as an override if
called after. Override the hint on open.
This is a less invasive change that is green on try and also fixes the
issue.
Assignee | ||
Updated•3 years ago
|
![]() |
||
Comment 12•3 years ago
|
||
Make content-type on JAR channels behave the same as HTTP channels. r=Gijs
https://hg.mozilla.org/integration/autoland/rev/6192634b7401c3d4f1ee8abfe310bd68dcd5ac1f
https://hg.mozilla.org/mozilla-central/rev/6192634b7401
Updated•3 years ago
|
Comment 13•3 years ago
|
||
(In reply to :Gijs (he/him) from comment #10)
(In reply to Kris Maglione [:kmag] from comment #9)
I would lean towards simply making it impossible to load those stylesheets except when they were inserted by privileged callers.
This would effectively "undo"
contentaccessible
, right? And would need a carve-out for someabout
pages in addition to the system principal case...
Yes, for a large part. But I think we probably want that, anyway. Allowing for about:
pages would be easy. I mostly just don't think that content should be directly injectable by web content. Especially now that we have the infrastructure to make it injectable by a privileged caller without allowing web content.
Updated•3 years ago
|
Comment 14•3 years ago
|
||
Changing the priority to P1 as the bug is tracked by a release manager for the current beta.
See Triage for Bugzilla for more information.
If you disagree, please discuss with a release manager.
Comment 15•3 years ago
|
||
The patch landed in nightly and beta is affected.
:emilio, is this bug important enough to require an uplift?
If not please set status_beta
to wontfix
.
For more information, please visit auto_nag documentation.
Assignee | ||
Comment 16•3 years ago
|
||
Gijs, your call.
Assignee | ||
Comment 17•3 years ago
|
||
Wanted to write Gijs / Freddy, d'oh :-)
Reporter | ||
Comment 19•3 years ago
|
||
(In reply to Frederik Braun [:freddy] from comment #18)
Sure, if it applies cleanly. Why not?
I think my only reservation is risk. I don't feel like I have a great understanding of potential fall-out, e.g. for add-ons. But it's super early in beta and we're likely not going to find out about fallout on nightly anyway - and on the flip side, this is fixing a publicly-disclosed issue, so on the whole uplifting seems like a good idea to me.
Reporter | ||
Comment 20•3 years ago
|
||
(In reply to Kris Maglione [:kmag] from comment #13)
(In reply to :Gijs (he/him) from comment #10)
(In reply to Kris Maglione [:kmag] from comment #9)
I would lean towards simply making it impossible to load those stylesheets except when they were inserted by privileged callers.
This would effectively "undo"
contentaccessible
, right? And would need a carve-out for someabout
pages in addition to the system principal case...Yes, for a large part. But I think we probably want that, anyway. Allowing for
about:
pages would be easy. I mostly just don't think that content should be directly injectable by web content. Especially now that we have the infrastructure to make it injectable by a privileged caller without allowing web content.
OK. I think there are other reasons we want this (e.g. bug 1530499). I'll follow up there.
Assignee | ||
Comment 21•3 years ago
|
||
Comment on attachment 9274452 [details]
Bug 1757604 - Make content-type on JAR channels behave the same as HTTP channels. r=Gijs
Beta/Release Uplift Approval Request
- User impact if declined: see comment 19. I don't think risk is too big fwiw. We already heavily restrict add-on script extensions and so on.
- Is this code covered by automated tests?: No
- Has the fix been verified in Nightly?: Yes
- Needs manual test from QE?: Yes
- If yes, steps to reproduce: Load https://demo.vwzq.net/php/ff_chrome.php, there should be no red.
- List of other uplifts needed: none
- Risk to taking this patch: Medium
- Why is the change risky/not risky? (and alternatives if risky): See above.
- String changes made/needed: none
- Is Android affected?: Unknown
Assignee | ||
Updated•3 years ago
|
Comment 22•3 years ago
•
|
||
Comment on attachment 9274452 [details]
Bug 1757604 - Make content-type on JAR channels behave the same as HTTP channels. r=Gijs
Fun fact, this actually landed on 101 prior to the merge. And I was able to confirm that 101.0b2 shows the expected rendering for the testcase referenced in the approval request.
Updated•3 years ago
|
Updated•3 years ago
|
Updated•3 years ago
|
Comment 23•3 years ago
•
|
||
I've reproduced this bug using the STR from comment 21, on an affected build, Firefox 100.0.1 running Win 10 x64.
The issue is verified as fixed on latest Beta 101.0b8, across platforms: Win 10 x64, macOS 11 and Ubuntu 18.04 x64.
Updated•3 years ago
|
Reporter | ||
Comment 24•3 years ago
|
||
(In reply to :Gijs (he/him) from comment #1)
As noted in my last comments in bug 1460538, the change in bug 1488061 then also didn't work because it changes the HTML output but not the indexed stream - to fix things that way we need to change https://searchfox.org/mozilla-central/rev/8f42809e51cb07aa4f5739932a06d14581e9dd4a/netwerk/base/nsDirectoryIndexStream.cpp#100,102-103 to strip query params for
file
and/orjar
and/orchrome
(or rather, only include it for... well, for what, exactly?)
I'd like a second opinion on whether it's still useful to try and fix nsDirectoryIndexStream
so it doesn't include query/hash info in the echo'd content? I'm thinking yes, as a belt + suspenders kinda thing... Freddy, does that seem reasonable?
Comment 25•3 years ago
|
||
Updated•3 years ago
|
Comment 26•3 years ago
|
||
Yeah, I believe we should try and improve upon bug 1488061 and also strip the stuff from the nsDirectoryIndexStream
. Should be simple enough and likely worth the effort (before someone finds another kind of injection that isn't script or style :)).
Reporter | ||
Comment 27•3 years ago
|
||
Filed bug 1771774 for the directory stream improvement.
Comment 28•3 years ago
|
||
Is this ready for an ESR91 uplift? It grafts cleanly.
Assignee | ||
Comment 29•3 years ago
|
||
Comment on attachment 9274452 [details]
Bug 1757604 - Make content-type on JAR channels behave the same as HTTP channels. r=Gijs
ESR Uplift Approval Request
- If this is not a sec:{high,crit} bug, please state case for ESR consideration: simple enough sec-moderate
- User impact if declined: see comment 0
- Fix Landed on Version: 101
- Risk to taking this patch: Low
- Why is the change risky/not risky? (and alternatives if risky): It behaves the same as HTTP channels, so shouldn't cause much trouble.
Comment 30•3 years ago
|
||
Comment on attachment 9274452 [details]
Bug 1757604 - Make content-type on JAR channels behave the same as HTTP channels. r=Gijs
Approved for 91.11esr.
Comment 31•3 years ago
|
||
uplift |
Comment 32•3 years ago
|
||
This is also verified as fixed on 91.11.0esr across platforms: Win 10 x64, macOS 11 and Ubuntu 22.04 x64.
Updated•3 years ago
|
Updated•2 years ago
|
Description
•