How webservers react on specific characters

One thing I did during my Master Thesis a while ago, was to test how different webservers react to all kind of characters. One of the first things I tested was all characters represented by one byte (00 to FF) and their percent encoded equivalents (%00 to %FF). Of course the results may vary with other server versions, server configurations, server side code, client libraries or the sent HTTP headers. For example python’s urllib2 is not able to send 0A (line feed) in an URI (which makes sense). I tried to use standard components as best as I could. The webservers I used were:

  • An Apache 2.2.12 server (port 80), Ubuntu 9.10 machine with PHP 5.2.10
  • On the same machine a Tomcat 6.0.26 server (port 8080) with JSP (Java Server Pages)
  • On a Microsoft-IIS/6.0, Windows 2003 Server R2/SP2 with ASP.NET 2.0.50727 a script in C# on Virtualbox 3.1.8

So here are the main results in one picture:


The ‘Name’ column means that the character was injected into the parameter name, e.g. na%00me=value&a=b. The fields with ‘S’ are explained in another section of my Master Thesis, but some of the time you can guess the behavior. E.g. I think you know what & stands for in GET parameters, right? 😉

This kind of information is useful when you are trying to write a fuzzer, that is more focused to do some tests that make sense. Would be interesting if this table is useful for someone else.

Apache HTTP 0.9 compatible

When sending the ASCII control character null (hexadecimal 00) in the query string of an URI, IIS returns a 400 (Bad Request). Tomcat passes the null to the web application. But Apache returns a HTTP entity (the HTML code), but no HTTP headers. Additionally the URI is truncated (the null and everything after it is missing).

If you have a local apache running, try this python script (you need to have a index.html or index.php in your root directory):

import urllib2
print 'Valid request:'
print urllib2.urlopen('http://localhost/?abc=123&def=456_VALID').read()
print ''
print 'Invalid request:'
print urllib2.urlopen('http://localhost/?abc=123'+chr(0)+'&def=456_INVALID').read()

If you watch it with wireshark you will see that the answer to the second request has no HTTP headers. The apache access.log will look like this:

::1 - - [09/Jun/2010:16:44:41 +0200] "GET /?abc=123&def=456_VALID HTTP/1.1" 200 321 "-" "Python-urllib/2.6"
::1 - - [09/Jun/2010:16:44:41 +0200] "GET /?abc=123" 200 94 "-" "-"

Eric Covener of the apache project:

The null in the invalid URL causes the request line to be terminated before the rest of the URL or the protocol. The response (no headers) is “HTTP 0.9” described here:

You can find my (invalid) bug report here. I think this can only be used for web server fingerprinting. Or if there is a client (e.g. a browser) that sends the null character as well, there might be some changes for header injection.


As everything starts once, today it’s my blog. This blog is simply about IT Security stuff.

Today I was wondering how a web server reacts on an URI with a pound sign (#) in it. It took me about 3 hours to realise that it is not possible to send a pound sign with Firefox and WebScarab, even my first try with the perl library did not work. They’re just all too URI RFC 3986 compliant. But python’s urllib2 worked (not urllib)!

Findings: Apache and IIS simply ignore it and everything after it. Apache Tomcat interprets the pound sign as part of the last GET value.

If you want to try it yourself, use Wireshark to watch if the pound sign is really sent! I’m still thinking about an exploit…