I’ve always heard of XSS by name, but I had never come across it until I worked on my portfolio last week. Here’s what the Vue.js debugger warned me about :
That’s when I started looking into this kind of attack, understanding how it works, and eventually trying it out.
I. what ?
Cross-Site Scripting (XSS) is one of, if not the most common security vulnerabilities along with SQL Injection and MITM.
It consists of injecting your own code into any poorly secured website, leading to data theft, session hijacking, defacement of websites and even distribution of malware.
II. why ?
Here are some common factors that can make a website susceptible to XSS attacks :
Lack of Input Validation and Sanitization
-
Directly Embedding User Input : If your website takes user input and directly embeds it into HTML, JavaScript, or other parts of the web page without proper validation or sanitization, it can be exploited.
-
Examples : Comment sections, search fields, contact forms …
Improper Output Encoding
-
Failure to Encode Output : Not encoding output correctly before rendering it in the browser can lead to XSS vulnerabilities.
-
Examples : Displaying user-submitted content without HTML entity encoding or using innerHTML to insert user data into the DOM without proper sanitization.
Weak CSP
-
Weak or No CSP : Content Security Policy (CSP) helps mitigate XSS by restricting the sources from which scripts can be loaded and executed. An absent or poorly configured CSP can leave your site vulnerable.
-
Example : Make sure all your website comes from trusted sources :
Content-Security-Policy: default-src 'self' *.safe-source.example.net
this rule will ensure all content is provided by the site itself or by subdomains of safe-source.example.net.
III. how ?
To demonstrate simple XSS attacks, I’ll use the WebGoat project which is an intentionally insecure web app that allows you to test vulnerabilities.
I recommend using a virtual machine to run it and carefully reading the documentation beforehand.
The easiest way to run the program is to pull its Docker image using this command :
docker pull webgoat/webgoat
then expose the app on your 8080 port (you might need sudo for both of these commands) :
docker run -p 127.0.0.1:8080:8080 -p 127.0.0.1:9090:9090 -e TZ=Europe/Amsterdam webgoat/webgoat
If everything went well, you can now visualize the website on localhost:8080/WebGoat.
Register yourself as a new user then head to the third page of the Cross Site Scripting (stored) section.
See that comment text field down there ? That’s where the magic is gonna happen.
As you can see, my comment appears harmless but actually loads a small script. While this script is not dangerous for the moment, it demonstrates that the text field lacks proper sanitization and allows us to run our own code into the website.
Since my comment is stored in database, the script will be loaded each time for every browser that accesses this page.
Here’s a simple way to make it more malicious (simple website defacement) :
Result :
This issue might be disturbing and humiliating for the website owner, but this is actually quite easy to fix and no harm has been caused to users.
However XSS attacks can lead to data theft which is a much more significant problem.
I’ll show you how this works using the BeEF project. The BeEF (Browser Exploitation Framework) project is an open-source penetration testing tool that focuses on web browsers. It allows to assess the security posture of a website by using client-side attack vectors.
Disclosure : Please be aware that while the BeEF framework is a powerful tool for understanding and demonstrating the impact of browser vulnerabilities, it must be used responsibly and legally. Exploiting vulnerabilities without permission is illegal and unethical. This demonstration is for educational purposes only, and any misuse of this information is strictly prohibited.
Once you’ve downloaded or cloned the project, you must run the following scripts from the root directory:
./install
./beef
NB : it might ask you to change your credentials before launching BeEF, default credentials are both “beef”.
In this menu, look for any Hook URL then copy it. A hook in the BeEF Framework is a piece of JavaScript code that is used to collect data and perform actions in the victim’s browser. I will now inject this hook in every browser accessing the page we pwned before.
As you can see the hook got correctly loaded into the website :
Now back to the BeEF terminal menu, copy the UI URL linked to the chosen hook
and paste it into your browser to access the attacker panel after entering the credentials you set up previously.
This interface shows all the hooked machines along with their information. For example, here you can see the browser of my Ubuntu VM.
In the “commands” tab, among many other actions you can choose which page will replace the hooked one. In my case I chose a generic login form that could trick unexperienced users.
Here’s what the hooked comment section looks like on the victim’s browser :
When the user submits their input, you can view the captured data in the attacker panel.
If your website stores sensitive information about your users, these credential leaks could be a disaster.
IV. conclusion.
Never Trust User Inputs. That’s it.