Blocking Common Attacks using ModSecurity 2.5: Part 1

Magnus Mischel

November 2009

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 and httprecon at


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 80

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
Content-Length: 303
Connection: close
Content-Type: text/html; charset=iso-8859-1

<title>405 Method Not Allowed</title>
<h1>Method Not Allowed</h1>
<p>The requested method DELETE is not allowed for the URL /index.
<address>Apache/2.2.8 (Fedora) mod_jk/1.2.27 DAV/2 Server at www. Port 80</address>

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

$ nc 80

HTTP/1.1 405 Method Not Allowed
Content-Type: text/html
Server: Microsoft-IIS/7.0
Set-Cookie: CSAnonymous=LmrCfhzHyQEkAAAANWY0NWY1NzgtMjE2NC00NDJjLWJlYz
YtNTc4ODg0OWY5OGQz0;; 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.">
<html xmlns="">
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-
<title>405 - HTTP verb used to access this page is not allowed.</
<style type="text/css">
body{margin:0;font-size:.7em;font-family:Verdana, Arial, Helvetica,
fieldset{padding:0 15px 10px 15px;}
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;
#content{margin:0 0 0 2%;position:relative;}
< /head>
<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>

The site 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 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

<title>400 Bad Request</title>
<h1>Bad Request</h1>
<p>Your browser sent a request that this server could not
understand.<br />
<address>Apache/2.2.8 (Fedora) mod_jk/1.2.27 DAV/2 Server at www. Port 80</address>

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 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

<META HTTP-EQUIV="Content-Type" Content="text/html; charset=usascii"></
<BODY><h2>Bad Request - Invalid Hostname</h2>
<hr><p>HTTP Error 400. The request hostname is invalid.</p>

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.

Bad protocol name

An other tweak is to use a non-existent protocol name such as FAKE when issuing the request. This is Apache's response to such a request:

$ nc 80
GET / FAKE/1.0

HTTP/1.1 200 OK
Date: Mon, 27 Apr 2009 09:50:37 GMT
Server: Apache/2.2.8 (Fedora) mod_jk/1.2.27 DAV/2
Last-Modified: Thu, 12 Mar 2009 01:10:41 GMT
ETag: "6391bf-4d-464e1a71da640"
Accept-Ranges: bytes
Content-Length: 77
Connection: close
Content-Type: text/html

Welcome to our web page.

Apache actually delivers the web page with a 200—OK response code, as if this had been a properly formed GET request. In contrast, this is the response of Internet Information Services:

$ nc 80
GET / FAKE/1.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:51:56 GMT
Connection: close
Content-Length: 311

<META HTTP-EQUIV="Content-Type" Content="text/html; charset=usascii"></
<BODY><h2>Bad Request</h2>
<hr><p>HTTP Error 400. The request is badly formed.</p>

IIS responds with a 400 error, citing error message The request is badly formed. Interesting is also that IIS immediately returns the response after I pressed Enter a single time at the end of typing GET / FAKE/1.0—normally, HTTP requires that two newlines follow the request line, something that can be seen in Apache's response to the same request, where there is a blank line between the request line and the start of the response.

The ETag HTTP header

You may be familiar with the Last-Modified HTTP header. This is used to allow web browsers to cache downloaded content, such as image files, and avoids them having to re-download content that hasn't changed since it was last accessed. The ETag header (short for "Entity Tag") works in a similar way, but uses additional information about a file such as its size and inode number (which is a number associated with each file in the Linux file system) to construct a tag that will change only if one of these properties change.

ETag headers can be used by fingerprinting tools as one property to profile the server. In addition, using ETags can actually degrade performance—for example, if you are running several web servers to balance the load for a site and rely on the default Apache ETag configuration (as set by the FileETag directive) then each server will return a different ETag for the same file, even when the file hasn't changed. This is because the inode number will be different for the file on each server. The changing ETag values will cause browsers to re-download files even though they haven't changed.

Disabling ETags can therefore be beneficial both for website performance and to make it more difficult to fingerprint the web server. In Apache, you can use the Header directive to remove the ETag header:

Header unset ETag

One note of caution is that if you run WebDAV with mod_dav_fs, you shouldn't disable the ETag since mod_dav_fs uses it to determine if fi les have changed.

Using ModSecurity to defeat HTTP fingerprinting

Since we don't want to be more helpful than necessary to potential attackers, we will now attempt to use ModSecurity rules together with some other confi guration tweaks to make automated HTTP fingerprinting tools think that we are running a Microsoft IIS/6.0 server.

We will be using the information we now have available on how fingerprinting tools work to create a set of rules to defeat them. Here is a list of what we need to implement:

  • Allow only the request methods GET, HEAD, and POST
  • Block all HTTP protocol versions except 1.0 and 1.1
  • Block requests without a Host header
  • Block requests without an Accept header
  • Set the server signature to Microsoft-IIS/6.0
  • Add an X-Powered-By: ASP.NET 2.0 header
  • Remove the ETag header

Here are the rules used to implement this:

# Defeat HTTP fingerprinting

# Change server signature
SecServerSignature "Microsoft-IIS/6.0"

# Deny requests without a host header
SecRule &REQUEST_HEADERS:Host "@eq 0" "phase:1,deny"

# Deny requests without an accept header
SecRule &REQUEST_HEADERS:Accept "@eq 0" "phase:1,deny"

# Deny request that don't use GET, HEAD or POST
SecRule REQUEST_METHOD !^(get|head|post)$ "phase:1,t:lowerCase,deny"

# Only allow HTTP version 1.0 and 1.1
SecRule REQUEST_PROTOCOL !^http/1.(0|1)$ "phase:1,t:lowercase,deny"

# Add X-Powered-By header to mimic IIS
Header set X-Powered-By "ASP.NET 2.0"

# Remove the ETag header
Header unset ETag

Now let's run httprint and httprecon against our server again and see what happens. This is the result when running httprint:

ModSecurity 2.5

And this is what happens when running httprecon:

ModSecurity 2.5

Success! Both fingerprinting tools are now no longer identifying the server as Apache. Httprint thinks we are running Orion/2.0.x, while httprecon has been successfully fooled into identifying the server as Microsoft IIS 6.0.

Blocking proxied requests

Requests routed via proxy servers can be problematic for some sites. If you run any type of discussion forum, users can hide behind the perceived anonymity of a proxy server and launch anything from profanity-laden tirades in forum posts to outright denial of service attacks. You may therefore want to block proxied requests if you find that they cause problems on your site.

One way to do this is to check for the presence of the X-Forwarded-For header in the HTTP request. If this header exists, it means that the request was made by a proxy server on behalf of the real user.

This rule detects and blocks requests by proxy servers that use the X-Forwarded-For header:

SecRule &REQUEST_HEADERS:X-Forwarded-For "@gt 0" deny

The rule uses the & operator to return the number of request headers present with the name X-Forwarded-For. If this number is greater than zero, that means such a header is present, and the request is blocked.

Another similar header used by some proxy servers is the Via header, which you may also want to detect to catch a greater number of proxy servers. Keep in mind, though, that there are many legitimate uses for proxy servers, so before blocking every detectable proxy server out there, consider what legitimate traffic you will be blocking.

>> Continue Reading Blocking Common Attacks using ModSecurity 2.5: Part 2


[ 1 | 2 | 3]

If you have read this article you may be interested to view :

You've been reading an excerpt of:

ModSecurity 2.5

Explore Title