Timezone may leak from XSLT Date function
Looking at the patch for document.lastModified
, I looked at all the uses of PR_LocalTimeParameters and found this one that looks sketchy.
My concern would be that an attacker could render a XSLT document using a function that formats a datetime; then reads that XSLT document (cause it's same origin) and gets the timezone out.
Designs
- Show closed items
Activity
-
Newest first Oldest first
-
Show all activity Show comments only Show history only
- Tom Ritter added Fingerprinting label
added Fingerprinting label
- Author Developer
cc @thorin
Collapse replies - Maintainer
I can have a look next week
- Thorin added All Platforms label
added All Platforms label
- Maintainer
Okay, this seems to be some... non-standardish help Firefox does to XSLT?
The updated docs is at https://exslt.github.io/date/index.html, and some helps arrives from https://stackoverflow.com/a/1575134.
I tried to modify MDN's
XSLTProcessor
example:<div id="example"></div> <script> const xslText = ` <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:date="http://exslt.org/dates-and-times" extension-element-prefixes="date"> <xsl:output method="html" /> <!-- XSLT + extension, leaks --> <xsl:template match="/"><xsl:value-of select="date:date-time()" /></xsl:template> <!-- Does not leak, XSLT 2.0, unsupported --> <!--<xsl:template match="/"><xsl:value-of select="current-dateTime()" /></xsl:template>--> </xsl:stylesheet> `; const parser = new DOMParser(); const xsltProcessor = new XSLTProcessor(); const xslStylesheet = parser.parseFromString(xslText, "application/xml"); xsltProcessor.importStylesheet(xslStylesheet); const xmlDoc = parser.parseFromString("<body>Test</body>", "application/xml"); const fragment = xsltProcessor.transformToFragment(xmlDoc, document); document.getElementById("example").appendChild(fragment); </script>
This leaks
2024-03-25T11:41:34.020+01:00
. There's even a function to format the date, but I didn't have any luck in using it. This string should be enough.@tjr I haven't tried to write a patch yet (I assume it will be pretty similar to the other one). Do you want me to try to? And did you open a Bug already?
Collapse replies - Maintainer
Okay, I tried to make the PoC shorter by removing the XML content, but it seems my debug build really dislike it. I keep getting all sorts of errors with
GetReadyStateEnum
when trying to convert it to a fragment.Just to be sure, I changed it a little bit to use
transformToDocument
instead:<script> const xslText = ` <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:date="http://exslt.org/dates-and-times" extension-element-prefixes="date"> <xsl:output method="text" /> <xsl:template match="/"><xsl:value-of select="date:date-time()" /></xsl:template> </xsl:stylesheet> `; const parser = new DOMParser(); const xsltProcessor = new XSLTProcessor(); const xslStylesheet = parser.parseFromString(xslText, "application/xml"); xsltProcessor.importStylesheet(xslStylesheet); const xmlDoc = parser.parseFromString("<test />", "application/xml"); const styledDoc = xsltProcessor.transformToDocument(xmlDoc); document.write(styledDoc.firstChild.textContent); if (!styledDoc.firstChild.textContent.endsWith("+00:00")) { document.write(" Fail"); } else { document.write(" Pass"); } </script>
This doesn't trigger assertions and is usable with debug builds.
However, I have another problem now: I can't use the specialized
Document::ShouldResistFingerprinting
because there's a specialized context that refuses to pass the document.Diff that works (ESR 115 - no special RFPTarget)
diff --git a/dom/xslt/xslt/txEXSLTFunctions.cpp b/dom/xslt/xslt/txEXSLTFunctions.cpp index d4882d0b13cf..3eeebaf619a7 100644 --- a/dom/xslt/xslt/txEXSLTFunctions.cpp +++ b/dom/xslt/xslt/txEXSLTFunctions.cpp @@ -591,7 +591,12 @@ nsresult txEXSLTFunctionCall::evaluate(txIEvalContext* aContext, // http://exslt.org/date/functions/date-time/ PRExplodedTime prtime; - PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &prtime); + PR_ExplodeTime( + PR_Now(), + nsContentUtils::ShouldResistFingerprinting(RFPTarget::Unknown) + ? PR_GMTParameters + : PR_LocalTimeParameters, + &prtime); int32_t offset = (prtime.tm_params.tp_gmt_offset + prtime.tm_params.tp_dst_offset) /
Diff that doesn't work
diff --git a/dom/xslt/xslt/txEXSLTFunctions.cpp b/dom/xslt/xslt/txEXSLTFunctions.cpp index d4882d0b13cf..4d1fea3a87eb 100644 --- a/dom/xslt/xslt/txEXSLTFunctions.cpp +++ b/dom/xslt/xslt/txEXSLTFunctions.cpp @@ -590,8 +590,14 @@ nsresult txEXSLTFunctionCall::evaluate(txIEvalContext* aContext, case txEXSLTType::DATE_TIME: { // http://exslt.org/date/functions/date-time/ + Document* sourceDoc = getSourceDocument(aContext); + NS_ENSURE_STATE(sourceDoc); PRExplodedTime prtime; - PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &prtime); + PR_ExplodeTime(PR_Now(), + sourceDoc->ShouldResistFingerprinting(RFPTarget::Unknown) + ? PR_GMTParameters + : PR_LocalTimeParameters, + &prtime); int32_t offset = (prtime.tm_params.tp_gmt_offset + prtime.tm_params.tp_dst_offset) /
Stack trace
__GI___clock_nanosleep (@clock_nanosleep@GLIBC_2.2.5:29) __GI___nanosleep (@__nanosleep:9) __sleep (@sleep:17) common_crap_handler(int, void const*) (/home/piero/Tor/tor-browser/toolkit/xre/nsSigHandlers.cpp:96) child_ah_crap_handler(int) (/home/piero/Tor/tor-browser/toolkit/xre/nsSigHandlers.cpp:110) WasmTrapHandler(int, siginfo_t*, void*) (/home/piero/Tor/tor-browser/js/src/wasm/WasmSignalHandlers.cpp:799) __restore_rt (@__restore_rt:3) txEarlyEvalContext::getPrivateContext() (/home/piero/Tor/tor-browser/dom/xslt/xpath/txXPathOptimizer.cpp:33) getSourceDocument(txIEvalContext*) (/home/piero/Tor/tor-browser/dom/xslt/xslt/txEXSLTFunctions.cpp:46) txEXSLTFunctionCall::evaluate(txIEvalContext*, txAExprResult**) (/home/piero/Tor/tor-browser/dom/xslt/xslt/txEXSLTFunctions.cpp:593) txXPathOptimizer::optimize(Expr*, Expr**) (/home/piero/Tor/tor-browser/dom/xslt/xpath/txXPathOptimizer.cpp:63) txExprParser::createExprInternal(nsTSubstring<char16_t> const&, unsigned int, txIParseContext*, Expr**) (/home/piero/Tor/tor-browser/dom/xslt/xpath/txExprParser.cpp:175) txExprParser::createExpr(nsTSubstring<char16_t> const&, txIParseContext*, Expr**) (/home/piero/Tor/tor-browser/dom/xslt/xpath/txExprParser.h:33) getExprAttr(txStylesheetAttr*, int, nsAtom*, bool, txStylesheetCompilerState&, mozilla::UniquePtr<Expr, mozilla::DefaultDelete<Expr>>&) (/home/piero/Tor/tor-browser/dom/xslt/xslt/txStylesheetCompileHandlers.cpp:155) txFnStartValueOf(int, nsAtom*, nsAtom*, txStylesheetAttr*, int, txStylesheetCompilerState&) (/home/piero/Tor/tor-browser/dom/xslt/xslt/txStylesheetCompileHandlers.cpp:1830) txStylesheetCompiler::startElementInternal(int, nsAtom*, nsAtom*, txStylesheetAttr*, int) (/home/piero/Tor/tor-browser/dom/xslt/xslt/txStylesheetCompiler.cpp:257) txStylesheetCompiler::startElement(int, nsAtom*, nsAtom*, txStylesheetAttr*, int) (/home/piero/Tor/tor-browser/dom/xslt/xslt/txStylesheetCompiler.cpp:95) handleNode(nsINode*, txStylesheetCompiler*) (/home/piero/Tor/tor-browser/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp:475) handleNode(nsINode*, txStylesheetCompiler*) (/home/piero/Tor/tor-browser/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp:484) handleNode(nsINode*, txStylesheetCompiler*) (/home/piero/Tor/tor-browser/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp:484) handleNode(nsINode*, txStylesheetCompiler*) (/home/piero/Tor/tor-browser/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp:498) TX_CompileStylesheet(nsINode*, txMozillaXSLTProcessor*, txStylesheet**) (/home/piero/Tor/tor-browser/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp:609) txMozillaXSLTProcessor::ImportStylesheet(nsINode&, mozilla::ErrorResult&) (/home/piero/Tor/tor-browser/dom/xslt/xslt/txMozillaXSLTProcessor.cpp:518) mozilla::dom::XSLTProcessor_Binding::importStylesheet(JSContext*, JS::Handle<JSObject*>, void*, JSJitMethodCallArgs const&) (/home/piero/Tor/tor-browser/obj-x86_64-pc-linux-gnu/dom/bindings/XSLTProcessorBinding.cpp:983) bool mozilla::dom::binding_detail::GenericMethod<mozilla::dom::binding_detail::NormalThisPolicy, mozilla::dom::binding_detail::ThrowExceptions>(JSContext*, unsigned int, JS::Value*) (/home/piero/Tor/tor-browser/dom/bindings/BindingUtils.cpp:3329) CallJSNative(JSContext*, bool (*)(JSContext*, unsigned int, JS::Value*), js::CallReason, JS::CallArgs const&) (/home/piero/Tor/tor-browser/js/src/vm/Interpreter.cpp:486) js::InternalCallOrConstruct(JSContext*, JS::CallArgs const&, js::MaybeConstruct, js::CallReason) (/home/piero/Tor/tor-browser/js/src/vm/Interpreter.cpp:580) InternalCall(JSContext*, js::AnyInvokeArgs const&, js::CallReason) (/home/piero/Tor/tor-browser/js/src/vm/Interpreter.cpp:647) js::CallFromStack(JSContext*, JS::CallArgs const&, js::CallReason) (/home/piero/Tor/tor-browser/js/src/vm/Interpreter.cpp:652) js::Interpret(JSContext*, js::RunState&) (/home/piero/Tor/tor-browser/js/src/vm/Interpreter.cpp:3395) MaybeEnterInterpreterTrampoline(JSContext*, js::RunState&) (/home/piero/Tor/tor-browser/js/src/vm/Interpreter.cpp:400) js::RunScript(JSContext*, js::RunState&) (/home/piero/Tor/tor-browser/js/src/vm/Interpreter.cpp:458) js::ExecuteKernel(JSContext*, JS::Handle<JSScript*>, JS::Handle<JSObject*>, js::AbstractFramePtr, JS::MutableHandle<JS::Value>) (/home/piero/Tor/tor-browser/js/src/vm/Interpreter.cpp:845) js::Execute(JSContext*, JS::Handle<JSScript*>, JS::Handle<JSObject*>, JS::MutableHandle<JS::Value>) (/home/piero/Tor/tor-browser/js/src/vm/Interpreter.cpp:877) ExecuteScript(JSContext*, JS::Handle<JSObject*>, JS::Handle<JSScript*>, JS::MutableHandle<JS::Value>) (/home/piero/Tor/tor-browser/js/src/vm/CompilationAndEvaluation.cpp:493) JS_ExecuteScript(JSContext*, JS::Handle<JSScript*>) (/home/piero/Tor/tor-browser/js/src/vm/CompilationAndEvaluation.cpp:517) mozilla::dom::JSExecutionContext::ExecScript() (/home/piero/Tor/tor-browser/dom/base/JSExecutionContext.cpp:241) mozilla::dom::ExecuteCompiledScript(JSContext*, mozilla::dom::JSExecutionContext&, JS::loader::ClassicScript*) (/home/piero/Tor/tor-browser/dom/script/ScriptLoader.cpp:2153) mozilla::dom::ScriptLoader::EvaluateScript(nsIGlobalObject*, JS::loader::ScriptLoadRequest*) (/home/piero/Tor/tor-browser/dom/script/ScriptLoader.cpp:2418) mozilla::dom::ScriptLoader::EvaluateScriptElement(JS::loader::ScriptLoadRequest*) (/home/piero/Tor/tor-browser/dom/script/ScriptLoader.cpp:2222) mozilla::dom::ScriptLoader::ProcessRequest(JS::loader::ScriptLoadRequest*) (/home/piero/Tor/tor-browser/dom/script/ScriptLoader.cpp:1863) mozilla::dom::ScriptLoader::ProcessInlineScript(nsIScriptElement*, JS::loader::ScriptKind) (/home/piero/Tor/tor-browser/dom/script/ScriptLoader.cpp:1297) mozilla::dom::ScriptLoader::ProcessScriptElement(nsIScriptElement*, nsTAutoStringN<char16_t, 64ul> const&) (/home/piero/Tor/tor-browser/dom/script/ScriptLoader.cpp:922) mozilla::dom::ScriptElement::MaybeProcessScript() (/home/piero/Tor/tor-browser/dom/script/ScriptElement.cpp:183) nsIScriptElement::AttemptToExecute() (/home/piero/Tor/tor-browser/obj-x86_64-pc-linux-gnu/dist/include/nsIScriptElement.h:222) nsHtml5TreeOpExecutor::RunScript(nsIContent*) (/home/piero/Tor/tor-browser/parser/html/nsHtml5TreeOpExecutor.cpp:950) nsHtml5TreeOpExecutor::RunFlushLoop() (/home/piero/Tor/tor-browser/parser/html/nsHtml5TreeOpExecutor.cpp:741) nsHtml5ExecutorReflusher::Run() (/home/piero/Tor/tor-browser/parser/html/nsHtml5TreeOpExecutor.cpp:80) mozilla::SchedulerGroup::Runnable::Run() (/home/piero/Tor/tor-browser/xpcom/threads/SchedulerGroup.cpp:114) mozilla::RunnableTask::Run() (/home/piero/Tor/tor-browser/xpcom/threads/TaskController.cpp:555) mozilla::TaskController::DoExecuteNextTaskOnlyMainThreadInternal(mozilla::detail::BaseAutoLock<mozilla::Mutex&> const&) (/home/piero/Tor/tor-browser/xpcom/threads/TaskController.cpp:879) mozilla::TaskController::ExecuteNextTaskOnlyMainThreadInternal(mozilla::detail::BaseAutoLock<mozilla::Mutex&> const&) (/home/piero/Tor/tor-browser/xpcom/threads/TaskController.cpp:702) mozilla::TaskController::ProcessPendingMTTask(bool) (/home/piero/Tor/tor-browser/xpcom/threads/TaskController.cpp:491) mozilla::TaskController::TaskController()::$_0::operator()() const (/home/piero/Tor/tor-browser/xpcom/threads/TaskController.cpp:218) mozilla::detail::RunnableFunction<mozilla::TaskController::TaskController()::$_0>::Run() (/home/piero/Tor/tor-browser/xpcom/threads/nsThreadUtils.h:548) nsThread::ProcessNextEvent(bool, bool*) (/home/piero/Tor/tor-browser/xpcom/threads/nsThread.cpp:1240) NS_ProcessNextEvent(nsIThread*, bool) (/home/piero/Tor/tor-browser/xpcom/threads/nsThreadUtils.cpp:479) mozilla::ipc::MessagePump::Run(base::MessagePump::Delegate*) (/home/piero/Tor/tor-browser/ipc/glue/MessagePump.cpp:85) mozilla::ipc::MessagePumpForChildProcess::Run(base::MessagePump::Delegate*) (/home/piero/Tor/tor-browser/ipc/glue/MessagePump.cpp:268) MessageLoop::RunInternal() (/home/piero/Tor/tor-browser/ipc/chromium/src/base/message_loop.cc:368) MessageLoop::RunHandler() (/home/piero/Tor/tor-browser/ipc/chromium/src/base/message_loop.cc:361) MessageLoop::Run() (/home/piero/Tor/tor-browser/ipc/chromium/src/base/message_loop.cc:343) nsBaseAppShell::Run() (/home/piero/Tor/tor-browser/widget/nsBaseAppShell.cpp:148) XRE_RunAppShell() (/home/piero/Tor/tor-browser/toolkit/xre/nsEmbedFunctions.cpp:717) mozilla::ipc::MessagePumpForChildProcess::Run(base::MessagePump::Delegate*) (/home/piero/Tor/tor-browser/ipc/glue/MessagePump.cpp:235) MessageLoop::RunInternal() (/home/piero/Tor/tor-browser/ipc/chromium/src/base/message_loop.cc:368) MessageLoop::RunHandler() (/home/piero/Tor/tor-browser/ipc/chromium/src/base/message_loop.cc:361) MessageLoop::Run() (/home/piero/Tor/tor-browser/ipc/chromium/src/base/message_loop.cc:343) XRE_InitChildProcess(int, char**, XREChildData const*) (/home/piero/Tor/tor-browser/toolkit/xre/nsEmbedFunctions.cpp:652) mozilla::BootstrapImpl::XRE_InitChildProcess(int, char**, XREChildData const*) (/home/piero/Tor/tor-browser/toolkit/xre/Bootstrap.cpp:67) content_process_main(mozilla::Bootstrap*, int, char**) (/home/piero/Tor/tor-browser/ipc/contentproc/plugin-container.cpp:57) main (/home/piero/Tor/tor-browser/browser/app/nsBrowserApp.cpp:375) __libc_start_call_main (@__libc_start_call_main:26) __libc_start_main_impl (@__libc_start_main@@GLIBC_2.34:43) _start (@_start:14)
For Tor Browser and Mullvad Browser, the currently working patch would be enoough. We technically support neither turning RFP off, nor adding exceptions.
Given that this is a very obscure feature of web technologies, maybe the patch is okay also for Firefox
. - Maintainer
Notice that through the specialized context we can access only the recycler.
It includes some node-related stuff, but if I understand correctly, you can get only
txXPathNode
, which exposesoperator==
andoperator!=
, but doesn't allow a direct access to the underlyingnsINode
, so noOwnerDoc
even from there. - Maintainer
you don't need to write to doc to get the value
But you need to access the processed XML to get the value.
So, you need either to convert it to a fragment, or to a document passing through the
XSLTProcessor
. - Maintainer
Okay, but then are you referring to the two
document.write
? They weren't a problem, the problem was before.In any case, I agree that we can stop when we declare
styledDoc
and then just accessstyledDoc.firstChild.textContent
.But it's a PoC, so it's good enough for my purposes.
- Pier Angelo Vendrame assigned to @pierov
assigned to @pierov
- Pier Angelo Vendrame added Doing label
added Doing label
- Pier Angelo Vendrame added Uplift label
added Uplift label
- Pier Angelo Vendrame added 13.5 stable label
added 13.5 stable label
- Pier Angelo Vendrame added Backport label
added Backport label
- Pier Angelo Vendrame added 13.0 stable label
added 13.0 stable label
- Pier Angelo Vendrame mentioned in merge request !962 (merged)
mentioned in merge request !962 (merged)
- Pier Angelo Vendrame marked this issue as related to tor-browser-build#41094 (closed)
marked this issue as related to tor-browser-build#41094 (closed)
- Pier Angelo Vendrame marked this issue as related to tor-browser-build#41095 (closed)
marked this issue as related to tor-browser-build#41095 (closed)
- Pier Angelo Vendrame marked this issue as related to tor-browser-build#41099 (closed)
marked this issue as related to tor-browser-build#41099 (closed)
- Pier Angelo Vendrame marked this issue as related to tor-browser-build#41100 (closed)
marked this issue as related to tor-browser-build#41100 (closed)
- Pier Angelo Vendrame removed Doing label
removed Doing label
- Pier Angelo Vendrame added Next label
added Next label
- Thorin mentioned in issue #42493 (closed)
mentioned in issue #42493 (closed)
- Pier Angelo Vendrame removed Next label
removed Next label
- Pier Angelo Vendrame added Next label
added Next label
- Maintainer
Backports: 4b70c6b0, a975b00f and mullvad-browser@1b1e94cd.
Keeping the issue open to remind me to open an upstream Bug.
Collapse replies - Maintainer
Done: Bug 1891690.
1 1
- Pier Angelo Vendrame closed
closed
- Pier Angelo Vendrame removed Next label
removed Next label
- Pier Angelo Vendrame changed title from Timezone May leak from XSLT Date function to Timezone may leak from XSLT Date function
changed title from Timezone May leak from XSLT Date function to Timezone may leak from XSLT Date function
- Pier Angelo Vendrame made the issue visible to everyone
made the issue visible to everyone
- Pier Angelo Vendrame marked this issue as related to #30862 (closed)
marked this issue as related to #30862 (closed)
- Pier Angelo Vendrame mentioned in merge request !1137 (merged)
mentioned in merge request !1137 (merged)