Closed Bug 1883693 (CVE-2024-5690) Opened 1 year ago Closed 1 year ago

Leaking Browser URL/Protocol Handlers by img onerror loading time

Categories

(Core :: Networking, defect, P2)

defect

Tracking

()

VERIFIED FIXED
127 Branch
Tracking Status
firefox-esr115 127+ verified
firefox125 --- wontfix
firefox126 --- wontfix
firefox127 + verified

People

(Reporter: t.satoki111, Assigned: valentin)

References

Details

(Keywords: csectype-disclosure, reporter-external, sec-moderate, Whiteboard: [reporter-external] [client-bounty-form] [verif?][necko-triaged][necko-priority-queue][adv-main127+][adv-esr115.12+])

Attachments

(6 files)

Attached file poc_img.html

Hello, I'm Satoki, a CTF player and security engineer. Inspired by CVE-2020-15680, I've discovered a new leak involving external protocol handlers. The mechanism is simple: it measures the time from when the loading of an "img" tag starts to when the "onerror" event is triggered. I've found that if a handler exists, there's a delay in response.

Threshold: 455ms
amazon:// : 437ms
ftp:// : 853ms
geo:// : 400ms
instagram:// : 392ms
mailto:// : 2527ms
ms-edge:// : 401ms
ms-store:// : 441ms
onenote:// : 952ms
skype:// : 395ms
slack:// : 901ms
sms:// : 470ms
spotify:// : 886ms
steam:// : 834ms
tel:// : 1619ms
twitch:// : 474ms
twitter:// : 455ms
whatsapp:// : 406ms
zoommtg:// : 873ms

No user interaction is required for this leak. I'm attaching poc_img.html, but the behavior is the same when deployed on a server.

Have you become a bit tired of me reporting similar vulnerabilities every time? I apologize ;(

Flags: sec-bounty?
Group: firefox-core-security → dom-core-security
Component: Security → DOM: Events
Product: Firefox → Core

Nika found that we don't create the channel at all if the external protocol handler doesn't exist, so that may be causing the issue.

Tom, how much do we care about this kind of fingerprinting for external handlers? Thanks.

Flags: needinfo?(tom)

I am guessing this is because of how and when we detect that the protocol handler doesn't exist. We appear to do external protocol handler existence checks when trying to create the ext protocol handler channel, which means the check is done before we have done content security checks. This could mean that the behaviour & timing of the error is slightly different if the handler exists vs. if it doesn't.

This might be as simple as removing the check to avoid creating the channel if the protocol handler doesn't exist (https://searchfox.org/mozilla-central/rev/6b0b8c1003504e302e243c300355ef4d61e24909/uriloader/exthandler/nsExternalProtocolHandler.cpp#523-529), and then instead making the channel fail to open in that case, by switching the debug check in OpenURL to a runtime check which sets rv = NS_ERROR_UNKNOWN_PROTOCOL and goto finish;-es (https://searchfox.org/mozilla-central/rev/6b0b8c1003504e302e243c300355ef4d61e24909/uriloader/exthandler/nsExternalProtocolHandler.cpp#152-161).

Not sure what other impacts this change might have (we may have some places where we're relying on the exception happening when the channel is created rather than when the channel is opened?).

Could be interesting to confirm if this timing change would disappear with this change.

(In reply to Andrew McCreight [:mccr8] from comment #2)

Tom, how much do we care about this kind of fingerprinting for external handlers? Thanks.

We (Emilio IIRC) made a concerted effort to remove this leak, so this vector is unfortunate and we would like to fix it to be consistent with our previous goals, but it's a sec-moderate at a stretch.

Flags: needinfo?(tom)

Have you become a bit tired of me reporting similar vulnerabilities every time? I apologize ;(

Not yet :-)

When I was looking into bug 1882364 this morning I found the same chunk of code Nika flagged in comment 3, confirming my suspicion these are different symptoms of the same bug. But it's also possible we would have fixed just one of these on its own with a narrower fix that didn't address the others if we didn't know about them all.

Status: UNCONFIRMED → NEW
Ever confirmed: true
See Also: → CVE-2024-9398

Hi Valentin, are you or your team the right person to confirm comment 3? Perhaps Networking is a better component for this issue?

Flags: needinfo?(valentin.gosu)
See Also: → 680300, 1626068

I had not been reporting sec-low because it is sec-moderate, but by timing this image, it is possible to leak local files from the HTML files of Bug 1882827 and Bug 1884580. You just need to specify the file scheme instead of a custom scheme.

(In reply to Hsin-Yi Tsai (she/her) [:hsinyi] from comment #6)

Hi Valentin, are you or your team the right person to confirm comment 3? Perhaps Networking is a better component for this issue?

Hi Hsin-Yi, not sure if this is a pure Networking bug. There's a bit of overlap with other components.
If there's no one else who can work on this we can take it, though I'm not able to access many of the bugs referenced here.

Flags: needinfo?(valentin.gosu)
Severity: -- → S2

(In reply to Valentin Gosu [:valentin] (he/him) from comment #8)

If there's no one else who can work on this we can take it, though I'm not able to access many of the bugs referenced here.

I went ahead and CC'ed you on all of them (hopefully) in case that helps.

Component: DOM: Events → Networking
Priority: -- → P2
Whiteboard: [reporter-external] [client-bounty-form] [verif?] → [reporter-external] [client-bounty-form] [verif?][necko-triaged][necko-priority-queue]

(In reply to Nika Layzell [:nika] (ni? for response) from comment #3)

This might be as simple as removing the check to avoid creating the channel if the protocol handler doesn't exist (https://searchfox.org/mozilla-central/rev/6b0b8c1003504e302e243c300355ef4d61e24909/uriloader/exthandler/nsExternalProtocolHandler.cpp#523-529), and then instead making the channel fail to open in that case, by switching the debug check in OpenURL to a runtime check which sets rv = NS_ERROR_UNKNOWN_PROTOCOL and goto finish;-es (https://searchfox.org/mozilla-central/rev/6b0b8c1003504e302e243c300355ef4d61e24909/uriloader/exthandler/nsExternalProtocolHandler.cpp#152-161).
Could be interesting to confirm if this timing change would disappear with this change.

Excellent suggestion. I can confirm that the above changes make the timing issues disappear - at least on Linux. Will test with other platforms next.

Not sure what other impacts this change might have (we may have some places where we're relying on the exception happening when the channel is created rather than when the channel is opened?).

As far as I can tell, nsOSHelperAppService::LoadUriInternal was removed, so this comment no longer applies.
Also, I can't find any places that rely on .newChannel throwing NS_ERROR_UNKNOWN_PROTOCOL for security checks.

Assignee: nobody → valentin.gosu
Status: NEW → ASSIGNED

(In reply to Valentin Gosu [:valentin] (he/him) from comment #10)

(In reply to Nika Layzell [:nika] (ni? for response) from comment #3)

Not sure what other impacts this change might have (we may have some places where we're relying on the exception happening when the channel is created rather than when the channel is opened?).

As far as I can tell, nsOSHelperAppService::LoadUriInternal was removed, so this comment no longer applies.
Also, I can't find any places that rely on .newChannel throwing NS_ERROR_UNKNOWN_PROTOCOL for security checks.

https://searchfox.org/mozilla-central/rev/f63ca2952da98e0817bdae0ddf1314281a497106/devtools/shared/DevToolsUtils.js#781-799

I'm kind of wondering about landing this kind of change in a separate public bug as a refactoring. I expect some test failures / fallout. AIUI the impact on timing and this bug is somewhat indirect so perhaps that would simplify some things?

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

(In reply to Valentin Gosu [:valentin] (he/him) from comment #10)

Also, I can't find any places that rely on .newChannel throwing NS_ERROR_UNKNOWN_PROTOCOL for security checks.

https://searchfox.org/mozilla-central/rev/f63ca2952da98e0817bdae0ddf1314281a497106/devtools/shared/DevToolsUtils.js#781-799

Good catch! Not sure what the approach to take with this here is then, as this would definitely break in that case. I suppose we could manually check nsIExternalProtocolService from the JS code to check if the handler exists. It'd be a bit of a pain. Probably something like this after the uri is parsed (untested):

let handler = Services.io.getProtocolHandler(uri.scheme);
if (handler instanceof Ci.nsIExternalProtocolHandler &&
    !handler.externalAppExistsForScheme(uri.scheme)) { // Unrelated note: I'm not sure why the scheme needs to be provided here?
  uri = Services.io.newURI("file://" + url);
}

This would also remove the need to do the recursive calls in that function, I believe. I imagine this check is useful because of windows using C:\ drive names, which might parse as a c: external protocol? :valentin did you run into any xpcshell failures on windows after the changes?

This doesn't fix any other cases which we might not have caught which depend on it though, and the fact :gijs found one means there are somewhat likely to be others.

I'm kind of wondering about landing this kind of change in a separate public bug as a refactoring. I expect some test failures / fallout. AIUI the impact on timing and this bug is somewhat indirect so perhaps that would simplify some things?

Yeah, this could probably be done on a public bug as a refactoring fairly easily.

Pushed by valentin.gosu@gmail.com: https://hg.mozilla.org/integration/autoland/rev/1a96a3723839 Remove early return in nsExternalProtocolHandler::NewChannel when handler doesn't exist r=nika https://hg.mozilla.org/integration/autoland/rev/5b0d6bb6f378 Fix devtools expectation that newChannel throws for unsupported external handlers r=nika,devtools-reviewers,ochameau
Backout by ncsoregi@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/3b921c0cbf1b Backed out 2 changesets for causing bustage on nsExternalProtocolHandler.cpp. CLOSED TREE

Backed out for causing bustage on nsExternalProtocolHandler.cpp:

Push with failures
Failure log

uriloader/exthandler/nsExternalProtocolHandler.cpp:151:18: error: use of undeclared identifier 'MakeScopeExit'; did you mean 'mozilla::MakeScopeExit'?

Flags: needinfo?(valentin.gosu)
Pushed by valentin.gosu@gmail.com: https://hg.mozilla.org/integration/autoland/rev/8958ecbeec9e Remove early return in nsExternalProtocolHandler::NewChannel when handler doesn't exist r=nika https://hg.mozilla.org/integration/autoland/rev/56770cf9b51a Fix devtools expectation that newChannel throws for unsupported external handlers r=nika,devtools-reviewers,ochameau
Flags: needinfo?(valentin.gosu)
Pushed by valentin.gosu@gmail.com: https://hg.mozilla.org/integration/autoland/rev/4e8e200c3599 Remove early return in nsExternalProtocolHandler::NewChannel when handler doesn't exist r=nika https://hg.mozilla.org/integration/autoland/rev/4f9f5e9c42f8 Fix devtools expectation that newChannel throws for unsupported external handlers r=nika,devtools-reviewers,ochameau
Backout by smolnar@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/3946c6ee99c9 Backed out 2 changesets for causing xpc failures @ test_fetch-file.js CLOSED TREE

Push with failures
Failure log

[task 2024-05-01T00:20:00.497Z] 00:20:00  WARNING -  TEST-UNEXPECTED-FAIL | devtools/shared/tests/xpcshell/test_fetch-file.js | xpcshell return code: 0
[task 2024-05-01T00:20:00.499Z] 00:20:00     INFO -  TEST-INFO took 447ms
[task 2024-05-01T00:20:00.499Z] 00:20:00     INFO -  >>>>>>>
[task 2024-05-01T00:20:00.500Z] 00:20:00     INFO -  PID 4124 | DLL blocklist was unable to intercept AppInit DLLs.
[task 2024-05-01T00:20:00.500Z] 00:20:00     INFO -  PID 4124 | [Parent 4124, Main Thread] WARNING: Failed to get directory to cache.: file /builds/worker/checkouts/gecko/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp:148
[task 2024-05-01T00:20:00.501Z] 00:20:00     INFO -  PID 4124 | [Parent 4124, Main Thread] WARNING: Failed to get directory to cache.: file /builds/worker/checkouts/gecko/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp:148
[task 2024-05-01T00:20:00.502Z] 00:20:00     INFO -  PID 4124 | [Parent 4124, Main Thread] WARNING: Couldn't get the user appdata directory. Crash events may not be produced.: file /builds/worker/checkouts/gecko/toolkit/crashreporter/nsExceptionHandler.cpp:2924
[task 2024-05-01T00:20:00.502Z] 00:20:00     INFO -  (xpcshell/head.js) | test MAIN run_test pending (1)
[task 2024-05-01T00:20:00.502Z] 00:20:00     INFO -  (xpcshell/head.js) | test run_next_test 0 pending (2)
[task 2024-05-01T00:20:00.503Z] 00:20:00     INFO -  (xpcshell/head.js) | test MAIN run_test finished (2)
[task 2024-05-01T00:20:00.503Z] 00:20:00     INFO -  running event loop
[task 2024-05-01T00:20:00.503Z] 00:20:00     INFO -  devtools/shared/tests/xpcshell/test_fetch-file.js | Starting test_arrow_urls
[task 2024-05-01T00:20:00.503Z] 00:20:00     INFO -  (xpcshell/head.js) | test test_arrow_urls pending (2)
[task 2024-05-01T00:20:00.503Z] 00:20:00     INFO -  (xpcshell/head.js) | test run_next_test 0 finished (2)
[task 2024-05-01T00:20:00.504Z] 00:20:00     INFO -  PID 4124 | [Parent 4124, Main Thread] WARNING: Couldn't get the user appdata directory, crash dumps will go in an unusual location: file /builds/worker/checkouts/gecko/toolkit/crashreporter/nsExceptionHandler.cpp:2982
[task 2024-05-01T00:20:00.505Z] 00:20:00     INFO -  PID 4124 | [Parent 4124, Main Thread] WARNING: Couldn't get the user appdata directory. Crash events may not be produced.: file /builds/worker/checkouts/gecko/toolkit/crashreporter/nsExceptionHandler.cpp:2924
[task 2024-05-01T00:20:00.505Z] 00:20:00     INFO -  TEST-PASS | devtools/shared/tests/xpcshell/test_fetch-file.js | test_arrow_urls - [test_arrow_urls : 31] The file contents were correctly read. - "ad" deepEqual "ad"
[task 2024-05-01T00:20:00.505Z] 00:20:00     INFO -  (xpcshell/head.js) | test run_next_test 1 pending (2)
[task 2024-05-01T00:20:00.506Z] 00:20:00     INFO -  (xpcshell/head.js) | test test_arrow_urls finished (2)
[task 2024-05-01T00:20:00.506Z] 00:20:00     INFO -  devtools/shared/tests/xpcshell/test_fetch-file.js | Starting test_empty
[task 2024-05-01T00:20:00.506Z] 00:20:00     INFO -  (xpcshell/head.js) | test test_empty pending (2)
[task 2024-05-01T00:20:00.506Z] 00:20:00     INFO -  (xpcshell/head.js) | test run_next_test 1 finished (2)
[task 2024-05-01T00:20:00.507Z] 00:20:00     INFO -  TEST-PASS | devtools/shared/tests/xpcshell/test_fetch-file.js | test_empty - [test_empty : 40] The empty file was read correctly. - "" deepEqual ""
[task 2024-05-01T00:20:00.507Z] 00:20:00     INFO -  (xpcshell/head.js) | test run_next_test 2 pending (2)
[task 2024-05-01T00:20:00.507Z] 00:20:00     INFO -  (xpcshell/head.js) | test test_empty finished (2)
[task 2024-05-01T00:20:00.507Z] 00:20:00     INFO -  devtools/shared/tests/xpcshell/test_fetch-file.js | Starting test_encoding_utf8
[task 2024-05-01T00:20:00.508Z] 00:20:00     INFO -  (xpcshell/head.js) | test test_encoding_utf8 pending (2)
[task 2024-05-01T00:20:00.508Z] 00:20:00     INFO -  (xpcshell/head.js) | test run_next_test 2 finished (2)
[task 2024-05-01T00:20:00.508Z] 00:20:00     INFO -  PID 4124 | DLL blocklist was unable to intercept AppInit DLLs.
[task 2024-05-01T00:20:00.509Z] 00:20:00     INFO -  PID 4124 | JavaScript error: resource://gre/modules/ExtHandlerService.sys.mjs, line 57: NS_ERROR_FAILURE: Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsIProperties.get]
[task 2024-05-01T00:20:00.510Z] 00:20:00     INFO -  PID 4124 | [Parent 4124, Main Thread] WARNING: NS_ENSURE_SUCCESS(rv, rv) failed with result 0x805E0006 (NS_ERROR_CONTENT_BLOCKED): file /builds/worker/checkouts/gecko/dom/security/nsContentSecurityManager.cpp:1456
[task 2024-05-01T00:20:00.510Z] 00:20:00     INFO -  Unexpected exception NS_ERROR_CONTENT_BLOCKED: Failed to open input source 'c:\\Users\\task_171451964454847\\AppData\\Local\\Temp\\test_fetch-file-0.042017455803060044'
[task 2024-05-01T00:20:00.510Z] 00:20:00     INFO -  mainThreadFetch/<@resource://devtools/shared/DevToolsUtils.js:719:15
[task 2024-05-01T00:20:00.511Z] 00:20:00     INFO -  mainThreadFetch@resource://devtools/shared/DevToolsUtils.js:566:10
[task 2024-05-01T00:20:00.511Z] 00:20:00     INFO -  test_encoding_utf8@D:/task_171451964454847/build/tests/xpcshell/tests/devtools/shared/tests/xpcshell/test_fetch-file.js:50:43
[task 2024-05-01T00:20:00.511Z] 00:20:00     INFO -  _do_main@D:\task_171451964454847\build\tests\xpcshell\head.js:245:6
[task 2024-05-01T00:20:00.512Z] 00:20:00     INFO -  _execute_test@D:\task_171451964454847\build\tests\xpcshell\head.js:596:5
[task 2024-05-01T00:20:00.512Z] 00:20:00     INFO -  @-e:1:1
[task 2024-05-01T00:20:00.512Z] 00:20:00     INFO -  exiting test
Flags: needinfo?(valentin.gosu)
Flags: needinfo?(valentin.gosu)
Pushed by valentin.gosu@gmail.com: https://hg.mozilla.org/integration/autoland/rev/d25baafab824 Remove early return in nsExternalProtocolHandler::NewChannel when handler doesn't exist r=nika https://hg.mozilla.org/integration/autoland/rev/a887767c0627 Fix devtools expectation that newChannel throws for unsupported external handlers r=nika,devtools-reviewers,ochameau
Flags: sec-bounty? → sec-bounty+
QA Whiteboard: [post-critsmash-triage]
Flags: qe-verify-
Duplicate of this bug: 1882364

Please request ESR uplift on this when you get a chance.

Flags: needinfo?(valentin.gosu)
Attachment #9403466 - Flags: approval-mozilla-esr115?
Attachment #9403467 - Flags: approval-mozilla-esr115?

esr115 Uplift Approval Request

  • User impact if declined: privacy leak of OS application handlers.
  • Code covered by automated testing: no
  • Fix verified in Nightly: yes
  • Needs manual QE test: yes
  • Steps to reproduce for manual QE testing: see bug 1883693 comment 0
  • Risk associated with taking this patch: Slight risk of test breakage.
  • Explanation of risk level: Most of the externalProtocolHandler code hasn't changed since 115, but it's possible some of the affected tests have.
  • String changes made/needed: None
  • Is Android affected?: yes
Flags: qe-verify- → qe-verify+
Flags: needinfo?(valentin.gosu)
QA Whiteboard: [post-critsmash-triage] → [post-critsmash-triage] [qa-triaged]

Reproduce the leak using an old Nightly build from 2024-03-04, I have lots of exposed handlers as Exist such as (ftp, mailto, skype, slack, steam, tel, whatsapp, zoommtg) and the Threshold is around 503ms on Windows 11 and different values for Ubuntu 22.04 (VM) (1454ms) and macOS 13.6 (350ms).
Verified that using latest Nightly 128 from today (2024-05-23), I have every handler from the attached poc file as Does not exist and the Threshold is severally decreased on Windows 11 (30ms), Ubuntu 22.04 (VM) (132ms) / Ubuntu 22.04 PC (230ms) and macOS 13.6 (66ms).

I did ran into a weird thing on the Ubuntu 22.04 VM that I have. After I load the poc file a few times, sometimes a few handlers are displayed as Exist from time to time and not the same handler (basically randomly). This did not happen on Ubuntu 22.04 installed on a PC. Could this be something influenced by the testcase itself or is there any reason for concern?

Flags: needinfo?(valentin.gosu)

(In reply to Bogdan Maris, Desktop QA from comment #32)

I did ran into a weird thing on the Ubuntu 22.04 VM that I have. After I load the poc file a few times, sometimes a few handlers are displayed as Exist from time to time and not the same handler (basically randomly). This did not happen on Ubuntu 22.04 installed on a PC. Could this be something influenced by the testcase itself or is there any reason for concern?

The code is probably running slower on the VM and it's randomly exceeding the limit.
I think this should be OK. @Nika, do you think this requires more investigation?

Flags: needinfo?(valentin.gosu) → needinfo?(nika)

Yeah, it seems likely based on the other numbers associated with that VM that the machine is running slower, and being given less reliable scheduling, which could lead to random longer gaps. I don't think there's much more worth investigating there.

Flags: needinfo?(nika)

Thanks for your feedback, I'm going to close this as verified fixed for 127 since I also checked with Firefox 127.0b5 and I get similar results as with Latest Nightly. I'll leave the qe-verify+ flag on so I can verify on ESR when the fix lands there.

Attachment #9403466 - Flags: approval-mozilla-esr115? → approval-mozilla-esr115+
Attachment #9403467 - Flags: approval-mozilla-esr115? → approval-mozilla-esr115+
Attachment #9403466 - Flags: approval-mozilla-esr115+ → approval-mozilla-esr115-
Attachment #9403466 - Flags: approval-mozilla-esr115- → approval-mozilla-esr115+
Whiteboard: [reporter-external] [client-bounty-form] [verif?][necko-triaged][necko-priority-queue] → [reporter-external] [client-bounty-form] [verif?][necko-triaged][necko-priority-queue][adv-main127+]
Whiteboard: [reporter-external] [client-bounty-form] [verif?][necko-triaged][necko-priority-queue][adv-main127+] → [reporter-external] [client-bounty-form] [verif?][necko-triaged][necko-priority-queue][adv-main127+][adv-esr115.12+]

(In reply to Bogdan Maris, Desktop QA from comment #35)

Thanks for your feedback, I'm going to close this as verified fixed for 127 since I also checked with Firefox 127.0b5 and I get similar results as with Latest Nightly. I'll leave the qe-verify+ flag on so I can verify on ESR when the fix lands there.

Also verified fixed on 115.12.0esr across platforms (Windows 11, macOS 13.6 and Ubuntu 22.04).

Status: RESOLVED → VERIFIED
Flags: qe-verify+
Alias: CVE-2024-5690
Group: core-security-release
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: