Cross Site Scripting (XSS)
Stored XSS vs Reflected XSS vs DOM XSS
Not all XSS vulnerabilities behave the same as some XSS behaviors may be limited to the user that placed the code initially and some XSS behaviors may be stored on a page for other users to visit. Stored XSS is when code is able to be stored on a web page where users can navigate to the page (or load it by some other means like an iframe) and the code will always be executed. This is arguably one of the most dangerous forms of XSS as it is impossible to detect without reading the page (and possibly executing the code).
Reflected XSS is very similar to Stored XSS in that it allows an attacker to execute code on the client side via a web application. However, Reflected XSS involves having the victim send a malformed request on behalf of the attacker. A common method for doing this is to send a shortened URL that resolves to a URL with a vulnerable parameter. This method allows for code execution, but it can be much more targeted that a Stored XSS can be.
DOM XSS takes advantage of the DOM model and can manipulate objects on the page during its execution. A common misconception is that DOM is another form of XSS, when in fact it is a modifier to Stored and Reflected XSS. This means that an attacker could perform Stored XSS or Stored DOM XSS in which they simply execute code on the client or they execute code which modifies the page layout itself via DOM.
The next attack is a demonstration of fingerprinting using XSS. This time, the attacker adds an image tag with a source pointing to their IP address. The image doesn’t have to actually exist on the host, it just matters that the victim’s browser attempts to call out to the attacker’s machine. In doing so, the victim’s browser will send the normal GET preample of their User-Agent, Referrer, and more. This is shown below when the victim’s browser attempts to connect to the attacker. Their User-Agent (A string identifying their browser), their Referrer (What page they came from) and more information is displayed to the attacker. This information can then be used to find out where the user came from, what browser (and version) they are using and even their language.
From the victim’s point of view, the web page just appears to be stuck loading some random resource in the background. A more advanced attack could even force the connection to close right after a request was made. This would make the attack virtually invisible to the average user.
Reflected XSS works very similarly to Stored XSS with the exception that it is trigger by a malformed request. The victim is tricked into opening a link that will execute a malicious script to leak information such as cookies, browser version, and more.
Below shows the victim’s point of view as they receive the malicious link and are convinced to open it. The payload executes successfully and sends the attacker everything they need.
Input Sanitation is the most common and one of the most effective XSS prevention methods. It involves escaping any characters that would normally mess with the setup of the page or allow for code execution on the page. Characters like this are ‘<‘, ‘>’, ‘;’, ‘&’, and more. HTML has special codes for each of these characters that allows them to be rendered exactly as they appear without the possibility of them altering the web page. Those character escapes are ‘%lt;’, ‘%gt;’, ‘%semi;’, and ‘%amp;’.
Whitelisting and Blacklisting are also effective sanitiation methods. Whitelisting only allows strings through that contain certain characters and Blacklisting forbids strings that contain certain characters. While both can be very effective if used properly, they should never be used exclusively. An example of a poor Blacklist is shown below:
- Can not use ‘<‘
- Can not use ‘script’
- Can not use ‘alert’
While at first glance this appears to cut out a lot of the alert XSS test, it can be bypassed by taking advantage of URL encoded characters and case-insensitivity as shown below:
When designing a web application, user data should never be fed into tags that execute something like as <script> and <style> and they should never be find into an attribute where a user could break an attribute such as <!– –> or <div. Allowing a user to input data into any of these locations, especially if unescaped, can allow the user to break out of the tag by closing it at the beginning and re-opening it at the end such as <!– VAR –> == <!– ‘–><script>alert(‘hi’);</script><!–‘ –>. CSS style tags in particular allow an attacker to perform a “CSS Injection” which we will go into more detail about later.
Web Application Firewalls (WAF)
Web Application Firewalls offer many features for protecting your Web Applications such as XSS prevention, Brute force preventing, and in some cases DDoS prevention. WAFs can specifically be used to combat XSS by scanning requests sent to the server such as that executed of a Reflected XSS or the submission of a Stored XSS and blocking anything that appears dangerous. It should be noted that a WAF is not the end all of XSS and additional security measures such as smart programming practices should be used to have a more secure landscape.
Bypassing a WAF is mostly just feeling out where the WAF fails to sanitize inputs that it is given. Assuming no ridiculous ban time between failed requests, a WAF can be poked and prodded with various XSS bypass methods such as escaped characters, use of concatenated variables, and more. For more information WAF bypass check out SecJuice’s article on WAF bypass.
Content Security Policy
Content Security Policy can be used to enforce code execution from the page’s origin and any additionally whitelisted locations at the discretion of the developer. This allows a developer to have a much tighter grip over where code can be pulled from to be executed on the client’s side. Although this will not help if the whitelisted location ever becomes compromised as an attacker could host their scripts from there and slip through. Though at that point, you have much bigger problems to worry about than XSS.
Common bypasses for Content Security Policy (CSP) generally involve forcing data to be received or sent from a trusted source such as a JSON endpoint or a static upload domain. If the XSS is able to be triggered and it calls out to these trusted domains then CSP can be completely bypassed.
The X-XSS-Protection header can be enabled and forced into server responses by the server. This header will tell the browser to scrub request responses for XSS before they have a chance to reach the client. There are three options for this header: X-XSS-Protection: 0, X-XSS-Protection: 1, and X-XSS-Protection: 1; mode=block. The first completely disabled the XSS protection. The second is the default value a browser will use so long as the config has not been modified. It will block resources that appear to be loaded via XSS (this is prone to false positives). The last one will completely block the page if anything appears fishy about it. Unfortunately, these can all have their own individual issues. The first is an open door if an XSS vulnerability exists, the second can block legitimate libraries or even contribute to things like Referrer leakage, and the final can be used to dance around Browser XSS prevention as there is no “Did XSS auditor block it? Better check the console.” as the page will simply fail to load if something was detected. The final option also contains the same issues as the second. Additionally, the XSS Browser protection (at least for Chrome) is only effective against Reflected XSS and not Stored or Stored DOM XSS. This is confirmed by a Chromium developer with the quote “XSS auditor is only effective against reflective XSS, so the payload must be part of the URL or the POST body”.
XSS gets a lot of heat for being a “low-risk” vulnerability. It only affects clients and the server is generally safe in this situation. While it does only extend to clients, that should not be the only reason to force it to a low-risk. As shown above, XSS can have a lot of impact on not only the user experience, but their private data as well. XSS can be used to find out information about the victim’s browser and their session. This information could be used to steal cookies and impersonate admins, launch targeted exploits against their browser, or even completely re-write the page to phish login information with DOM XSS. Server administrators generally care about much more serious exploits such as SQLi, RCE, LFI/RFI, and more. While those are terrible exploits that can lead to a lot of problems, XSS should be blocked with just as much disdain from as many angles as possible.
As for the attacker’s point of view, XSS can show up in some of the most unlikely of places. Text forms are an obvious first choice, but User-Agent and Referrer header readouts in routers can be just as damaging. Always think about how every piece of information attached to your session is being fed into the server. Is there anywhere that could possibly show up to an admin that you can’t see (Blind XSS)? Remember that the server might be implementing one of the security features shown above so treading lightly is the key. Hacking is the art of curiosity and exploration so be sure to do so responsibly.