Closed Bug 1309630 (CVE-2022-22755) Opened 8 years ago Closed 3 years ago

Code execution after tab and window close.

Categories

(Core :: XSLT, defect, P3)

49 Branch
defect

Tracking

()

VERIFIED FIXED
97 Branch
Tracking Status
firefox-esr91 - wontfix
firefox60 --- wontfix
firefox95 --- wontfix
firefox96 --- wontfix
firefox97 + verified
firefox98 --- verified

People

(Reporter: me, Assigned: peterv)

References

(Regressed 1 open bug)

Details

(Keywords: reporter-external, sec-moderate, Whiteboard: [post-critsmash-triage][adv-main97+])

Attachments

(7 files, 3 obsolete files)

Attached file Minimal Test Case
STEPS TO REPRODUCE:
  1 Download 'exploit.xsl' (a minimal testcase of the bug).
  2 Run `python -m SimpleHTTPServer 8080` in a terminal.
  3 Navigate to 'http://localhost:8080/exploit.xsl'.
  4 Check the output of the server started in Step 2.
  5 Open another tab.
  6 Close the 'exploit.xsl' tab.
  7 Check the output of the server started in Step 2.
  8 Close the browser window. Grab lunch.
  9 Check the output of the server started in Step 2.

EXPECTED BEHAVIOR:
  - At Step 4, the server IS reporting incoming GET requests.
  - At Step 7, the server is NOT reporting incoming GET requests.
  - At Step 9, the server is NOT reporting incoming GET requests.

ACTUAL BEHAVIOR:
  - At Step 4, the server IS reporting incoming GET requests.
  - At Step 7, the server IS reporting incoming GET requests.
  - At Step 9, the server IS reporting incoming GET requests.

POSSIBLE EXPLOITATION
A. User Tracking
I've constructed a proof-of-concept user-tracking server that serves
each request a variant of 'exploit.xsl' which has been tagged with a 
unique identifying number. The server sleeps for several seconds before
responding to each incoming request, so as not to cause an undue amount
of network traffic. Upon each request, the server logs the time of the
heartbeat, the user ID, and their IP address. This leaks, roughly, the
user's possibly-changing location and their computer usage habits.

B. Theft of Computing Resources
This bug can be exploited to force the user's browser to perform general
computation after the user has left the page. The attached file does not
have a base-case to its recursive calls, but can be easily modified to
have one that forwards the result of the computation to the attacker.

C. Denial-of-Service Attacks
This attack can be used to generate a large volume of network trafic
from a user after they have left the page. Combined with an XSS attack,
Firefox users could be co-opted into bombarding a site long after they
have left the page.

OTHER OBSERVATIONS
  1 This bug is exploitable with javascript disabled (unsurprising from
    a technical perspective, but given the possible attacks, probably
    surprising from a user's perspective).
  2 If the firefox process ends and then is restarted with the session
    restored, the requests pick right up from where they left off.
  3 If the recursion reaches a base case after the window is closed,
    Firefox appears to do some DOM processing. This can be tested by
    modifying 'exploit.xslt' to output an HTML file containing,
      <link rel="prefetch" href="/test.png">
    upon reaching its base case. The server logs will display a request
    to 'test.png', even though the window was closed before processing
    the XSLT completed. It may be able to combine this bug with other
    bugs to produce other exploits at this point.
  4 The attacker can detect when the tab is closed since the pending 
    request is interrupted.
  5 The attacker may modify an in-progress computation by serving a
    different 'exploit.xsl?n=N' at a particular value of N. (I haven't
    explored this in much depth, yet.)
  6 This bug is exploitable with javascript disabled (unsurprising from
    a technical perspective, but given the possible attacks, probably
    surprising from a user's perspective).
Having trouble reproducing this, but some of these results would be alarming from a privacy POV if true. For instance "OTHER OBSERVATIONS" #2 seems really surprising given the way sessionrestore works.
Group: core-security → dom-core-security
Flags: needinfo?(peterv)
For the sake of testing, it's useful to set Firefox's cache size to zero, or clear the cache before navigating to 'exploit.xsl'. Otherwise, since 'exploit.xsl' is cached aggressively, the requests will not appear in the server log until the appended query parameter becomes sufficiently large as to not be in the cache already.
I've had the situation of observation #2 occur a few more times since filing the report (I notice because the server log suddenly explodes), but I haven't figured out the sequence of events that causes it to happen reliably, yet.

Having played around with this a bit more, I'm pretty sure that the appearance (from the server's perspective) that the "requests pick right up from where they left off" is because the requests up to that point have just been fetched from cache.
Hmm, we probably should add a request to the loadgroup to stop new loads if the loadgroup is canceled. Haven't been able to reproduce the session restore case yet.
Assignee: nobody → peterv
Flags: needinfo?(peterv)
I've attached two video demonstrations in which I open Firefox, navigate to 'exploit.xsl', kill the Firefox process, and then restart it. Immediately after the browser window opens, Firefox navigates to the previously open 'exploit.xsl' tabs. (It took a few tries between each video, however.)
Attached file javascript-after-tab-close.tar (obsolete) —
Using this bug and Gecko's XSLT/Javascript interface, I was able to execute javascript code in a tab after the window was closed.

Attached is a very hastily assembled demo server and video demonstrating the exploit.
I've attached a more coherent demonstration of executing javascript after the tab or window is closed. See 'demonstration.mp4' for a demonstration, or open Firefox to 'http://localhost:8000/' and execute 'cargo run' to play with the backdoor yourself. I've found it to be a very convenient way to test which web APIs are available after the tab is closed. I have also included the stdout and stderr of firefox during the video demonstration as 'firefox.log'.

I've had firefox eventually segfault a few times, too.

Can anyone at firefox confirm this bug? Is there any information I can include that would help?
Attachment #8801118 - Attachment is obsolete: true
Flags: sec-bounty?
Priority: -- → P3
Tyson, can you see if you can reproduce this PoC?
Flags: needinfo?(twsmith)
(In reply to Al Billings [:abillings] from comment #8)
> Tyson, can you see if you can reproduce this PoC?

I can reproduce the issue. I used the html page in the rust example combined with the original xsl file and served them using Python's SimpleHTTPServer.
Status: UNCONFIRMED → NEW
Ever confirmed: true
Flags: needinfo?(twsmith)
I am unable to reproduce the session restore version of the bug.
To be clear I followed the original steps to trigger the issue. Once the hidden script was running I opened one new fresh tab and closed all remaining tabs. The script was still pinging the test server. I called "killall firefox" to trigger session restore and reopened the browser. The "fresh tab" I previously opened was restored and the script was no longer pinging the server.
Closing the last tab when the hidden script is running keeps the browser alive even though it appears to be closed when e10s is disabled (this is not the case with e10s enabled)
I've attached a slightly different demonstration of the exploit being run across sessions.

If I get the exploit page into the profile's 'Top Sites' list, the exploit will run quietly in the background, without the browser actually showing that it's trying to load the page at all.

In the attached video, I create a blank profile, and then navigate to the exploit page twice. After the second navigation, the exploit page is placed in the 'Top Sites' list. I then:
 • Open the browser to no particular page at all; the exploit runs (1:54).
 • Open a new tab, close the old opened 'New Tab' page, and navigate to mozilla.org; the exploit is still running (~2:08).
 • Close the browser.
 • Open the browser directly to mozilla.org; the exploit runs (2:30).
 • Close the browser.
 • Open the browser directly to a private browsing window to no particular page at all; the exploit runs (2:50).
Attachment #8800828 - Attachment is obsolete: true
Andrew, can someone take a look at this issue? It's been sitting around for quite a bit.
Flags: needinfo?(overholt)
Attached patch v1 (obsolete) — Splinter Review
Need to add an automated testcase.
Flags: needinfo?(overholt)
Flags: sec-bounty? → sec-bounty+
Group: dom-core-security → core-security-release
Status: NEW → RESOLVED
Closed: 3 years ago
Resolution: --- → FIXED
Target Milestone: --- → 97 Branch
Flags: qe-verify+
Whiteboard: [post-critsmash-triage]

Verified as fixed on macOS 11.6, Windows 10 and on Ubuntu 20.04.

Status: RESOLVED → VERIFIED
Attachment #9017648 - Attachment is obsolete: true

Is this ready for an ESR approval request? Please nominate if yes.

Flags: needinfo?(peterv)

Per Slack discussion with Peter, better to let this one ride the trains.

Whiteboard: [post-critsmash-triage] → [post-critsmash-triage][adv-main97+]
Alias: CVE-2022-22755
Regressions: 1763179
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: