Self-XSS (Self Cross Site Scripting) attacks involve injecting JS code into a web page, just like any other XSS attack. The major difference is that this vulnerability can only be exploited when the user itself inputs a XSS payload in the page, making it almost impossible for an attacker to trigger it without the user consent. As a result, many bug bounty programs do not offer rewards to those who find these kind of vulnerabilities, since it alone does not pose a security threat to its users.
However, it is still important to refer it when we talk about XSS attacks, and therefore I will provide an example of a vulnerable web application.
You can download the vulnerable app using the following buttons:
To run it you can simply run docker compose up
Once the app is up and running, we can access http://localhost:8080 to visit it:
If we input something in the input field and click the button, we can see that the text below the title changes accordingly.
If we check its source we get this:
We can see the button has an onclick
attribute that refers do_something()
, but where is this function defined?
When we visit the location of the last script
tag (http://localhost:8080/static/main.js), we can see this same function:
We can see that it gets the value of the input field and then proceeds to set the innerHTML
property of the description element to it.
The problem here is that assigning the innerHTML
property to a value controlled by the user poses a security risk since this property allows you to add new HTML tags as children of the target element.
For example, let's try inputting <input/>
in the text area.
You can see that the element was rendered.
However, since our purpose is XSS, we want to inject a new JS script into this page.
So, our payload can use a script
tag to achieve this. Let's try to create an alert with the text "You were hacked":
However, our script does not get executed even though we can see it was added to the page...
This is due to the fact that when you append scripts to a page they don't get automatically executed.
However, there are some ways to circunvent this, such as creating an img
tag instead and using the onerror
attribute to execute your desired JS script:
Looks like our Self-XSS attack succeeded!
Sometimes, you might be interested in leaking the user cookies, specially the authentication/session ones as they can be enough for you to gain control over the user account.
Fortunately, to access the cookies stored in the browser you can access the document.cookie
property.
For example, let's try the alert method again but with the cookie as its value.
We can see that we succeeded in printing the user cookies.
However, just printing them won't matter most of the times. We need a way to send this cookies back to the attacker.
To achieve this, we can send the cookies to a web server controlled by us. There are some simple websites for this purpose like https://requestcatcher.com.
Let's modify our payload to send a request to our requestcatcher site, with the cookie in it.
For this example, I'll pass the cookie in the body of a POST request:
And we can see we got a request with the cookie in it!
I hope you now have a better understanding of Self-XSS attacks.
Table of Contents