🤬
  • Added CVE-2022-22620 RCA

    Change-Id: I3733635bc06f6b50d51dff0c3a6b61c415258da1
  • Loading...
  • Maddie Stone committed 2 years ago
    e9d68dac
    1 parent f076bb0b
  • ■ ■ ■ ■ ■ ■
    0day-RCAs/2022/CVE-2022-22620.md
     1 +# CVE-2022-22620: Use-after-free in Safari
     2 +*Maddie Stone*
     3 + 
     4 +## The Basics
     5 + 
     6 +**Disclosure or Patch Date:** 10 February 2022
     7 + 
     8 +**Product:** Apple Safari/WebKit
     9 + 
     10 +**Advisory:** https://support.apple.com/en-us/HT213093
     11 + 
     12 +**Affected Versions:** Safari 15.3, iOS 15.3, macOS 12.2 and earlier
     13 + 
     14 +**First Patched Version:** Safari 15.3 (v. 16612.4.9.1.8 and 15612.4.9.1.8), iOS 15.3.1, macOS 12.2.1
     15 + 
     16 +**Issue/Bug Report:** https://bugs.webkit.org/show_bug.cgi?id=235551
     17 + 
     18 +**Patch CL:** https://github.com/WebKit/WebKit/commit/486816dc355c19f1de1b8056f85d0bbf7084dd6e
     19 + 
     20 +**Bug-Introducing CL:** https://github.com/WebKit/WebKit/commit/aa31b6b4d09b09acdf1cec11f2f7f35bd362dd0e
     21 + 
     22 +**Reporter(s):** Anonymous
     23 + 
     24 +## The Code
     25 + 
     26 +**Proof-of-concept:**
     27 + 
     28 +```javascript
     29 +input = document.body.appendChild(document.createElement("input"));
     30 + 
     31 +foo = document.body.appendChild(document.createElement("a"));
     32 +foo.id = "foo";
     33 + 
     34 +// Go to state1 when history.back is called
     35 +// The URL needs to be <currentPage+hash> to trigger loadInSameDocument during the call to back()
     36 +// Since the foo's element id="foo", focus will change to that element
     37 +history.pushState("state1", "", location + "#foo");
     38 + 
     39 +// Current state = state2
     40 +history.pushState("state2", "");
     41 + 
     42 +setTimeout(() => {
     43 + 
     44 + // Set the focus on the input element.
     45 + // During the call to back() the focus will change to the foo element
     46 + // and therefore triggering the blur event on the input element
     47 + input.focus();
     48 + input.onblur = () => history.replaceState("state3", "");
     49 + setTimeout(() => history.back(), 1000);
     50 +}, 1000);
     51 +````
     52 + 
     53 +**Exploit sample:** N/A
     54 + 
     55 +**Did you have access to the exploit sample when doing the analysis?** No
     56 + 
     57 +## The Vulnerability
     58 + 
     59 +**Bug class:** Use-after-free
     60 + 
     61 +**Vulnerability details:**
     62 + 
     63 +The History API allows access to (and modification of) a stack of the pages visited in the current frame, and these page states are stored as a `SerializedScriptValue`. The History API exposes a getter for `state`, and a method `replaceState` which allows overwriting the "most recent" history entry.
     64 + 
     65 +The bug is that `FrameLoader::loadInSameDocument` takes the `state` as an argument (`stateObject`), but doesn't increase its reference count. Only a `HistoryItem` object holds a reference to the `stateObject`. `loadInSameDocument` can trigger a callback into user JavaScript through the `onblur` event. The user's callback can call `replaceState` to replace the `HistoryItem`'s `state` with a new object, therefore dropping the only reference to the `stateObject`. When the callback returns, `loadInSameDocument` will still use this free'd object in its call to `statePopped`, leading to the use-after-free.
     66 + 
     67 +When `loadInSameDocument` is called it changes the focus to the element its scrolling to. If we set the focus on a different element prior to `loadInSameDocument` running, the [`blur` event](https://developer.mozilla.org/en-US/docs/Web/API/Element/blur_event) will be fired on that element. Then we can free the `stateObject` by calling `replaceState` in the `onblur` event handler.
     68 + 
     69 +**Patch analysis:**
     70 + 
     71 +The patch changes the `stateObject` argument to `loadInSameDocument` from a raw pointer, `SerializedScriptValue*`, to a reference-counted pointer, `RefPtr<SerializedScriptValue>`, so that `loadInSameDocument` now increments the reference count on the object.
     72 + 
     73 +**Thoughts on how this vuln might have been found _(fuzzing, code auditing, variant analysis, etc.)_:**
     74 + 
     75 +It seems reasonable that the vulnerability could have been found through watching the commits and seeing the initial fix from 2013 reverted in 2016, code auditing, or fuzzing. Fuzzing seems *slightly* less likely due to needing to support "navigation" which many fuzzers explicitly try to exclude.
     76 + 
     77 +**(Historical/present/future) context of bug:**
     78 + 
     79 +This bug was actually reported and initially fixed in 2013. In 2016 the fix was regressed during (it seems) refactoring. A full write-up is available [here](https://googleprojectzero.blogspot.com/2022/06/an-autopsy-on-zombie-in-wild-0-day.html).
     80 + 
     81 +## The Exploit
     82 + 
     83 +(The terms *exploit primitive*, *exploit strategy*, *exploit technique*, and *exploit flow* are [defined here](https://googleprojectzero.blogspot.com/2020/06/a-survey-of-recent-ios-kernel-exploits.html).)
     84 + 
     85 +**Exploit strategy (or strategies):** N/A, no access to exploit sample
     86 + 
     87 +**Exploit flow:**
     88 + 
     89 +**Known cases of the same exploit flow:**
     90 + 
     91 +**Part of an exploit chain?**
     92 + 
     93 +## The Next Steps
     94 + 
     95 +### Variant analysis
     96 + 
     97 +**Areas/approach for variant analysis (and why):**
     98 + 
     99 +* Look for any commits where a reference-counted pointer was changed to a raw pointer.
     100 +* Update fuzzer so that it could find this bug and therefore also hopefully provide coverage for other similar bugs too.
     101 + 
     102 +**Found variants:** N/A
     103 + 
     104 +### Structural improvements
     105 + 
     106 +What are structural improvements such as ways to kill the bug class, prevent the introduction of this vulnerability, mitigate the exploit flow, make this type of vulnerability harder to exploit, etc.?
     107 + 
     108 +**Ideas to kill the bug class:**
     109 + 
     110 +By default, arguments to functions should be reference-counted. Raw pointers should only be used in rare exceptions.
     111 + 
     112 +**Ideas to mitigate the exploit flow:** N/A
     113 + 
     114 +**Other potential improvements:**
     115 + 
     116 +* The bug was killed in 2013 and re-introduced in 2016. It seems that this likely occured due to the large issues affecting most software dev teams: legacy code, short reviewer turn-around expectations, refactoring and security efforts are generally under-appreciated and under-rewarded, and lack of memory safety mitigations. Steps towards any of these would likely make a difference.
     117 +* The two commits that reverted the 2013 fix were very, very large commits: 40 and 94 files changed. While some large commits may include exclusively no-ops, these commits included many changes affecting lifetime semantics. This seems like it would make it very difficult for any developer or reviewer to be able to truly audit and understand the security impacts of all the changes being made.
     118 + 
     119 +### 0-day detection methods
     120 + 
     121 +What are potential detection methods for similar 0-days? Meaning are there any ideas of how this exploit or similar exploits could be detected **as a 0-day**?
     122 + 
     123 +The code to trigger this vulnerability is pretty generic. I think any detection would have to be around exploitation method, which we couldn't analyze in this case since we didn't have access to the exploit sample.
     124 + 
     125 +## Other References
     126 + 
     127 +* ["An Autopsy on a Zombie In-the-Wild 0-day"](https://googleprojectzero.blogspot.com/2022/06/an-autopsy-on-zombie-in-wild-0-day.html) Project Zero blog post
Please wait...
Page is in error, reload to recover