Closed Bug 1666777 Opened 4 years ago Closed 4 years ago

HTML Sanitizer Bypass with combined Image + onerror and STYLE element

Categories

(Core :: DOM: Core & HTML, defect, P1)

defect

Tracking

()

VERIFIED DUPLICATE of bug 1667113

People

(Reporter: sourc7, Unassigned)

References

Details

(Keywords: reporter-external, sec-high, Whiteboard: [reporter-external] [client-bounty-form] [verif?])

Attachments

(3 files)

When directly testing the HTML Sanitizer, I found I able to bypass Firefox 83.0a1 (2020-09-23) HTML sanitizer with mXSS payload: <svg><style>[any xss payload]

In example after inserting document.body.innerHTML = '<svg><style><svg onload="javascript:alert(1337)"></svg>' to the browser console, I didn't receive warning message from the HTML sanitizer (e.g. "Removed unsafe attribute. Element: svg. Attribute: onload.").

Flags: sec-bounty?

The resulting parsed DOM is <svg><style></style></svg> though, so it's not clear to me whether there's really an issue here - maybe we're neglecting to warn because ? Kris or Freddy, do you know?

Group: firefox-core-security → dom-core-security
Type: task → defect
Component: Security → DOM: Core & HTML
Flags: needinfo?(kmaglione+bmo)
Flags: needinfo?(fbraun)
Product: Firefox → Core

The resulting parsed DOM is <svg><style></style></svg> though

Hi :Gijs what command to show the DOM output? I'm sorry if this is a false positive.

I'm currently using Firefox DOMParser the output is:

var payload = `<svg><style><svg onload="javascript:alert(1337)"></svg>`;
var doc = new DOMParser().parseFromString(payload, "text/html")
doc.body.innerHTML
"<svg><style><svg onload=\"javascript:alert(1337)\"></svg></style></svg>"
Attached image DOMParser output

Well, I'm pretty sure it's not warning about the onload attribute because the entire <svg> element is being dropped. As for why the SVG element is being dropped, I have no idea. It would be interesting to know, but as long as we're not actually executing the script, I'm happy.

Flags: needinfo?(kmaglione+bmo)

(In reply to Irvan Kurniawan from comment #2)

The resulting parsed DOM is <svg><style></style></svg> though

Hi :Gijs what command to show the DOM output? I'm sorry if this is a false positive.

I used .innerHTML in the about:config document, as you did in comment #0. Although the assignment expression's result is the same as the input (ie so that foo = bar = "string" assigns the same string everywhere), if you check document.body.innerHTML after the assignment, you'll see that the attribute has disappeared.

I don't know if it's a false positive, I'm not an expert on our sanitizer code. The blogpost does suggest using innerHTML.

I'm currently using Firefox DOMParser the output is:

var payload = `<svg><style><svg onload="javascript:alert(1337)"></svg>`;
var doc = new DOMParser().parseFromString(payload, "text/html")
doc.body.innerHTML
"<svg><style><svg onload=\"javascript:alert(1337)\"></svg></style></svg>"

If you check doc.nodePrincipal after this snippet (assuming you're executing in a privileged console) then you'll see it's a null principal (ie same as a sandboxed iframe) - the DOM parser is parsing into a new, unprivileged document. Therefore the sanitizer does not run (or it'd break web content using innerHTML unsafely - of course that might be a good thing for security, but users can't really deal with that level of breakage...). You can compare with document.nodePrincipal which on about:config or about:preferences or similar will show a system principal ("chrome privileges", ie same execution privileges as JS from Firefox itself).

The <svg> element in the <style> node gets removed because we sanitize <style> nodes by getting their text content, sanitizing it, and then setting its new text content to the sanitized value, which automatically removes any non-text nodes in the process.

Status: UNCONFIRMED → RESOLVED
Closed: 4 years ago
Resolution: --- → INVALID

if you check document.body.innerHTML after the assignment, you'll see that the attribute has disappeared.

Thanks :Gijs for the detailed explanation, I able to view DOM output as you mention:

> document.body.innerHTML = '<svg><style><svg onload="javascript:alert(1337)"></svg>'
> "<svg><style><svg onload=\"javascript:alert(1337)\"></svg>"
> Content Security Policy: The page’s settings blocked the loading of a resource at inline (“default-src”). debugger eval code:1
> document.body.innerHTML
> "<svg><style></style></svg>"

Sorry it's my fault not checking document.body.innerHTML on about:config to check the DOM output. I was think it same as normal page (e.g example.com)

Status: RESOLVED → VERIFIED

(In reply to Kris Maglione [:kmag] from comment #4)

Well, I'm pretty sure it's not warning about the onload attribute because the entire <svg> element is being dropped. As for why the SVG element is being dropped, I have no idea. It would be interesting to know, but as long as we're not actually executing the script, I'm happy.

Hi Kris and :Gijs I found out it able to execute script :D, please re-open the ticket.

Steps to reproduce

  1. Go to about:config
  2. Set security.csp.enable boolean from true -> false
  3. Restart Firefox Nightly
  4. Go to about:config
  5. Insert document.body.innerHTML = "<svg><style><image href='https://www.example.com' onerror='alert(9113)'></svg>" to the console
  6. XSS will execute

Although DOM output show "<svg><style></style></svg>", but script execution is still possible.

Attached image PoC - Script Execution

(In reply to Irvan Kurniawan from comment #8)

(In reply to Kris Maglione [:kmag] from comment #4)

Well, I'm pretty sure it's not warning about the onload attribute because the entire <svg> element is being dropped. As for why the SVG element is being dropped, I have no idea. It would be interesting to know, but as long as we're not actually executing the script, I'm happy.

Hi Kris and :Gijs I found out it able to execute script :D, please re-open the ticket.

I'm not sure if this is going to be materially different from bug 1666300 - I think if we fix that, this bug will be fixed, too. But we can reopen this to make sure we don't miss it going forward.

Status: VERIFIED → REOPENED
Ever confirmed: true
Resolution: INVALID → ---
See Also: → CVE-2020-26956, 1666893
Summary: HTML Sanitizer Bypass with combined SVG and STYLE element → HTML Sanitizer Bypass with combined Image + onerror and STYLE element

(In reply to :Gijs (he/him) from comment #10)

(In reply to Irvan Kurniawan from comment #8)

(In reply to Kris Maglione [:kmag] from comment #4)

Well, I'm pretty sure it's not warning about the onload attribute because the entire <svg> element is being dropped. As for why the SVG element is being dropped, I have no idea. It would be interesting to know, but as long as we're not actually executing the script, I'm happy.

Hi Kris and :Gijs I found out it able to execute script :D, please re-open the ticket.

I'm not sure if this is going to be materially different from bug 1666300 - I think if we fix that, this bug will be fixed, too. But we can reopen this to make sure we don't miss it going forward.

Hi :Gijs thanks for re-opening this report.

In my opinion, it would be great to merge this report to bug 1666300 (edit the title it also able to bypass the HTML Sanitizer)

Flags: needinfo?(fbraun)
Depends on: CVE-2020-26956, 1666893
Keywords: sec-high

Hi Daniel, bug 1666300 has been classified as sec-moderate and seems to be most likely the cause for this as of comment 10. Should we reconsider classification here or there?

Flags: needinfo?(dveditz)

bug 1666300 was classified sec-moderate because it involved copy/paste (user action) in a web context. This bug points out that the same mechanism impacts our defense-in-depth against privilege escalation attacks into a browser/chrome UI context, which is properly rated sec-high (it's a kind of "sandbox escape"). We probably don't need so many bugs tracking what it almost surely the same underlying problem, but whatever bug remains should be sec-high.

One worry about coalescing bugs is that we lose testcases/scenarios we have to verify along the way, and then end up missing edgecases and embarrassing ourselves when we announce the incomplete fix. E.g. there may be special-case code around svg vs. other elements. Since we have a sec-high problem to solve it should be handled quickly and a temporary overcount of a sec-moderate or two don't really matter.

Flags: needinfo?(dveditz)
Severity: -- → S2
Priority: -- → P1

This was fixed as bug 1667113 from the same reporter.

Status: REOPENED → RESOLVED
Closed: 4 years ago4 years ago
Resolution: --- → DUPLICATE
Status: RESOLVED → VERIFIED
Flags: sec-bounty? → sec-bounty-
Group: dom-core-security
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: