The following pages and parameters were vulnerable to XSS:
[Insert URLs and parameters]
Stored XSS is particularly pernicious for a number of reasons. For one, stored XSS doesn’t require a victim to click on a link as is necessary with reflected XSS. Simply loading a page on an exploited website is enough to trigger the attack. In addition, the attack is not targeted at any one user but at all users that load the infected page. As a result, an attacker can potentially exploit a large number of users based on the amount of traffic the page receives. Lastly, this attack is not time-dependent. It is possible that the payload could be days or months after the original attack depending on how long the page contents are left unmodified.
Likelihood – Medium
Impact – High
Overall Risk – High
To ensure that stored user input is not executed by the browser, the application should output encode user data into HTML entities. This ensures that the browser will only display user input and not interpret it as a command. At a minimum, output encode the following characters:
- “<” = “<”
- “>” = “>”
- “&” = “&”
- “/” = “/”
- single quote = “'”
- double quote = “"”
It is advisable to utilize a standard library for output encoding. There are libraries available for most platforms, including the OWASP Enterprise Security API (ESAPI).
How To Test
- Configure Burp Suite as a proxy and configure a browser to use it.
- Identify requests that contain user input.
- In Burp under the Proxy tab ->HTTP history, right click on these requests and send them to Scanner. Under Options in Scanner, make sure Stored XSS is checked.
- Identify requests that store user input in the database such as user comments.
- For each parameter in a form, insert a unique string such as “pizza”.
- If the field is returned, try an actual XSS payload such as ‘><svg/onload=alert(‘field 1’)>.
- If the string is not returned or is encoded, begin testing filter evasion techniques as indicated in the Reflected XSS finding.
Sample Report Screenshots
Time Saving Tips
When submitting strings in stored parameters, give each string a unique name (instead of alert(0)) so if the string appears in another part of the application, you’ll know where it came from. Appending a string to the name of the parameter is how we approach it..
In some cases, a parameter on a form might be vulnerable to stored cross site scripting, but you may never know because you don’t have access to the output. An example might be an admin page that shows log files. Unless you have the admin account, you might not know the page is vulnerable. Sometimes this is referred to as blind or out-of-band XSS. One way to test is to use Burp Collaborator to generate a payload that will make a call out to the Burp Collaborator server when fired. Burp Collaborator will even indicate if a DNS lookup has occurred indicating that the server attempted to resolved the domain. In other cases, the payload might not fire for days or weeks depending on how often the page is loaded. In this case, it is helpful to use a service such as XSS Hunter, which will give you a subdomain to use as part of your payload and then email you if the payload is triggered at some point in the future.
Want access to the full AppSec Findings Database? Click here to subscribe today.
Have a thought or question? Leave a comment below.