10 min read

Web applications can be attacked from a number of different angles, which is what makes defending against them so difficult. Here are just a few examples of where things can go wrong to allow a vulnerability to be exploited:

  • The web server process serving requests can be vulnerable to exploits. Even servers such as Apache, that have a good security track record, can still suffer from security problems – it’s just a part of the game that has to be accepted.
  • The web application itself is of course a major source of problems. Originally, HTML documents were meant to be just that – documents. Over time, and especially in the last few years, they have evolved to also include code, such as client-side JavaScript. This can lead to security problems. A parallel can be drawn to Microsoft Office, which in earlier versions was plagued by security problems in its macro programming language. This, too, was caused by documents and executable code being combined in the same file.
  • Supporting modules, such as mod_php which is used to run PHP scripts, can be subject to their own security vulnerabilities.
  • Backend database servers, and the way that the web application interacts with them, can be a source of problems ranging from disclosure of confidential information to loss of data.

HTTP fingerprinting

Only amateur attackers blindly try different exploits against a server without having any idea beforehand whether they will work or not. More sophisticated adversaries will map out your network and system to find out as much information as possible about the architecture of your network and what software is running on your machines. An attacker looking to break in via a web server will try to find one he knows he can exploit, and this is where a method known as HTTP fingerprinting comes into play.

We are all familiar with fingerprinting in everyday life – the practice of taking a print of the unique pattern of a person’s finger to be able to identify him or her – for purposes such as identifying a criminal or opening the access door to a biosafety laboratory. HTTP fingerprinting works in a similar manner by examining the unique characteristics of how a web server responds when probed and constructing a fingerprint from the gathered information. This fingerprint is then compared to a database of fingerprints for known web servers to determine what server name and version is running on the target system.

More specifically, HTTP fingerprinting works by identifying subtle differences in the way web servers handle requests – a differently formatted error page here, a slightly unusual response header there – to build a unique profile of a server that allows its name and version number to be identified. Depending on which viewpoint you take, this can be useful to a network administrator to identify which web servers are running on a network (and which might be vulnerable to attack and need to be upgraded), or it can be useful to an attacker since it will allow him to pinpoint vulnerable servers.

We will be focusing on two fingerprinting tools:

  • httprint

    One of the original tools – the current version is 0.321 from 2005, so it hasn’t been updated with new signatures in a while. Runs on Linux, Windows, Mac OS X, and FreeBSD.

  • httprecon

    This is a newer tool which was first released in 2007. It is still in active development. Runs on Windows.

Let’s first run httprecon against a standard Apache 2.2 server:

ModSecurity 2.5

And now let’s run httprint against the same server and see what happens:

ModSecurity 2.5

As we can see, both tools correctly guess that the server is running Apache. They get the minor version number wrong, but both tell us that the major version is Apache 2.x.

Try it against your own server! You can download httprint at http://www.net-square.com/httprint/ and httprecon at http://www.computec.ch/projekte/httprecon/.

Tip

If you get the error message Fingerprinting Error: Host/URL not found when running httprint, then try specifying the IP address of the server instead of the hostname.

The fact that both tools are able to identify the server should come as no surprise as this was a standard Apache server with no attempts made to disguise it. In the following sections, we will be looking at how fingerprinting tools distinguish different web servers and see if we are able to fool them into thinking the server is running a different brand of web server software.

How HTTP fingerprinting works

There are many ways a fingerprinting tool can deduce which type and version of web server is running on a system. Let’s take a look at some of the most common ones.

Server banner

The server banner is the string returned by the server in the Server response header (for example: Apache/1.3.3 (Unix) (Red Hat/Linux)). This banner can be changed by using the ModSecurity directive SecServerSignature. Here is what to do to change the banner:

# Change the server banner to MyServer 1.0
ServerTokens Full
SecServerSignature "MyServer 1.0"

Response header

The HTTP response header contains a number of fields that are shared by most web servers, such as Server, Date, Accept-Ranges, Content-Length, and Content-Type. The order in which these fields appear can give a clue as to which web server type and version is serving the response. There can also be other subtle differences – the Netscape Enterprise Server, for example, prints its headers as Last-modified and Accept-ranges, with a lowercase letter in the second word, whereas Apache and Internet Information Server print the same headers as Last-Modified and Accept-Ranges.

HTTP protocol responses

An other way to gain information on a web server is to issue a non-standard or unusual HTTP request and observe the response that is sent back by the server.

Issuing an HTTP DELETE request

The HTTP DELETE command is meant to be used to delete a document from a server. Of course, all servers require that a user is authenticated before this happens, so a DELETE command from an unauthorized user will result in an error message – the question is just which error message exactly, and what HTTP error number will the server be using for the response page?

Here is a DELETE request issued to our Apache server:

$ nc bytelayer.com 80
DELETE / HTTP/1.0

HTTP/1.1 405 Method Not Allowed
Date: Mon, 27 Apr 2009 09:10:49 GMT
Server: Apache/2.2.8 (Fedora) mod_jk/1.2.27 DAV/2
Allow: GET,HEAD,POST,OPTIONS,TRACE
Content-Length: 303
Connection: close
Content-Type: text/html; charset=iso-8859-1

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>405 Method Not Allowed</title>
</head><body>
<h1>Method Not Allowed</h1>
<p>The requested method DELETE is not allowed for the URL /index.
html.</p>
<hr>
<address>Apache/2.2.8 (Fedora) mod_jk/1.2.27 DAV/2 Server at www.
bytelayer.com Port 80</address>
</body></html>

As we can see, the server returned a 405 – Method Not Allowed error. The error message accompanying this response in the response body is given as The requested method DELETE is not allowed for the URL/index.html. Now compare this with the following response, obtained by issuing the same request to a server at www.iis.net:

$ nc www.iis.net 80
DELETE / HTTP/1.0

HTTP/1.1 405 Method Not Allowed
Allow: GET, HEAD, OPTIONS, TRACE
Content-Type: text/html
Server: Microsoft-IIS/7.0
Set-Cookie: CSAnonymous=LmrCfhzHyQEkAAAANWY0NWY1NzgtMjE2NC00NDJjLWJlYz
YtNTc4ODg0OWY5OGQz0; domain=iis.net; expires=Mon, 27-Apr-2009 09:42:35
GMT; path=/; HttpOnly
X-Powered-By: ASP.NET
Date: Mon, 27 Apr 2009 09:22:34 GMT
Connection: close
Content-Length: 1293
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.
w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html >
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-
1"/>
<title>405 - HTTP verb used to access this page is not allowed.</
title>
<style type="text/css">
<!--
body{margin:0;font-size:.7em;font-family:Verdana, Arial, Helvetica,
sans-serif;background:#EEEEEE;}
fieldset{padding:0 15px 10px 15px;}
h1{font-size:2.4em;margin:0;color:#FFF;}
h2{font-size:1.7em;margin:0;color:#CC0000;}
h3{font-size:1.2em;margin:10px 0 0 0;color:#000000;}
#header{width:96%;margin:0 0 0 0;padding:6px 2% 6px 2%;fontfamily:"
trebuchet MS", Verdana, sans-serif;color:#FFF;
background-color:#555555;}
#content{margin:0 0 0 2%;position:relative;}
.content-container{background:#FFF;width:96%;margin-top:8px;padding:10
px;position:relative;}
-->
</style>
< /head>
<body>
<div id="header"><h1>Server Error</h1></div>
<div id="content">
<div class="content-container"><fieldset>
<h2>405 - HTTP verb used to access this page is not allowed.</h2>
<h3>The page you are looking for cannot be displayed because an
invalid method (HTTP verb) was used to attempt access.</h3>
</fieldset></div>
</div>
</body>
</html>

The site www.iis.net is Microsoft’s official site for its web server platform Internet Information Services, and the Server response header indicates that it is indeed running IIS-7.0. (We have of course already seen that it is a trivial operation in most cases to fake this header, but given the fact that it’s Microsoft’s official IIS site we can be pretty sure that they are indeed running their own web server software.)

The response generated from IIS carries the same HTTP error code, 405; however there are many subtle differences in the way the response is generated. Here are just a few:

  • IIS uses spaces in between method names in the comma separated list for the Allow field, whereas Apache does not
  • The response header field order differs – for example, Apache has the Date field first, whereas IIS starts out with the Allow field
  • IIS uses the error message The page you are looking for cannot be displayed because an invalid method (HTTP verb) was used to attempt access in the response body

Bad HTTP version numbers

A similar experiment can be performed by specifying a non-existent HTTP protocol version number in a request. Here is what happens on the Apache server when the request GET / HTTP/5.0 is issued:

$ nc bytelayer.com 80
GET / HTTP/5.0

HTTP/1.1 400 Bad Request
Date: Mon, 27 Apr 2009 09:36:10 GMT
Server: Apache/2.2.8 (Fedora) mod_jk/1.2.27 DAV/2
Content-Length: 295
Connection: close
Content-Type: text/html; charset=iso-8859-1

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>400 Bad Request</title>
</head><body>
<h1>Bad Request</h1>
<p>Your browser sent a request that this server could not
understand.<br />
</p>
<hr>
<address>Apache/2.2.8 (Fedora) mod_jk/1.2.27 DAV/2 Server at www.
bytelayer.com Port 80</address>
</body></html>

There is no HTTP version 5.0, and there probably won’t be for a long time, as the latest revision of the protocol carries version number 1.1. The Apache server responds with a 400 – Bad Request Error, and the accompanying error message in the response body is Your browser sent a request that this server could not understand. Now let’s see what IIS does:

$ nc www.iis.net 80
GET / HTTP/5.0

HTTP/1.1 400 Bad Request
Content-Type: text/html; charset=us-ascii
Server: Microsoft-HTTPAPI/2.0
Date: Mon, 27 Apr 2009 09:38:37 GMT
Connection: close
Content-Length: 334

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/
TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Bad Request</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=usascii"></
HEAD>
<BODY><h2>Bad Request - Invalid Hostname</h2>
<hr><p>HTTP Error 400. The request hostname is invalid.</p>
</BODY></HTML>

We get the same error number, but the error message in the response body differs – this time it’s HTTP Error 400. The request hostname is invalid. As HTTP 1.1 requires a Host header to be sent with requests, it is obvious that IIS assumes that any later protocol would also require this header to be sent, and the error message reflects this fact.

LEAVE A REPLY

Please enter your comment!
Please enter your name here