Clickjacking
Table of Contents
Guide 04 in Sarah’s Welcome to Web Security Series #
In this series, Sarah discusses some common vulnerability classes found in web security and how you can find and exploit them. Today’s focus is clickjacking, a technically simple, yet effective, vulnerability.
Introduction #
In the previous guide, we looked at how CSRF vulnerabilities can induce a user to perform unintended actions by visiting a malicious webpage. Clickjacking (sometimes called ‘UI redressing’) is similar in that it causes a user to do something unexpected but it requires the user to interact with a malicious web page, rather than just looking at it. Essentially, the attacker loads some webpage that has a sensitive action, for example, a bank page that lets you transfer money . Then, they create a decoy website which is overlaid on top of the original page, which is now obscured. When the user clicks on a button on the decoy page (E.g. “Claim your prize!”), they actually end up clicking on some button on the original page (E.g. “Transfer my money!”) which triggers the unintended action. It is not a technically difficult attack, though it can require patience to craft a perfect decoy website. However, the more complicated clickjacking attacks are combined with other vulnerabilities, such as DOM XSS to have more dangerous consequences.
When Can Clickjacking Be Used? #
In short, whenever a website can be completely framed, it is vulnerable to clickjacking. For those who do not know what a frame is, it is essentially a part of a web page which can have content which is independent of its contained (i.e. the rest of the web page). It’s not particularly good practice to use frames, particularly in cases where the website can perform sensitive actions. However, it does make some things (such as constructing a navigation bar) simpler and it can also allow for more segregated items on a web page (e.g. information that can be scrolled independently of each other).
Crafting a Clickjacking Payload #
Creating a clickjacking payload is as simple as piecing together a HTML page.1 It tends to only get more complicated if the attacker wishes to create a very nice looking site, has to bypass some simple defences (though even this can be quite trivial) and/or wants to include other vulnerabilities. As an example, here is a web page from one of PortSwigger’s labs. In this example, we want to include a simple XSS payload in our clickjacking attack so that when the user clicks the ‘Submit feedback’ button, they also call the print()
function.
To do this, we need to create a ‘decoy website’, which acts as a mask over this website. If we keep it simple, all we need to do is create a page with a button (in this case, it’s just a fake button made of a div
element) that sits right on top of the real button, then place the real website in a transparent iframe. Here’s my version of a simple decoy page:
<style>
iframe {
position:relative;
width: 1920px;
height: 850px;
opacity: 0.0001;
z-index: 2;
}
div {
position:absolute;
top: 830px;
left: 410px;
z-index: 1;
}
</style>
<div>Click me</div>
<iframe
src="https://my-lab-id.web-security-academy.net/feedback?name=<img src=1
onerror=print()>&email=vice-pres@monsec.com&subject=MonSec&message=MonSec is awesome.#feedbackResult">
</iframe>
As you can see, the majority of the code is spent on styling, making the iframe transparent and positioning the button correctly. At the very bottom, we have the iframe which holds the original website, as well as our XSS payload (<img src=1 onerror=print()>
) and the details needed for the form. If I increase the opacity of the original site so it can be seen, here’s what it looks like:
It looks ugly, but it’ll do the job. With the original site completely transparent:
And that’s about it. If you wanted to, you could make your decoy look a lot better or add additional features (such as iframe sandbox="allow-forms"
which can bypass simple frame-busting scripts). Some clickjacking attacks even require multiple decoy pages. Nevertheless, once you have crafted a suitable decoy page, it is simply a matter of getting the user onto the fake page and then getting them to click on the button. In our case, when the user clicks our fake button, it will trigger the XSS payload and call print()
.
Defending Against Clickjacking #
As clickjacking is such a simple attack, it is not surprising that its defences are also fairly easy to implement. OWASP has a cheat sheet for it, though there are only three main defences and they all revolve around preventing the website from being framed.
The first and foremost defence should be to prevent a browser from loading the page in a frame by using the X-Frame-Options
or Content Security Policy (frame-ancestors)
headers. Note that the former takes priority so it should be the preferred defence. Furthermore, much like with other vulnerabilities, a content security policy is only as good as it is properly configured, so make sure you consult the correct documentation.2 After that, the SameSite cookies attribute can be used to prevent session cookies from being loaded into frames which can prevent the user from performing sensitive actions. Finally, a JavaScript script can be written to try and stop the page from being loaded into a frame. Such scripts are called ‘frame-busters’ and their success largely depends on the quality of the code, as it can be easily circumvented if written poorly.
Conclusion #
Though clickjacking is not a particularly impressive-looking nor technically brilliant vulnerability, it is still one worth knowing as sometimes it is the simplest of things that are overlooked. When combined with other vulnerabilities, it can be a potent attack vector, though modern practices surrounding web design (for websites that have sensitive actions) and framing generally make it harder to successfully execute.
Credit to PortSwigger’s WebSecurity Academy for the images. If you are interested in learning more about clickjacking and web security, the WebSecurity Academy is a fantastic resource. You can create a free account and explore their labs here.