A topic typically forgotten when discussing XSS is the Same-Origin Policy (SOP). With SOP, browsers trust all code coming from the origin site. XSS attacks exploit this policy by tricking the browser into believing malicious code came from a trusted site. XSS exploits are primarily defined in literature as either client- or server-side attacks. From there, they are further sub-categorized into Persistent-, Reflected-, and DOM-based XSS attacks. The first two are server-side attacks whereas the latter is a client-side attack.
Treat this post as a step-by-step guide on identifying XSS vulnerabilities rather than a tool-tutorial. I plan to make a post on XSS tools in a later post.
TYPES OF XSS ATTACKS
Not all XSS attacks are created equally; therefore, to understand this vulnerability, it is meaningful to break it down into its three main categories, discussed below.
Unlike the Persistent and Non-Persistent XSS attacks, which exploits a vulnerable website by having the server insert a malicious script, the DOM-based XSS attack exploits a vulnerability in the client’s web browser, making it a truly client-side attack. Additionally, with Persistent/Non-Persistent XSS attacks, the payload is injected into the application during server-side processing of requests where untrusted input is dynamically added to HTML. But for DOM-based XSS, the attack is injected directly into the application during runtime in the client.
document.URL, document.documentURI, document.location, location.href, location.search, window.name, location.search, location.header, or document.referrer. XSS vulnerabilities can all be introduced through these sources.
document.getElementById(“Example”).innerHTML = “some random string” will retrieve all text content inside the “Example” ID of the DOM and overwrite the current HTML content within that ID. Now, imagine changing
"some random string" to a malicious
<script>. This is how the DOM-based XSS works.
DOM-based XSS attacks can be confusing, so here is a demonstration from Muscat (2014). The following HTML in the Figure below allows users to select a default language by using a query string.
If a user selected “German” as the default language, then the URL would like the following:
The execution Sink in this example is
Blind XSS (BXSS) – An Honorable Mention
The Blind XSS (BXSS) is a subcategory of the Persistent XSS attack whereby the attacker blindly targets web pages that store user input in a database, such as blogs, forums, comment boxes, contact forms, login forms, and message boards. Although the BXSS and the Persistent XSS attacks are fairly identical in terms of the end-goal and the stored payload, the distinction lies in the execution of the attack. In a BXSS attack, the attacker fires off payloads into vulnerable sites, but doing so manually is cumbersome. The process is instead automated using XSS security tools, such as XSS Hunter or the XSS Validator extension in Burp Suite. These tools automatically generate payloads and even correlates injection attempts.
TESTING FOR XSS VULNERABILITIES
To test for XSS vulnerabilities, web developers or testers must determine every area that the web application accepts user input and identify how this input is processed. This includes not-so-obvious inputs, such as HTTP requests, POST data, hidden form field values, and pre-defined radio or selection values. Testers can accomplish this task by crafting their own harmless input (e.g.,
<script>alert('XSS');</script>) and submitting them as input to the server. Otherwise, they can use application fuzzers to generate random or predefined lists of known attack strings. A common tool used to accomplish this task is Burp Suite and its XSS-Validator extension, powered by PhantomJS.
However, testing for XSS vulnerabilities in modern web applications should not be as easy as simply submitting
alert() code injection like the example above will most likely fail. To bypass these filters, testers need to get creative with their payloads by manipulating them in a way that they bypass filters. This typically involves using malformed
<img> tags, HTML entities, malformed
<a> tags, encoding, iframes, and so on. OWASP has an XSS Filter Evasion Cheat Sheet that reveals a comprehensive list of fancy tricks. Likewise, PortSwigger has its own XSS Filter Evasion Cheat Sheet that accomplishes the same purpose, albeit, a little more comprehensively.
Testers must also inspect the source of the page. In FireFox, for example, this can be done by simply right-clicking anywhere on the web page and clicking “Inspect Element” (shortcut = F12). This is important because when testing for possible XSS vulnerabilities in the URL, testers can see where the payload is reflecting in the DOM and which characters in the script are being sanitized. For instance, if the web page has a “Search” feature that allows users to search content throughout the web site via keywords or tags, a script (e.g.,
“/><script>alert(1)</script>) could be submitted through the search bar. After submission, testers should inspect the page code to see where this payload was reflected. If the payload fails, testers can check the code to see the reason why. For instance, if the script was modified from
"/><script>alert(1)</script> to “"/>alert(1)”, then the testers can identify HOW the script tags were sanitized. From there, the testers can resort to alternative evasion techniques.
Step 1 – Source Code Inspection:
It should be noted that the output of retire can be hard to read, but testers can use some of its available flags to rectify this. For example, the data can be outputted in json format using –outputformat json. The end product scans the client-side code of a web site and compiles a report in json format, which it can save to a json file and display to the tester. But to make sense of that json, testers can format it in a way that it pulls out the critical information (e.g., severity, description, and location) while leaving out the noise (e.g., dependency graphs). Testers can create a Python file that can be used for string manipulation and general data munging, to write a script that formats the json into a plain text report.
Fortunately, if set up is to laborious, FireFox includes a Retire.JS add-on that can be enabled in the browser. This option is much easie to set up and understand:
Step 2 – Automated Scanners:
It is not usually feasible to manually insert an XSS string into every injection point and determine if the payload executes or not. This takes too much time. Thus, leveraging a tool is the best approach; however, manual verification is still necessary if a vulnerability is discovered. Here are some tools that I use to locate XSS vulnerabilities:
Epsylon’s XSSer is an automatic -framework- to detect, exploit and report XSS vulnerabilities in web-based applications. It provides several options bypass certain filters and various special techniques for code injection. XSSer also includes pre-installed (>1300 XSS) attacking vectors and can bypass-exploit code on several browsers/WAFs.
S0md3v’s XSStrike is a detection suite equipped with four hand written parsers, an intelligent payload generator, a powerful fuzzing engine, and an incredibly fast crawler. Instead of injecting payloads and checking it works like all the other tools do, XSStrike analyses the response with multiple parsers and then crafts payloads that are guaranteed to work by context analysis integrated with a fuzzing engine. Here are some examples of the payloads generated by XSStrike. Apart from that, XSStrike has crawling, fuzzing, parameter discovery, WAF detection capabilities as well. It also scans for DOM XSS vulnerabilities, which is a feature that sets it apart from most XSS tools.
PortSwigger’s XSS-Validator, Powered by PhantomJS:
PortSwigger’s XSS-Validator Extension is a burp intruder extender designed for automation and validation of XSS vulnerabilities. XSS Validator is designed to forward responses to the XSS detection server, which must run both externally and simultaneously to the extender. The XSS detection server is powered by Phantom.js and/or Slimer.js. Instructions on how to set this up in Burp can be found on PortSwigger’s Github.
Step 3 – XSS Filter Bypass:
No modern web application is without XSS filters; therefore, expect user input to be sanitized wherever the application accepts data. Be sure to utilize tools that can encode payloads for obfuscation. If the tester has an idea of what the filter is performing, then try bypassing these filters using encoding or modifying payloads to break through the filter. Tip: XSStrike can actually help identify what the filters are blocking:
Step 4 – Consider File Upload Vulnerabilities:
From OWASP: Do not forget about file upload vulnerabilities. If the web application allows file upload, it is important to check if it is possible to upload HTML content. For instance, if HTML or TXT files are allowed, XSS payload can be injected in the file uploaded. The pen-tester should also verify if the file upload allows setting arbitrary MIME types in Burp Suite. This design flaw can be exploited in browser MIME mishandling attacks. For instance, innocuous-looking files like JPG and GIF can contain an XSS payload that is executed when they are loaded by the browser. This is possible when the MIME type for an image such as
image/gif can instead be set to
text/html. In this case the file is treated by the client browser as HTML.
Step 5 – Verification:
If a automated scanner finds an XSS vulnerability, be sure to manually verify it exists. Unfortunately, many automated scanners discover false positives instead of true positives.
More Bug Bounty Tips:
- Hackvector is great for obfuscating payloads.
- Ideally all HTML special characters will be replaced with HTML entities. The key HTML entities to identify are
(>, <, &, ’, ”, \n, \r, \, \uxxxx).
- When sites sanitize input by modifying it instead of encoding or escaping values, testers should continue testing the site’s server-side logic. Think about how a developer might have coded their solution and what assumptions they have made. For example, check whether the developer considered what happens if two
srcattributes are submitted or if spaces are replaced with slashes.
Borso, S. (2019). The Penetration Tester’s Guide to Web Applications. Artech House
Kim, P. (2015). The Hacker Playbook 2. Secure Planet, LLC
Kim, P. (2018). The Hacker Playbook 3. Secure Planet, LLC
Makarem, C. (2018). DOM-Based Cross Site Scripting (DOM-XSS). Medium. Retrieved from https://medium.com/iocscan/dom-based-cross-site-scripting-dom-xss-3396453364fd
Marshal, J. (2018). Hands-Om Bug Hunting for Penetration Testers. Packt Publishing
Muscat, I (2014). Finding the Source of a DOM-based XSS Vulnerability with Acunetix. Acutenix 2021. Retrieved from https://www.acunetix.com/blog/articles/finding-source-dom-based-xss-vulnerability-acunetix-wvs/
Velu, V. K. & Beggs, R. (2019). Mastering Kali Linux for Advanced Penetration Testing. Packt Publishing