4

ok. I am dealing with a Classic ASP app written on VBScript. I am trying to filter possible XSS that might come via encoded Query string.

I have a simple XSS elimination function in place [getUserInput]. This looks for special charactors like < > / ' .... and replaces them with blank space. That works pretty well.

But, when I input something that is encoded via Server.URLEncode (VBScript) or escape (Javascript), obviously my above filter does not work.

I want to know the recommended solutions that are in place to prevent this Unicode converted input that makes my page vulnerable to XSS.

Repro steps:

<%
Response.Write getUserInput(Request("txt1")) + "<br/>"
Response.Write Server.URLEncode(getUserInput(Request("txt1"))) + "<br/>"
'the below line is where I am trying to decode and echo the input
Response.Write URLDecode2((getUserInput(Request("txt1")))) + "<br/>"
Response.Write "<br/>"
%>

<html>
Try any of the below two encoded strings in the input box and hit the button. </br></br>
alert('hi') </br>
%3Cscript%3Ealert%28%27hi%27%29%3C%2Fscript%3E  <br/>
alert(document.cookie) </br>
%3Cscript%3Ealert%28document.cookie%29%3C%2Fscript%3E <br/> 
</br>
<form method="get" name="form1" id="form1" action="#" onSubmit="CallOnLoad()">
    <input type='text' name='txt1' id='txt1' />
    <button name='btn' type='submit' id='btn'>Hitme</button>
</form>
</html>

<%
function getUserInput(input)

dim newString
newString=input  
newString    = replace(newString,"--","")
newString    = replace(newString,";","")          
  newString    = replace(newString,chr(34),"'") 
  newString    = replace(newString,"'","") 
  newString    = replace(newString,"=","=") 
  newString    = replace(newString,"(","[") 
  newString    = replace(newString,")","]")
  newString = replace(newString,"'","''")
  newString = replace(newString,"<","[")
  newString = replace(newString,">","]")  
  newString = replace(newString,"/*","/") 
  newString = replace(newString,"*/","/")
  getUserInput = newString

end function
%>
<%
'URLDecode2 - source code from http://www.motobit.com/tips/detpg_URLDecode/ 
Function URLDecode2(ByVal What)

  Dim Pos, pPos
  What = Replace(What, "+", " ")
  on error resume Next
  Dim Stream: Set Stream = CreateObject("ADODB.Stream")
  If err = 0 Then 
    on error goto 0
    Stream.Type = 2 'String
    Stream.Open
    Pos = InStr(1, What, "%")
    pPos = 1
    Do While Pos > 0
      Stream.WriteText Mid(What, pPos, Pos - pPos) + _
        Chr(CLng("&H" & Mid(What, Pos + 1, 2)))
      pPos = Pos + 3
      Pos = InStr(pPos, What, "%")
    Loop
    Stream.WriteText Mid(What, pPos)
    Stream.Position = 0
    URLDecode2 = Stream.ReadText
    Stream.Close
  Else 'URL decode using string concentation
    on error goto 0
    Pos = InStr(1, What, "%")
    Do While Pos>0 
      What = Left(What, Pos-1) + _
        Chr(Clng("&H" & Mid(What, Pos+1, 2))) + _
        Mid(What, Pos+3)
      Pos = InStr(Pos+1, What, "%")
    Loop
    URLDecode2 = What
  End If
End Function
%>

I am required to host the app on IIS 7.5/Win 2008 R2. Simple/elegant advices please?

How To: Prevent Cross-Site Scripting in ASP.NET is a good article, but it does not quiet to my scenario as I am dealing with Classic ASP.

Thanks.

PhilPursglove
  • 12,511
  • 5
  • 46
  • 68
gmaran23
  • 2,118
  • 2
  • 17
  • 18

3 Answers3

8

I am trying to filter possible XSS

This is largely a waste of time.

This breed of XSS is an output-stage issue, caused by inserting data into HTML without HTML-escaping it.

Despite the many efforts of deeply misguided “anti-XSS” tools and function, this problem simply cannot be handled by filtering at the input phase. At input time it is not known where data will end up, which data will need to be HTML-escaped (as opposed to injected into other text contexts like SQL or JavaScript), and what processing will be done to that data before it ends up on the page—in your example's case you're demonstrating this with URL-decoding, but it could be anything.

To correct problems caused by < and &, you need to remember to call Server.HTMLEncode on every string you inject into your output page, so that they'll be converted into &lt; and &amp; respectively. This is safe and will also allow users to use any character at will without some of them disappearing. (Imagine trying to post this message to SO with all the <s removed!)

That way you don't need to worry about encoded versions of <, because by the time you come to put them on the page you will have decoded them, and can apply the correct form of encoding, namely HTML-escaping.

This is not really anything to do with Unicode. Non-ASCII characters can be included in a page without any issues; it is only <, &, and in attribute values the quote character being used as a delimiter, that present any danger when injected into HTML.

There used to be a problem with over-long UTF-8 sequences, where a < could be smuggled in an invalid sequence of top-bit-set bytes that would get through HTML-encoding unchanged. Then IE (and Opera) would treat it as a real <. Whilst it's still a good idea to filter overlongs if you are working with UTF-8 in a language that has native byte strings rather than Unicode, it's not the necessity it once was as all current major browsers treat overlongs correctly, as non-functional invalid sequences.

Using correct HTML-escaping, your example might look like this (omitted the unchanged URLDecode2 function):

<p>
    <%= Server.HTMLEncode( Request("txt1") ) %> <br/>
    <%= Server.HTMLEncode( URLDecode2(Request("txt1")) ) %>
</p>
<p>
    Try any of the below two encoded strings in the input box and hit the button.
</p>
<ul>
    <li>&lt;script>alert('hi')&lt;/script></li>
    <li>%3Cscript%3Ealert%28%27hi%27%29%3C%2Fscript%3E</li>
    <li>&lt;script>alert(document.cookie)&lt;/script></li>
    <li>%3Cscript%3Ealert%28document.cookie%29%3C%2Fscript%3E<li>
</ul>
<form method="get" action="this.asp">
    <input type="text" name="txt1" value="<%= Server.HTMLEncode( Request("txt1") ) %>"/>
    <input type="submit" value="Hitme"/>
</form>

(In ASP.NET 4.0 there is a handy <%: shortcut to do <%= Server.HTMLEncode for you; unfortunately not so in Classic ASP.)

bobince
  • 528,062
  • 107
  • 651
  • 834
  • Beautiful! explanation with clarity:) The example that I was trying to demonstrate is referring to the output-stage issue I agree. I should have chosen a better repro. But actually, my aim is to filter script tags from the query string input (if someone tries an injection via the query string) where I am not worried about the output-stage, but the processing that I do once I receive the input. And thanks for the neat sample:) way better formatted than mine. – gmaran23 Sep 29 '11 at 20:32
  • 1
    Why filter the string `" – bobince Sep 29 '11 at 20:49
  • makes sense! – gmaran23 Sep 30 '11 at 05:12
  • Make sure you use the correct escaping based on context. For html attribute the escaping is actually different than between tag. See https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet. – Erlend Sep 30 '11 at 10:17
  • The only tags that have different escaping rules for text content in HTML (and then, only HTML not XHTML) are the CDATA elements: ` – bobince Sep 30 '11 at 10:44
1

When you have strings to parse in your xml builder asp. You could create it like so:

<description><![CDATA[ "& descriptionString &"]]></description>

You could use a HTML stripping function to strip out unneeded html or escaping html tags:

Function stripHTML(strHTML)
Dim objRegExp, strOutput
Set objRegExp = New RegExp
    with objRegExp
        .Pattern = "<(.|\n)+?>"
        .IgnoreCase = True
        .Global = True
    end with

'Replace all HTML tag matches with the empty string
strOutput = objRegExp.Replace(strHTML, "")
Set objRegExp = Nothing

'Replace all < and > with &lt; and &gt;
strOutput = Replace(strOutput, "<", "&lt;")
strOutput = Replace(strOutput, ">", "&gt;")
stripHTML = strOutput   
 'Return the value of strOutput
End Function

Another one for preventing SQL injection. Parse for example requests.querystrings to it from Form get/post.

function SQLInject(strWords)
 dim badChars, newChars, tmpChars, regEx, i
 badChars = array( _
 "select(.*)(from|with|by){1}", "insert(.*)(into|values){1}", "update(.*)set", "delete(.*)(from|with){1}", _
"drop(.*)(from|aggre|role|assem|key|cert|cont|credential|data|endpoint|event|f ulltext|function|index|login|type|schema|procedure|que|remote|role|route|sign| stat|syno|table|trigger|user|view|xml){1}", _
"alter(.*)(application|assem|key|author|cert|credential|data|endpoint|fulltext |function|index|login|type|schema|procedure|que|remote|role|route|serv|table|u ser|view|xml){1}", _
"xp_", "sp_", "restore\s", "grant\s", "revoke\s", _
"dbcc", "dump", "use\s", "set\s", "truncate\s", "backup\s", _
"load\s", "save\s", "shutdown", "cast(.*)\(", "convert(.*)\(", "execute\s", _
"updatetext", "writetext", "reconfigure", _
"/\*", "\*/", ";", "\-\-", "\[", "\]", "char(.*)\(", "nchar(.*)\(")  

 newChars = strWords
 for i = 0 to uBound(badChars)
     Set regEx = New RegExp
     regEx.Pattern = badChars(i)
     regEx.IgnoreCase = True
     regEx.Global = True
     newChars = regEx.Replace(newChars, "")
     Set regEx = nothing
 next
 newChars = replace(newChars, "'", "''")
 SqlInject = newChars
end function
Plippie
  • 2,836
  • 33
  • 28
1

You should use Unescape.

Function getUserInput(input)
dim newString
'***********************
newString=Unescape(input)
'***********************
newString    = replace(newString,"--","")
'etc ...
'etc ...
'etc ...
End Function
Kul-Tigin
  • 16,728
  • 1
  • 35
  • 64
  • hmm. Thats pretty neat. I did not know that Unescape existed in VBscript. I guess I am not gonna need the URLDecode2 function anyway. So, I am gonna try this solution. This appears neat and advisable to me unless someone'e gotta disagree with that. – gmaran23 Sep 29 '11 at 19:38
  • You're welcome. Additionally, I'd recommend you to read Mike's answer. – Kul-Tigin Sep 29 '11 at 19:47
  • Mike's answer? or bobince's answer? – gmaran23 Sep 29 '11 at 19:54