Closed Bug 640529 Opened 13 years ago Closed 12 years ago

too general "charset=" detection in meta into xss

Categories

(Core :: DOM: HTML Parser, defect)

1.9.2 Branch
defect
Not set
normal

Tracking

()

RESOLVED FIXED

People

(Reporter: gynvael, Unassigned)

References

()

Details

(Keywords: sec-low, sec-moderate, Whiteboard: [fixed by the HTML5 parser][sg:moderate] for 3.6, [sg:low] for 4.0, requires coordinated disclosure)

User-Agent:       Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.82 Safari/534.16
Build Identifier: Firefox 3.6.15 (fully) & 4.0rc1 (partly) 

Hey guys,

By accident we've found a bug in Firefox (FF3,FF4) <meta> tag (too
general "charset=" detection). In some cases this might allow (FF3)
setting charset to e.g. utf-7 and resulting an XSS (e.g. on redirector
pages).
Assumption: charset is not set in HTTP header or in any previous meta.

On encountering <meta> tag, the charset detection (FF3) looks for
"charset=" substring anywhere in the <meta...> string.
E.g.:

Correct usage:
<meta charset="utf-8">

Evil usage in some redirector (as suggested by lcamtuf, FF3 only):
<meta http-equiv="Refresh" content="10;http://www.example.com/charset=utf-7">
                                                              ^^^^^^^^^^^^^
(followed by e.g.
+ADw-script+AD4-alert(document.location)+ADw-/script+AD4- or sth)
In this case the "charset=" substring will be found (and used) from
inside the 'content' attribute.

(Please note that such redirectors exist in the wild, so it could be used to XSS some users)

Source-level rationale:
./intl/chardet/src/nsMetaCharsetObserver.cpp (mozilla-1.9.2 - Firefox 3.6rc2)

[c.a. line 256]
          PRInt32 start = contentPart1.RFind("charset=", PR_TRUE ) ;
(I'm not 100% sure that it's caused by this line, but it should be near)

In FF4 this seems to be somewhat different, because the above "evil"
version will not change the charset, however e.g. this still will work
(and probably should not):

<meta http-equiv="Content-Type" value="text/html;XYZcharset=utf-8" />
                                                 ^^^

Seems Opera (and Konqueror) are also affected, so please consider
coordinated disclosure at least with Opera (I'll handle contacting them).

Kudos to lcamtuf & sirdarckcat for the XSS idea, and thanks to Ben Hawkes for taking a look too.

I'll CC lcamtuf and sirdarckat in this bug (if for some reason (access?) I cannot do that, please add them, thanks!).



Reproducible: Always

Steps to Reproduce:
FF3:
1. Create/find/whatever a redirector that takes an URL as an argument and creates a meta Refresh redirection out of that
2. Add charset=SOMECHARSET to the redirected URL (e.g. http://something/charset=utf-7)
3. Watch the charset actually change.

FF4:
1. Create a page with
<meta http-equiv="Content-Type" value="text/html;XYZcharset=SOMECHARSET" />
2. Watch the charset actually change. (XYZcharset is not a proper keyword)
Actual Results:  
Charset was changed in both cases, when it should remain default.

Expected Results:  
Charset should not change in neither of the described cases.
Whiteboard: [sg:moderate] for 3.6, [sg:low] for 4.0, requires coordinated disclosure
Looks like bug 414064 removed UTF7 support. Is this bug still exploitable in other ways, or was UTF7 the only issue (and thus now fixed)?
Hey,

Well, in FF4 it was a minor problem anyway.
(FF3 was the real problem, but I guess it's not supported any more?)

But, to answer your question: removing UTF-7 doesn't solve the bug entirely because there are still other encodings like Shift JIS which can be used in some cases to bypass ansi-XSS escaping (especially JS backslash escaping).
That being said, the probability of this being exploitable in real world is really low (due to the fact that the page would have to blacklist the 'charset' keyword in said meta, and for some reason allow user input in that place, and there would have to be another JS-encoded input someplace on the page; all three of these together seem unlikely).

However, it seems some change in this place has been done anyway.
In FF4 this worked:
<meta http-equiv="Content-Type" value="text/html;XYZcharset=shift-jis" />
and in FF6 it doesn't.
The only thing that still works is:
<meta http-equiv="Content-Type" value="text/html;Acharset=shift-jis" />
i.e. only one character between ; and the word "charset" seems to work.

It still might be used to bypass some blacklist checks. But it's a really minor issue.

Cheers,
Hey,

I guess there is no reason for this bug to be private anymore. Could you mark it as Public?

Cheers,
Bouncing this over to Core::General, not sure if there's a better place for it.

I sorta suspect this might be a duplicate of some other bug? Seems like the general issue here is that of strange encodings being used to trick things not expecting said encodings, which I know has come up before. (UTF-7 being the prime example).
Product: Firefox → Core
QA Contact: general → general
Over to parser; this is totally Henri's sort of thing.
Component: General → HTML: Parser
QA Contact: general → parser
(In reply to Gynvael Coldwind from comment #2)
> Well, in FF4 it was a minor problem anyway.

Firefox trunk seems to work per spec. (I also inspected the source.)

Not honored as Shift_JIS:
<meta name="description" content="charset=shift_jis">
<meta http-equiv="Refresh" content="10000;http://www.example.com/charset=shift_jis">
<meta http-equiv="content-type" value="text/html; charset=shift_jis">

Honored as Shift_JIS:
<meta http-equiv="content-type" content="WHATEVERcharset=shift_jis">

> (FF3 was the real problem, but I guess it's not supported any more?)

Firefox 3.6 is still supported, but I'm not sure for what levels of security bugs. That is, I'm not sure if sg:moderate qualifies.

> In FF4 this worked:
> <meta http-equiv="Content-Type" value="text/html;XYZcharset=shift-jis" />
> and in FF6 it doesn't.

That's because attribute name is 'value' rather than 'content'.

> The only thing that still works is:
> <meta http-equiv="Content-Type" value="text/html;Acharset=shift-jis" />
> i.e. only one character between ; and the word "charset" seems to work.

Are you sure? With 'value' as the attribute name?

With 'content' as the attribute name, you can have whatever cruft before "charset" part as long as there's another attribute whose name is http-equiv and whose value is ASCII case-insensitively "content-type". This is as specced.

> It still might be used to bypass some blacklist checks. But it's a really
> minor issue.

What's the threat model? If a site allows a malicious party to control any substring of the value of the content attribute when the tag also has a http-equiv="Content-Type" attribute, hasn't the site lost security-wise no matter what?

I'm marking this confirmed for 3.6.x.

bz, what's our policy for sg:moderate fixes for 3.6 when there's no trunk patch that could be trivially applied to 3.6? In this case, fixing 3.6 would involve modifying code that's no longer on trunk.
Status: UNCONFIRMED → NEW
Ever confirmed: true
Version: unspecified → 1.9.2 Branch
Oh, and 3.6 is vulnerable if the tag is <meta name="description" content="charset=shift_jis">. Does the ability to mount the attack from UGC in description metadata change the sg:* level compared to mounting the attack from a Refresh URL?

Curiously, Opera Ragnarök is vulnerable--not just Opera's old parser.
My gut feel is that sg:moderate is wontfix for 3.6, but it's not really my call...  ccing dveditz.
Group: core-security
Henri, do you think we could close this bug?
(In reply to Olli Pettay [:smaug] from comment #9)
> Henri, do you think we could close this bug?

Yes. This is really WONTFIX for 3.6, but to make the status clearer at a glance, making [fixed by the HTML5 parser] and FIXED.

I’m a bit unhappy we disclosed this bug without waiting for Opera.
Status: NEW → RESOLVED
Closed: 12 years ago
Resolution: --- → FIXED
Whiteboard: [sg:moderate] for 3.6, [sg:low] for 4.0, requires coordinated disclosure → [fixed by the HTML5 parser][sg:moderate] for 3.6, [sg:low] for 4.0, requires coordinated disclosure
(In reply to Henri Sivonen (:hsivonen) from comment #10)
> Yes. This is really WONTFIX for 3.6, but to make the status clearer at a
> glance, making [fixed by the HTML5 parser] and FIXED.

For clarity, I think the “[sg:low] for 4.0” bit is incorrect. I think this isn’t sg:/sec- anything on 4.0 or later. See comment 6.
You need to log in before you can comment on or make changes to this bug.