Bypassing ValidateRequest
Back in August 2009 (https://jardinesoftware.net/2009/08/27/validaterequest-property-xss/) I wrote about the Validate Request functionality and how it doesn’t do a good job of protecting against Cross Site Scripting in an attribute context. In this post, I am going to explain another technique that can be used to bypass the Validate Request filter in an html element context. This technique uses a different character encoding to bypass the blacklist checks that are done.
To recap, the Validate Request returns false when the following conditions are met:
- <a-z - A < character followed by an alpha character.
- <!, </, <?
- &#
As you can see, the main goal is to trigger an error when the less than (<) character is passed followed by a specific set of characters. Since it blocks the start character for an HTML element, it makes it difficult to just add new elements to the page. So how do we get around this? Using Unicode-Wide characters, we can pass in a character that looks like the < character, but it really isn’t. That character is represented at the value %uff1c. If this value is passed to a varchar field in a SQL database, it will get converted to the real < character. I have not seen this work on a nvarchar field. If this value is than returned to the browser without proper encoding, cross site scripting is possible. Lets take a look at how this works from an example.
- Create an XSS payload for a susceptible field (<script>alert(9);</script>).
- Change the opening and closing signs to use unicode-wide representation (%uff1cscript%uff1ealert(9);%uff1c/script%uff1e)
- Submit the data to the server.
- The data is stored in a varchar field.
- Retrieve the data without any encoding.
- Cross Site Scripting ensues with an alert box with the value of 9.
I have only seen persistent cross site scripting work for this. I have not seen this work in a reflective manor.
This example shows how important output encoding is for remediating cross site scripting vulnerabilities. Input validation important, but not completely bullet proof. The only way to make sure the code is safe is during the output routine.