jar: URL with embedded null ("%00") can be used to make us misinterpret a file's MIME type
Categories
(Core :: Networking: JAR, defect, P2)
Tracking
()
People
(Reporter: sdev81300, Assigned: valentin)
Details
(Keywords: csectype-sop, reporter-external, sec-low, Whiteboard: [necko-triaged][necko-priority-queue][adv-main136+][adv-esr128.8+])
Attachments
(9 files, 2 obsolete files)
|
32.93 KB,
image/png
|
Details | |
|
55.92 KB,
image/png
|
Details | |
|
2.14 MB,
image/png
|
Details | |
|
50.97 KB,
image/png
|
Details | |
|
48 bytes,
text/x-phabricator-request
|
Details | Review | |
|
48 bytes,
text/x-phabricator-request
|
Details | Review | |
|
170.74 KB,
image/png
|
Details | |
|
48 bytes,
text/x-phabricator-request
|
phab-bot
:
approval-mozilla-esr128+
|
Details | Review |
|
447 bytes,
text/plain
|
Details |
Firefox for Android
Steps to reproduce:
A vulnerability in the jar: protocol parser of Mozilla Firefox allows filename and extension spoofing and MIME type manipulation leads to XSS when a null byte (%00) is included in the entry name of a JAR archive. This can result in malicious code execution, such as triggering JavaScript payloads embedded in image files by spoofing the file extension and MIME type.
[+] Screenshot Attached below , I can only attach one screenshot, if need more details please reach me out!!
Actual results:
Create a Malicious File:
-
Embed a JavaScript payload in the EXIF data of an image file (e.g., hacker.png) using the Exiftool like so : exiftool -Comment=<script>alert('XSS By Surya Dev Singh')</script>" hacker.png
-
Place the image (hacker.png) file in one folder (lets say hacker) and archive it to zip (jar files are basically zip file only so you can rename the generated zip file to something like hacker.ja)
-
Try to load the hacker.png file using the normally using the jar protocol : jar:file:///C:/Users/Username/Desktop/hacker.ja!/hacker/test2/hacker.png
It will load the image normally. -
But if you modify the URL by injecting Null Byte , it will terminate the "AUTF8String JAREntry" entry definition from the code . the modified URL would look like this :
jar:file:///C:/Users/Z004WREN/OneDrive%20-%20Siemens%20Healthineers/Desktop/hacker.ja!/hacker/test2/hacker.png%00.html -
This will Trigger the XSS payload that we have store in Exif comment data.
-
Now we can use this Null Byte Behavior with some slide modification to change the file name and its extension . which further means that we can change the mime type of the file . Thus will trigger an user to run the malicious file as non malicious file.
-
to do that we need to to add "://<custom_filename>" after the null byte termination. like so :
jar:file:///C:/Users/Z004WREN/OneDrive%20-%20Siemens%20Healthineers/Desktop/hacker.ja!/hacker/test2/hacker.png%00://definitely_not_a_hacker_file.exe
This will download the hacker.png file as "definitely_not_a_hacker_file.exe" with executable extension.
All this behavior has been trigger due to the vulnerable code base in mozilla :
The two classes GetJARFile and GetJAREntry makes heavy use of nsCString (likely a Mozilla-specific wrapper around std::string or a similar container) and other string types. Functions that process strings could be vulnerable if the null byte is mishandled. Here’s a potential scenario:
In SetSpecWithBase(const nsACString& aSpec, nsIURI* aBaseURL), the code likely constructs and manipulates URLs. If the aSpec string contains a null byte in an unexpected location, the nsIJARURIMutator function is then not able to handle the input that's coming from the GetJAREntry . it might cause string manipulation functions (e.g., strlen, strcpy, strcat) to terminate prematurely or lead to buffer overflows/underflows.
The methods that handle strings (such as SetPathQueryRef, SetHostPort, SetRef) could all be susceptible to this issue if they don't handle strings properly
Here are link to codebase :
https://searchfox.org/mozilla-central/source/__GENERATED__/dist/include/nsIJARURI.h#35
Expected results:
what should have happened :
The jar: protocol parser should correctly handle null bytes (\0) in filenames, preventing filename and extension spoofing.
The MIME type of the file should remain consistent with its actual content and extension, disallowing manipulations.
Files within JAR archives should be securely validated and sanitized to prevent execution of embedded scripts.
No JavaScript payload embedded in non-HTML files should execute, even with manipulated MIME types.
| Reporter | ||
Comment 1•9 months ago
|
||
| Reporter | ||
Comment 2•9 months ago
|
||
| Reporter | ||
Comment 3•9 months ago
|
||
Updated•9 months ago
|
Comment 4•9 months ago
|
||
Valentin, could you confirm whether the bug is easily exploitable?
Updated•9 months ago
|
| Reporter | ||
Comment 5•9 months ago
|
||
Since Firefox internally uses this jar: protocol to load extensions.
- any attacker could use extension to deliver malicious file by filename and extension spoofing by abusing the mime type described above
- can abuse the above describe code execution method to run arbitrary JavaScript code.
| Reporter | ||
Comment 6•9 months ago
|
||
Hi @smayya ,
I reported this bug here instead of Hackerone. I hope its still falls under Security Bug Bounty Program and can be assigned CVE ID to this.
Can you give your input on this ?
Thank You ☺ !!
| Assignee | ||
Comment 7•9 months ago
|
||
(In reply to Surya Dev Singh from comment #6)
Hi @smayya ,
I reported this bug here instead of Hackerone. I hope its still falls under Security Bug Bounty Program and can be assigned CVE ID to this.
I think bug bounties are submitted to bugzilla are just fine. But note this item in https://www.mozilla.org/en-US/security/client-bug-bounty/#claiming-a-bounty
If you have filed the bug directly in Bugzilla without using the Bugzilla client bug bounty form, please immediately notify the Mozilla Security Group by email to security@mozilla.org and include the number of the bug you filed and a mention that you are submitting it for bounty consideration. Do not send the actual vulnerability via email.
(In reply to Sunil Mayya from comment #4)
Valentin, could you confirm whether the bug is easily exploitable?
I haven't yet tested if this actually works, but as far as I understand we need a webextension/jar containing an image with a comment that embeds JS code, or an executable file embeded in the JAR as an image.
While these could make it possible to get around some of the AMO checks and include some risky code in your exension, as far as I can tell the webextension author already has the ability to run arbitrary JS code included in the extension.
@Surya Dev Singh, is there anything that a malicious extension could achieve by exploiting this bug that it can't already do?
| Reporter | ||
Comment 8•9 months ago
|
||
This potential vulnerability stems from how Firefox handles the JAR protocol, allowing a malicious web extension to embed risky code that could lead to arbitrary code execution. By embedding JavaScript in image comments or including an executable disguised as an image file within the JAR, the extension can exploit null byte injection and how the JAR protocol parser processes file paths and embedded data.
While a malicious extension author already has the ability to run arbitrary JavaScript within the extension, this vulnerability offers additional exploitation possibilities:
-
Stealthy Malware Delivery : An attacker could manipulate file names and extensions which auto downloads non common files like exe, enabling malware to be delivered as a seemingly harmless file, thus increasing the chances of user interaction.
-
Exploitation Vector : This flaw allows JavaScript code to be executed from non-JavaScript files, such as innocent-looking image or text files, processed as part of the JAR. Despite appearing benign, these files can execute malicious code behind the scenes.
The core issue lies in the vulnerability of Firefox’s JAR protocol parser, not the extension itself. This makes the bug particularly impactful, opening up new avenues for exploitation and broadening the attack surface. Given its potential severity, this flaw is a strong candidate for a bug bounty.
Valentine, please if possible can you check the POC provided in the "JAR:" protocol itself and let me know if it works as expected."
Thank You !!
Updated•9 months ago
|
Comment 9•9 months ago
|
||
Valentine, please if possible can you check the POC provided in the "JAR:" protocol itself and let me know if it works as expected."
I don't see a PoC anywhere we can check, only a bunch of screenshot attachments? Screenshots are not proofs of anything when they can be so easily faked. Can you please attach one for Valentin to check
| Reporter | ||
Comment 10•9 months ago
•
|
||
[trimmed unnecessary quote of comment 0 -dv]
Hello Team !!
Thank you for your reply !! Here is the full step by step POC that I have given, and screenshots are also attached for the same .
any person responsible to triage of the bug can easily use this step to reproduce the bug described.
This is what standard POC look like. but if you prefer it in some video form I can do it. I understand that screenshots can be faked, but this is what standard triage process goes in checking the validity of the POC I have given.
This a security bug should be triage and responded immediately to reduce the risk of its exposure so that a CVE id can be assign to it, since I have not reported it on hackerone. The Mozilla team can directly take a look at it here itself or can ask the team that review the bugs from the Hackerone mozilla bug bounty ( if there is a different team) . looking forward into this !!
Thank You !!
| Reporter | ||
Comment 11•9 months ago
|
||
Please let me know if you need any further input from my end , I would be really happy to secure the Mozilla software.
Thank You
Comment 12•9 months ago
|
||
We do NOT mean a video when we say PoC. A video is the same type of evidence as a screenshot. They can be useful for understanding, but almost never detailed enough on their own to replace an actual PoC.
Your "steps to reproduce" are just that, steps to reproduce. They are instructions for us to build our own PoC but not themselves the PoC. For a web site vulnerability "user actions" might be the full explanation of a vulnerability, But for a client bug (especially one like this dealing with specifically prepared binary files) the PoC is the set of files you deliver to a user, and how, so that they trigger the problem.
We certainly can follow your steps and create a hacked .jar file for ourselves, but that extra time requirement will tend to move your bug to the bottom of the pile of bugs to investigate. Presumably you already have the hacked .jar file used to make the screenshots so it would be easy to attach to the bug, and that would save us a lot of time. As a secondary benefit it makes sure we don't misinterpret one of the steps, or can't reproduce because you forgot to mention some modification. In this case the steps are straightforward and those outcomes unlikely, but that's one of the reasons we like to get the PoC from the reporter themselves.
As far as we know the jar: protocol is not usable from web content and therefore isn't something users will stumble upon on their own so the impact appears limited. We might be wrong—many vulnerabilities from from incorrect assumptions—and that, too, is something an actual PoC could demonstrate.
I completely understand the concept of the name hack with the embedded null. Something that reads or displays the name as a "C String" might show the .png extension, and internally Firefox "knows" the .jar said "the name is XX characters long" and therefore .html is the "real" extension at the end. Where my understanding is failing is who this is spoofing and how? In a hypothetical attack
- who made the jar file? how does the user get it?
- If the user takes an action and suddenly gets a "definitely_not_a_hacker_file.exe" download, why would the user think or expect it to be anything other than a downloaded executable? where it came from is all opaque to a user, right? Why would they even think it was supposed to be a .png?
Like in your first screenshot a user opens a random URL, normally a random URL can run JavaScript -- that's not a surprise. It even says ".html" on the end very clearly in that screenshot. Of course you can make the name longer to hide that, but then you'd also likely hide the ".png" that you're apparently trying to fool the user with -- you have no idea what the victim's window-size or resolution is going to be.
OK, now the 3rd screenshot has no null. Are you saying that is the same .jar file as the other screenshots? Does the .jar have two different files in it, one with the null and one not? Or is the "0x00" is only in the URL used to access it and not actually in the .jar itself? Your initial description said "leads to XSS when a null byte (%00) is included in the entry name of a JAR archive" and you link to code for JAREntry so I assumed the null was in the zip archive directory entry.
Comment 13•9 months ago
|
||
OK, the null is in the URL, not the .jar/.zip itself. compare: resource:///chrome.manifest with resource:///chrome.manifest%00.html (you will have to copy those URLs and paste them in a new window—web content can't link to resource: urls)
That resource: URL is equivalent to a jar: url into your install directory, so in my case you can do the same with jar:file:///Applications/Firefox Nightly.app/Contents/Resources/browser/omni.ja!/chrome.manifest%00.html. The easiest way to get that is to "typo" the path (chrome.manifes) and then copy the jar URL from the error page and put the 't' back on the end.
This is definitely a bug in the jar: URL parser which should treat a null/%00 as invalid. Someone could hack a zip archive to put a null in a filename in the directory entry, but you couldn't unzip that entry into a filename and I see no need for Gecko to support such an esoteric edge case with the jar: protocol.
The reporter is correct that a manipulated jar: URL could use this trick to force Firefox to interpret an entry in a zip archive as a different type than its filename suggests. How the victim gets the hacked .zip archive or the malicious URL to it is apparently an exercise for the reader.
Without a PoC there's no evidence this could actually be used in a "spoofing" or "XSS" attack. The jar: protocol is an internal mechanism.
Updated•9 months ago
|
| Assignee | ||
Comment 14•9 months ago
|
||
Definitely something we ought to fix.
Unclear right now if it also affects moz-extension URLs
| Reporter | ||
Comment 15•9 months ago
|
||
Some checks are being going on , will update this thread as we have something !!
Thank you
Comment 16•9 months ago
|
||
This also affects moz-extension:-URLs because they internally resolve to jar:-URLs. TL;DR of below: the worst that can happen here is misleading reviewers of extension code.
Unlike the other URLs here, moz-extension:-URLs can be linked from the web if the extension opts in by specifying an entry in web_accessible_resources. This list can contain explicit file names or wildcards. To exploit this bug at all, a wildcard must be used. Moreover extensions have a strict CSP that only allows its own scripts and disallows external and inline scripts - this mitigation has to be bypassed to create a successful exploit targeting victim extensions.
The most realistic attack scenario targeting victim extensions that I can imagine is as follows:
- a victim extension contains a non-HTML file that, when rendered as HTML, embeds a
<script>element (statically in the source, can be a relative path) that references a vulnerable JS resource within the same extension.- The non-HTML file doing something dangerous when rendered as HTML scenario itself is unlikely. The most realistic scenario that I can imagine is a JS file that embeds a HTML template or code comment with HTML.
- By vulnerable JS resource, I mean an extension's custom JS code that does not expect execution triggered by a third party.
- An attacker somehow discovers the extension's unique
moz-extension:-URL and loadsmoz-extension://uuidhere/file.js%00.html. Now it manages to invoke extension-defined functionality, unexpectedly.
The above scenario is not very realistic.
Another attack scenario is on the verification side:
- we require all extension code to have the .js file extension (or any other valid JS extension), enforced via https://searchfox.org/mozilla-central/rev/9f9fa5d2cb72b12ac7e168b7f6ee9820f63291e9/dom/security/nsContentSecurityManager.cpp#1202-1268
- if (automated) review only checks .js files, the extension package may execute code that has not been vetted by reviewers.
The latter scenario is a realistic way to reduce the effectiveness of extension review process.
To verify that moz-extension:-URLs are vulnerable at all by this bug, follow the following steps:
- Visit
about:debuggingand look up the moz-extension:-URL of the built-in webcompat extension. - Paste this URL in the address bar, with
TODO_REPLACE_THISreplaced with the actual uuid from step 1:moz-extension://TODO_REPLACE_THIS/shims/instagram-embed.js%00.html - Observe that the JS file is rendered as HTML, notably by this
<imgtag being rendered as a (broken) image: https://searchfox.org/mozilla-central/rev/9f9fa5d2cb72b12ac7e168b7f6ee9820f63291e9/browser/extensions/webcompat/shims/instagram-embed.js#143
| Assignee | ||
Updated•9 months ago
|
| Assignee | ||
Comment 17•9 months ago
|
||
| Assignee | ||
Comment 18•9 months ago
|
||
bug explainer
In nsJARChannel::LookupFile we unescape the filename of the file we're trying to load, while nsZipArchive::GetItem takes a char* filename argument, and computes the length based by calling strlen which is affected by embedded nulls.
nsExternalHelperAppService::GetTypeFromExtension works correctly in this case - even for URLs with percent encoded nulls the extension like .js%00.html the extension should be the last one.
The problem in this case is that the URL and JAR entry we were loading didn't match.
The solution in this case was to update nsZipArchive::GetItem, nsZipItemPtr_base::nsZipItemPtr_base and mozilla::FileLocation::FileLocation to pass the filename through nsACString instead.
| Assignee | ||
Comment 19•9 months ago
|
||
| Assignee | ||
Comment 20•9 months ago
|
||
The test fails without the patch applied, and passes with the patch applied.
I've also manually checked that jar URLs with embedded nulls no longer work.
Comment 21•9 months ago
|
||
Comment 22•9 months ago
|
||
Updated•9 months ago
|
Comment 23•9 months ago
|
||
The patch landed in nightly and beta is affected.
:valentin, is this bug important enough to require an uplift?
- If yes, please nominate the patch for beta approval.
- If no, please set
status-firefox135towontfix.
For more information, please visit BugBot documentation.
| Assignee | ||
Comment 24•9 months ago
|
||
Original Revision: https://phabricator.services.mozilla.com/D234164
Updated•9 months ago
|
Comment 25•9 months ago
|
||
beta Uplift Approval Request
- User impact if declined: Resources could be loaded from webextensions or other JAR resources with the wrong content-type. This could lead to the execution of comment embedded in an images' metadata as javascript if %00.js were appended to the image URL.
- Code covered by automated testing: yes
- Fix verified in Nightly: yes
- Needs manual QE test: yes
- Steps to reproduce for manual QE testing: Load jar:file:///[path_to_archive]!/resource.txt - This should load. Make sure that appending %00.js to the path makes the load fail.
- Risk associated with taking this patch: low
- Explanation of risk level: This patch attempts to make minimal behaviour changes to Firefox. It just changes the argument types of several methods to use nsACString instead of char*. The result is that percent unescaping the string should will pass the entire string to the consumer, and we will match the full path against the JAR resource, not just the characters before %00.
- String changes made/needed: none
- Is Android affected?: yes
Updated•9 months ago
|
Updated•9 months ago
|
Updated•9 months ago
|
| Assignee | ||
Updated•9 months ago
|
Comment 26•9 months ago
•
|
||
Hello. I have reproduced the issue with firefox 135.0a1 (2025-01-05) on Windows 10x64 by following the next steps:
- Created a
test.jarfile containingresource.txt(with random text) usingjar cf test.jar resource.txtin CMD - In the Firefox URL bar load the following links:
jar:file:///C:/Users/al3x_/Desktop/test.jar/test.jar!/resource.txtjar:file:///C:/Users/al3x_/Desktop/test.jar/test.jar!/resource.txt%00.jsjar:file:///C:/Users/al3x_/Desktop/test.jar/test.jar!/resource.txt%00
Actual result:
- In an affected build all links from steps 2 are loaded showing the text from step 1.
- In a fixed build with Firefox 136.0a1 (2025-01-21) only the
jar:file:///C:/Users/al3x_/Desktop/test.jar/test.jar!/resource.txtlink is loaded. Thejar:file:///C:/Users/al3x_/Desktop/test.jar/test.jar!/resource.txt%00.jsandjar:file:///C:/Users/al3x_/Desktop/test.jar/test.jar!/resource.txt%00links are showingFile not founderror (see screenshot). This was tested on Windows 10x64, macOS 12 and Ubuntu 24.04.
Just to be safe is the verification correct? Is there anything else that I should verify here?
| Assignee | ||
Comment 27•9 months ago
|
||
Thanks, that's all right!
Comment 28•9 months ago
|
||
Thank you!
Comment 29•9 months ago
|
||
The most interesting way to abuse this we've thought of is for a malicious extension to try to slip something by our reviewers. But it's still a malicious extension that a victim ``would have to install
| Reporter | ||
Comment 30•9 months ago
|
||
(In reply to Daniel Veditz [:dveditz] from comment #29)
The most interesting way to abuse this we've thought of is for a malicious extension to try to slip something by our reviewers. But it's still a malicious extension that a victim ``would have to install
I understand the extension would have to be install but this vulnerability would be running the JS code under the hood without the user knowing which is a security risk here and Thus can load Resources from WebExtensions or other JAR resources with the wrong content-type. This could lead to the execution of comment embedded in an images' metadata as JavaScript if %00.js were appended to the image URL.
From all the above discussion the conclusion comes that moz-extension are also vulnerable to this bug . as the team were able to reproduce the bug and the relevant patches have been applied , I want to know the when and how the bounty process would be initiated.
| Reporter | ||
Comment 31•9 months ago
|
||
Seems like my PGP was not set up for secure group email communication, I have done it now.
I am not sure weather the communication regarding the bounty have been made. if not, you can send me to my Email to initiate the bounty process since the PGP keys are now set.
Thank you Team !!
| Reporter | ||
Comment 32•9 months ago
|
||
Hello Team,
I wanted to get the CVE ID assigned to this bug, when can i expect the public information be disclosed ? so that I can apply for CVE MITRE to assign it a CVE.
Comment 33•8 months ago
|
||
:valentin could you add an esr128 uplift request on this?
| Assignee | ||
Comment 34•8 months ago
|
||
Original Revision: https://phabricator.services.mozilla.com/D234164
Updated•8 months ago
|
| Assignee | ||
Comment 35•8 months ago
|
||
Original Revision: https://phabricator.services.mozilla.com/D234164
Updated•8 months ago
|
Comment 36•8 months ago
|
||
esr128 Uplift Approval Request
- User impact if declined: Resources could be loaded from webextensions or other JAR resources with the wrong content-type. This could lead to the execution of comment embedded in an images' metadata as javascript if %00.js were appended to the image URL.
- Code covered by automated testing: yes
- Fix verified in Nightly: yes
- Needs manual QE test: yes
- Steps to reproduce for manual QE testing: See comment 25 and comment 26
- Risk associated with taking this patch: low
- Explanation of risk level: This patch attempts to make minimal behaviour changes to Firefox. It just changes the argument types of several methods to use nsACString instead of char*. The result is that percent unescaping the string should will pass the entire string to the consumer, and we will match the full path against the JAR resource, not just the characters before %00.
- String changes made/needed: none
- Is Android affected?: yes
| Assignee | ||
Updated•8 months ago
|
Updated•8 months ago
|
Updated•8 months ago
|
Updated•8 months ago
|
Updated•8 months ago
|
Updated•8 months ago
|
Updated•8 months ago
|
Comment 37•8 months ago
|
||
| uplift | ||
Updated•8 months ago
|
Comment 38•8 months ago
|
||
Verified fixed with 128.8.0esr on Windows 10x64, macOS 12 and Ubuntu 24. Same results as in comment 26.
Updated•8 months ago
|
Comment 39•7 months ago
|
||
Updated•7 months ago
|
Updated•6 months ago
|
Updated•3 months ago
|
Description
•