XSS

Misc tips

Url encoding

Javascript goodies

 

XSS – Cross Site Scripting

 

Lets create a simple html file a.html in c:\ with the following contents.

 

<html>

<form>

alert('hi')

</form>

</html>

 

Even though alert is the first javascript function that we all know, html does not recognize it as such and displays it as a label. We see alert as text in our browser. Lets now teach our browser to understand javascript code.

 

<html>

<form>

<script>alert('hi')</script>

</form>

</html>

 

Anything that we write within the tags <script> and </script> is executed as javascript code. Thus we now see a message box. IE is very picky and if we remove the / from the script, we do not see a message box nor do we see the text alert. Neither here nor there. If we change the function name from alert to alert1 we get an error message box asking us if we want to debug our application.

 

<html>

<form>

&lt;script>alert('hi')</script>

</form>

</html>

 

<script>alert('hi')

 

The escape the < character we use the symbols &lt;. Thus in the browser window we see the <script but it does not get executed as javascript code. IE does a multiple pass though our code. It first checks for the tags <script> </script>. It will finds these tags it executes what lies within as javascript code. This gets done first as javascript code can and does produce html which is merged with the rest of the html code. Then the html code gets rendered. As we have no script tags, our alert does not get executed as javascript. In the next round &lt; gets converted to the less than sign.

 

The ending </script> is there in the view source but does not displayed as  IE does not find a starting <script> tag. Thus we need to escape both < characters to make them look like non tags.

 

<html>

<form>

&lt;script>alert('hi')&lt;/script>

</form>

</html>

 

<script>alert('hi')</script>

 

<html>

<form>

<script>

document.write("<b>Vijay</b>");

</script>

</form>

</html>

 

Vijay

 

The write function in the document object is what we use to write html in place of javascript code. This is how javascript creates dynamic html pages. We see Vijay in bold.

 

<%@ language="C#"  %>

<html>

<script language="C#" runat="server">

void abc(Object o, EventArgs e)

{

l.Text = t.Text;

}

</script>

<form runat="server" >

<asp:TextBox id="t" runat="server" />

<asp:label id="l" runat="server" />

<asp:Button Text="Click" runat="server" OnClick="abc" />

</form>

</html>

 

In the above aspx file we have a text box and a label and button. We write some text in the text box  and  then click on the button which calls the abc function. Here we simply set the value of the label field to whatever we wrote in the text box. Pretty innocuous code you say. This is the ideal program for exploiting XSS.

 

In the text box we first write Vijay Mukhi and the label becomes Vijay Mukhi and the button shifts to the right. We then write the following text and click on the button.

 

<script>alert(‘hi’)</script>

 

We are surprised we see an error page that says that the request is potentially dangerous. Thus ASP.Net 2.0 is a very smart cookie which traps a XSS exploits. This is why we always recommend using the latest version of software so that we do not have to write code ourselves. The system handles it for us.

 

There may be cases where we would not like the system to do these checks for us. We ourselves do not know why you should disable the checks, but the option is there for you to do so.

 

<%@ language="C#" validateRequest="false" %>

 

By default the attribute validateRequest is true and as we set it to false we get no error on the above input. We see the alert or message box and then the button gets rendered. Once again keep defaults values for attributes like validateRequest, you can only get burned if you change it.

 

<%@ language="C#" validateRequest="false" %>

<html>

<script language="C#" runat="server">

void abc(Object o, EventArgs e)

{

l.Text = Server.HtmlEncode(t.Text);

}

 

<span id="l">&lt;script&gt;alert('hi1')&lt;/script&gt;</span>

 

At all times do not set the value of a control to input taken from the user. Always use the function HtmlEncode which convert the characters <>  into their & representation so that they are not executed as a script tag.  Thus we get the best of both worlds, we get the flexibility we want plus we also sanitize all input we get from the user. The span tag serves no useful purpose and evolution will some day take its toll.

 

a.aspx

<%@ language="C#" validaterequest="false" %>

<script language="C#" runat="server">

void Page_Load(object o,EventArgs e)

{

Response.Write(Request.QueryString["aa"]);

}

</script>

<form runat="server">

in a.aspx

</form>

 

b.html

<a href="a.aspx?aa=<script>alert('hi')</script>"> no </a>

 

The parameter aa in the hyperlink has java script code embedded in it. Thus the system gives us an error if we do not set the validate request off. We display the value of the field aa using the indexer QueryString and we see a Message Box. We are able to embed java script code anywhere. Normally we save values of form fields in a database or a log file. If we use a browser to read the log file, java script code can get executed where we least expect it. Thus anything send to the server by the browser must be thoroughly checked.

 

<form runat="server" AUTOCOMPLETE="OFF">

<asp:TextBox id="vijay" runat="server" />

<img src="javascript:alert('hi');">

<asp:button Text="Click" runat="server"/>

</form>

 

Javascript can be embedded anywhere and everywhere. Wherever an attribute requires a value, we can use java script code instead. If we replace the words javascript with mocha or livescript in IE nothing happens, try it with netscape and see the difference. Livescript was the original name for javascript.

 

<form runat="server" AUTOCOMPLETE="OFF">

<asp:TextBox id="vijay" runat="server" />

<img src="javascript:&#010;alert('hi');">

<asp:button Text="Click" runat="server"/>

</form>

 

The carriage return character is 10, the line feed is 13. Using &#010 we are embedding a enter in the code. We can write this anywhere and the system ignores enters in our code. We could also use the characters 9, 10, 11 12 and 13.

 

<img src="java&#X0a;script:alert('hi');">

 

We can use hex characters wherever we use decimal but need an extra X to specify hex. Thus we must check for hex encodings also.

 

<img src="java&#0000010;script:alert('hi');">

 

Padding with up to 4 zeroes also gives us the same result. One more zero and the message box does not show. Does not make sense to us.

 

<img src="java&#X00000a;script:alert('hi');">

For hex numbers also 4 zeroes work well.

 

<img src="javascript:&#065;lert('hi');">

 

What does not work is replacing the a with a 65. The view source shows us the actual characters we have typed out. This only goes to prove that the browser does not first convert all decimal entities to their ascii equivalents. Fortunately placing javascript code in a style tag after changing its mime type to text/javascript does not get the browser to execute it as javascript code.

 

<html>

<form runat="server" >

<style type="text/css">

@import url(javascript:alert('hi'));

</style>

<asp:button Text="Click" runat="server"/>

</form>

</html>

 

What we are going to show you is a zillion different places where we can place javascript code. Cascading style sheets and the style tag are used to give a consistent look and feel to our web page. The whole idea is that we do not have to specify formatting tags for each and every control individually, write it once and let every control pick it up from the style. We change the mime type of the style to text/css and then use the @import feature of the css not to bring in the file but execute javascript code.

 

 

<%@ language="C#" %>

<script language="C#" runat="server">

void abc(object o,EventArgs e)

{

Regex r = new Regex("^[A-Za-z0-9]{10,16}$");

bool b = r.IsMatch(t.Text);

Response.Write("isMatch returns " + b);

}

</script>

<form runat="server">

<asp:TextBox runat="server" id="t" />

<asp:button Text="Click" runat="server" onClick="abc" />

</form>

 

The .net world gives us the Regex class that understands regular expressions like the Unix world does. The [] brackets let us specify a range, A-Z stands for all capital letter, the curly braces {} let us repeats the last pattern a certain number of times. {10,16} allows us to use from 10 to 16 of the previous pattern. ^ means start of text, $ means end of text. This is why we have to key in from 10 to 16 caps, small or digits.

 

It is the IsMatch function that really checks the text that we have keyed in matches the regular expression or not. A value of true means it does, false means a failure, the text contains invalid characters. All input taken from the user must be checked for sanity or else trouble is looming for the web application. As mom said trust no one.

 

Random Tips

 

Use the Http fields send to us from the browser for error checks.

a.html

<a href="a.aspx"> hi </a>

 

b.html

<a href="a.aspx"> no </a>

 

a.aspx

<%@ language="C#" %>

<script language="C#" runat="server">

void Page_Load(object o,EventArgs e)

{

if ( Request.ServerVariables["HTTP_REFERER"] == "http://localhost/b.html")

Response.Write("Allowed");

else

Response.Write("Not Allowed");

 

}

</script>

<form runat="server">

in a.aspx

</form>

 

We create two html files a.html and b.html that simply allow us to click on a hyper link that takes us to a.aspx. Here in the function Page_Load we check for the field Http_referrer which tells us which url send us. ServerVariables is an Indexer that contains all the fields set by the browser. We use this wherever we know that a user can only come to this page say from a login page and not from any other page. Thus if the page that send us to a.aspx is not b.html, in Page_Load we can redirect the user to some other page.

 

This technique is useful whenever we want the user to follow an order of how he can navigate though our pages.

 

a.aspx

 <form runat="server" >

<asp:TextBox id="vijay" runat="server" />

<asp:button Text="Click" runat="server"/>

</form>

 

The problem with today’s browsers are that they remember everything. Thus each time we type something into a text box called Vijay, the next time we press the down arrow on that text box we will see a list of items we have typed. We run a.aspx and type Vijay in the text box and click on the button. We close the browser and start another copy and call a.aspx. We now type Mukhi and click on the button. We once again close the browser and start a new copy and navigate to a.aspx. Here we choose the text box and click on the down arrow and see Vijay and Mukhi. This gets dangerous as people can see what we have typed at the text box in the past.

 

<form runat="server" AUTOCOMPLETE="OFF">

<asp:TextBox id="vijay" runat="server" />

<asp:button Text="Click" runat="server"/>

</form>

 

We use the AUTOCOMPLETE attribute at the form level and set it to off so that for all the fields in the form our browser will not now remember the values we have keyed in. We can place the attribute for each field also. Thus it may make a users life easier if he does not have to key in the data for a field, but if multiple people use the same computer or we are using the form from a public machine, there could be issues of information leakage.

 

 

Url Encoding

 

Lets write the following URL in our browser

 

http://localhost/ab.html

 

The browser sends out a GET request to the server as GET /ab.html. As there are lots of ways of skinning a cat, there are lots of  ways of writing out a url.

 

Another way of evading an Ids is as follows

 

http://localhost/././././ab.html

 

A dot stands for the current directory and hence this url is identical to the above

 

http://localhost/aaa/../ab.html

 

Here we first move down into a directory aaa and from there we move up one back to where we are. The directory aaa does not have to be present on the server. This is how we can bypass a ids that is not smart.

 

http://localhost/aa/../asdf/hyuj/../../ab.html

 

The above url once again gives us ab.html and we can use a combination of . and .. as many times as we like. We must bear in mind that most smart security products today catch such simple url’s.

 

http://localhost/%41b.html

 

This gives us the same file ab.html. Hex characters are prefaced with a % sign and 41 is hex for decimal 65 the ASCII code for the letter A. Thus the GET request now changes and hence any self respecting IdS will first convert the hex digits to ASCII and then check the pattern. The latest version of snort does so.

 

http://localhost/%2541b.html

 

For some reason double hex coding does not work. The %25 hex becomes a % but the 41 does not become %41 and thus a A.

 

http://localhost/.%c0%afab.html

 

The characters %c0%af stands for a slash and hence the above url reads /ab.html. IDS’s also convert Unicode characters to ASCII. You can use Unicode characters instead of ASCII to obfuscate the path.

 

http://localhost/.//ab.html

 

Whenever a browser sees two slashes it converts it into a single slash. Another check for a IDS.

 

http://localhost/.////////////////////////ab.html

 

What applies to two applies to a zillion slashes, we never said decoding a url is simple.

 

 

http://localhost/.\\\\\\\\\\\\\\\\\ab.html

 

We yet cannot figure out whether to use a slash or a backslash to separate directories and files. Thus we are allowed to use both.

 

http://localhost/.\\\\\\////////////////ab.html

 

in any permutations and combinations.

 

http://localhost/ab.html%00vijay

 

Most code under windows is written in C where a 0 or null byte indicates end of string. Thus whatever we write after the 0 is not considered as part of the url. We would advice you to see the server logs at C:\winnt\system32\logfiles\w3svc1. Here there is no Vijay anywhere in the url.

 

 

http://localhost%co%afab.html

 

The slash in Unicode is %c0%af whereas in ascii it is %2f.

 

Javascript goodies

 

Ip.shtnl

<script language="javascript">

var ip = '<!--#echo var="REMOTE_ADDR"-->'

document.write(ip);

</script>

 

The little script uses SSL to display the users current ip address. All that we do is extract the value of the variable REMOTE_ADDR and display it.

 

We could have written the above code as

 

<script language="javascript">

document.write('<!--#echo var="REMOTE_ADDR"-->');

</script>