Closed mmndaniel closed 1 year ago
related: bypass with multiple arguments to doc.write
var f = document.createElement('iframe');
document.body.appendChild(f);
f.contentDocument.write('<iframe id="tst', '"></iframe><script>tst.contentWindow.alert(1);</script>');
wow, mental.
Given there is https://github.com/LavaMoat/snow/blob/48ec98b16b2d91c4f2535d78ae0597bb7e636201/src/inserters.js#L33 to deal with .innerHTML
, could the same be applied here by hooking into contentDocument.write
?
Basically this snippet fixes it and maybe can be generalized.
var f = document.createElement('iframe');
document.body.appendChild(f);
fix(f) // should be done by patched `.appendChild`
f.contentDocument.write('<iframe id="tst');
f.contentDocument.write('"></iframe><script>tst.contentWindow.alert(1);</script>');
function fix (f) {
var old_write = f.contentDocument.write
var content = ''
const parser = document.createElement('div')
f.contentDocument.write = patched_write
function patched_write (...args) {
content += args.join('')
parser.innerHTML = content
const iframes = [...parser.querySelectorAll('iframe')]
if (iframes.length) {
f.contentDocument.close()
iframes.forEach(iframe => {
var [s1, s2] = [
`console.log('apply snow to iframe')`,
`tst.contentWindow.alert = (...args) => console.log(...args)`
].map(s => Object.assign(document.createElement('script'), { textContent: `${s}` }))
iframe.before(s1)
iframe.after(s2)
})
console.log('fuck')
console.log(parser.children)
old_write.apply(f.contentDocument, [parser.innerHTML])
} else {
old_write.apply(f.contentDocument, args)
}
}
}
@serapath yes, something like that, the main points are that args
should be joined
(to address this), and buffered (to address the OP). I'd say the optimal parser for this case would be another document (new DOMParser().parseFromString('...', 'text/html'
) with the same readyState and content as the target document, because if reflects the actual resulting DOM the best. To illustrate my latest point:
var doc1 = new DOMParser().parseFromString('<html><head><body><frameset><frame src="/" /></frameset></body></head><html>', 'text/html');
var doc2 = new DOMParser().parseFromString('<html><frameset><frame src="/" /></frameset><html>', 'text/html');
// compare doc1 and 2
I found it the hard way when an attempted fix broke a similar test...
Sorry to ruin the party guys, but with the help of #118 we might not need to dig too deep into this (thanks for the help!)
What happens is that
document.write
calls are buffered, buthandleHTML
sees only one chunk at a time so it won't find anything inside thetemplate
.