Reflected XSS without CSP bypass in Socorro via controllable parsed.path in views.highlight_url
Categories
(Socorro :: General, defect, P1)
Tracking
(Not tracked)
People
(Reporter: 40826d, Assigned: willkg)
References
()
Details
(Keywords: reporter-external, sec-low, wsec-xss, Whiteboard: [reporter-external] [web-bounty-form] [verif?])
Attachments
(2 files)
Summary
Bug 1389217 introduced syntax highlighting of generated source files in Socorro. The view function takes the url
query parameter and validates it such that only files under http[s]://gecko-generated-sources.s3.amazonaws.com
will be fetched and highlighted with Pygments.
For example:
https://crash-stats.mozilla.org/sources/highlight/?url=https://gecko-generated-sources.s3.amazonaws.com/7a1db5dfd0061d0e0bcca227effb419a20439aef4f6c4e9cd391a9f136c6283e89043d62e63e7edbd63ad81c339c401092bcfeff80f74f9cae8217e072f0c6f3/x86_64-pc-windows-msvc/release/build/swgl-59e3a0e09f56f4ea/out/brush_solid_DEBUG_OVERDRAW.h
I was unable to bypass the validation or traverse anywhere meaningful (the only allowed host is a dedicated S3 bucket) but did find an interesting behaviour giving us control of the parsed.path
that is passed to the title
option of Pygments' HtmlFormatter which is ultimately returned unescaped:
def highlight_url(request):
# ...
url = request.GET.get("url")
# ...
parsed = urlparse(url)
# ...
filename = parsed.path.split("/")[-1]
# ...
formatter = HtmlFormatter(
full=True, title=parsed.path, linenos="table", lineanchors="L", hl_lines=lines
)
return http.HttpResponse(
highlight(resp.text, lexer, formatter), content_type="text/html"
)
Browsing to the following URL will trigger a CSP error (unless you disabled CSP using a WebExtension or intercept proxy, in which case you will observe an alert dialog with the value of document.domain
):
https://crash-stats.mozilla.org/sources/highlight/?url=https://gecko-generated-sources.s3.amazonaws.com/7a1db5dfd0061d0e0bcca227effb419a20439aef4f6c4e9cd391a9f136c6283e89043d62e63e7edbd63ad81c339c401092bcfeff80f74f9cae8217e072f0c6f3/x86_64-pc-windows-msvc/release/build/swgl-59e3a0e09f56f4ea/\%3Ch1%3ECheck%20DevTools%3Csvg%20onload=confirm(document.domain)%3E\out/../out/brush_solid_DEBUG_OVERDRAW.h
Environment
- Confirmed on: crash-stats.allizom.org, crash-stats.mozilla.org
- Browser: Firefox Nightly 108.0a1 (2022-10-27)
Impact
An attacker can execute arbitrary JavaScript in the context of another user on Socorro to exfiltrate Protected Data and perform actions as that user provided that CSP is unsupported or disabled in the browser. The impact is otherwise limited to HTML and CSS injection.
Reporter | ||
Comment 1•2 years ago
|
||
Updated•2 years ago
|
Comment 2•2 years ago
|
||
Hello Viridian,
Thank you for your detailed and well written report.
I can confirm that the added HTML is injected on the page and I can see the CSP violation in the console.
Thanks,
Frida
Comment 3•2 years ago
|
||
Hello Will,
I found that you worked on previous security reports for Socorro, can you please take a look at this report?
Thanks,
Frida
Reporter | ||
Comment 4•2 years ago
|
||
Thanks Frida, appreciate it!
By the way, I wondered if the Socorro team could help with a couple questions:
- How are raw crash data validated upon ingestion?
- Could an attacker influence the content type of an attachment they submit and and then fetch it back intact via the RawCrash API?
Assignee | ||
Comment 5•2 years ago
|
||
Yuck! Thank you for finding this! I'm grabbing this to fix now.
How are raw crash data validated upon ingestion?
Crash report payload structure is specified here:
https://socorro.readthedocs.io/en/latest/spec_crashreport.html
If you're planning to experiment with crash report payloads, please don't do it with our production system. Please use the stage environment instead.
Could an attacker influence the content type of an attachment they submit and and then fetch it back intact via the RawCrash API?
I don't think so. The RawCrash API returns either application/json
or application/octet-stream
and doesn't infer the content type from the content being requested.
The RawCrash API was implemented as a "model" with an api wrapper. That predates me and I'm not sure why it's squirrely and not more straight-forward.
Here's what determines the content type for the crash annotations (a set of key/values returned as JSON via the raw crash api):
Here's what determines the content type for all the other things attached to a crash report (minidump, memory_report, etc):
Assignee | ||
Comment 6•2 years ago
|
||
Assignee | ||
Comment 7•2 years ago
|
||
Reporter | ||
Comment 8•2 years ago
|
||
Thanks very much for the pointers Will (and the fast fix!)
If you're planning to experiment with crash report payloads, please don't do it with our production system. Please use the stage environment instead.
Of course. I haven't looked much at the rest of the pipeline yet, just the web app, but I'll make sure to test on stage when I do (or my local setup, if I get those parts working).
Assignee | ||
Comment 9•2 years ago
|
||
This was pushed to prod just now in bug #1798949. Marking as FIXED.
Thank you for reporting!
Updated•2 years ago
|
Updated•2 years ago
|
Updated•4 months ago
|
Description
•