2015-07 IIS 8.0 on Windows Server 2012 with ModSecurity 2.7.2


We will assume that we have an existing infrastructure in place, including Active Directory and DNS. In the example, the Active Directory domain will be named corp.class.tu, with domain controller brakiri.corp.class.tu at

Configure the networking for the new server; in this example we set the IP address of the web server to

We also configure the name and domain of the server; in the example, the web server will be named pakmara.corp.class.tu. We will join the web server to our domain.

Be sure that you have run a full sysprep before you join your system to the domain.

All other settings are in their default state. In particular, we have not added any additional roles to our server.


Run the Add Roles and Features Wizard (which can be found on the dashboard for server manager), select Web Server (IIS). You will be prompted to also add some management tools for IIS servers; do so. The Features provided can be left in their default state. When it comes to customizing the Role Services, we will add the following additional features:

  • HTTP Redirection
  • Custom Logging
  • Logging Tools
  • Request Monitor
  • Basic Authentication
  • IP and Domain Restrictions
  • URL Authorization
  • Windows Authentication
  • ISAPI Extenstions (under Application Development)
  • ISAPI Filters (under Application Development)

Note that we will not be discussing important topics like ASP, ASP.NET, and CGI scripts. Sorry.

If you want to install an FTP server on the machine, this is where you do that as well. We won’t.


IIS Install

The basics

The primary tool for managing your IIS web site is the IIS Manager. It can be launched from the Server Manager, under the Tools menu.

When it starts, you may be presented with a prompt to ask if you want to remain connected to the latest web platfrom components. Since we are working in an isolated lab, we’ll select "No".


Start at the node for your web server; in my case this is PAKMARA (CORP\mcole), which is the name of the host, followed by the name of the domain administrator I have used to log on.

Expand the Sites node. Now you see a list of all of the sites running on that
server. A Default Web Site already exists.

Expand the Default Web Site node. Notice that many of the icons are the same as the icons for the IIS installation as a whole.

Let us add some content to the default web site. The default directory for the IIS web site is c:\inetpub\wwwroot. You can visit that site directly in file explorer; you can also open that folder directly from the action pane in IIS Manager by selecting "Explore". You can also get there from the tree on the left, by right-clicking on the web site. The default install has five documents- three .png images, a .jpg image, and a web page (iisstart.htm). View the contents of iisstart.htm, both in a browser and in a text editor. Does the image have any interesting properties?

Create a web page, called index.html and place it in the c:\inetpub\wwwroot directory. Note that UAC may make this process more enjoyable than you would expect. I created my example file in the Documents library and copied it over to the proper directory; I am sure that there are other options.

Verify that your document is served.

Though there is a default web site already set up, let’s build a second. Go back to the IIS manager, then navigate Sites (rt click) → Add Web Site. Set the Site name: WebTest, and set the Physical path: C:\WebTest. You will need to create this folder- it does not yet exist. Set the Host name: webtest.corp.class.tu, and start the web site immediately.


In c:\webtest, create the default file index.html. We would like to visit this web site, but how do we account for the fact that our web server already has a web site? Give our IIS machine a second IP address, with a second DNS entry. Go to network properties (e.g. Control Panel → Network and Internet → Network & Sharing Center → View Status → Change Adapter Settings → (right-click) Properties → Internet Protocol Version 4 → Properties → Advanced → IP Settings → Add) and add a second IP address to this NIC- say

Windows 2012 (IIS) (Pakmara)-2014-03-16-15-36-48

If you then check your address from the command line, you will see both addresses present:


Windows IP Configuration

Ethernet adapter Ethernet0:

   Connection-specific DNS Suffix  . :
   Link-local IPv6 Address . . . . . : fe80::edbc:b65d:143e:ee81%13
   IPv4 Address. . . . . . . . . . . :
   Subnet Mask . . . . . . . . . . . :
   IPv4 Address. . . . . . . . . . . :
   Subnet Mask . . . . . . . . . . . :
   Default Gateway . . . . . . . . . :

Tunnel adapter Local Area Connection* 11:

   Media State . . . . . . . . . . . : Media disconnected
   Connection-specific DNS Suffix  . :

Tunnel adapter isatap.{1BB7279E-DF9D-46A0-A5CA-45F88EFEE852}:

   Media State . . . . . . . . . . . : Media disconnected
   Connection-specific DNS Suffix  . :

Since our web server is joined to a domain that is also running a DNS server, the server will automatically add both a A and a PTR record matching the hostname with the new IP address. Indeed, looking at the DNS Manager, we will see both addresses:


A lookup for this hostname will return both IP addresses:

C:\Users\mcole>nslookup pakmara.corp.class.tu
Server:  brakiri.corp.class.tu

Name:    pakmara.corp.class.tu

Of course, this is not the behavior we want. Instead, we will delete the both the original name and the duplicate from the DNS server (from both the forward and the reverse lookup zones), and add new records (both A and PTR) for pakmara.corp.class.tu at IP address and for webtest.corp.class.tu at When we are finished, we can verify that the nameserver works as we expect:

C:\Users\mcole>nslookup pakmara.corp.class.tu
Server:  brakiri.corp.class.tu

Name:    pakmara.corp.class.tu

C:\Users\mcole>nslookup webtest.corp.class.tu
Server:  brakiri.corp.class.tu

Name:    webtest.corp.class.tu

Go to another machine & visit the pages http://pakmara.corp.class.tu and http://webtest.corp.class.tu. The test pages you created should appear.

Go to another machine & visit the pages and What pages appear? Did you expect that result? Clearly, there is more to learn.

The IIS Manager interface

Let us spend some time learning about the different features of the IIS Manager.

Default document

If no document is specified in a URL, then the IIS will attempt to return a default document. The precise document is specified by the Default Document. This can be set at the web server level, or at the level of the individual sites. From IIS Manager, select either the web server (PAKMARA in this example) or the individual web sites (Default Web Site or WebTest in this example). In each case, you will be able to modify the Default Document. Settings made at the server level will propagate to the individual sites.

The default settings include 5 documents. What are they?

If your site uses a particular document as its index, then that document should be at the top of the list for performance reasons. When IIS looks for a default document, it looks through this list, in the specified order. It will not go on to the next item in the list until it is satisfied that the current list item does not exist, so if your default document is at the top of the list, then IIS will spend less time searching through the list.

Verify this by changing the order of the default document at the server level. Examine the default document order on the two web sites, and verify that the order of the documents has changed.

The ordering can also be specified at the site level. Verify this by changing the order of a site. Note that you will be warned that it will no longer inherit changes made by the parent. Note also that there is an option in the action pane to revert to the inherited default document. See also https://www.iis.net/ConfigReference/system.webServer/defaultDocument

Directory browsing

By default, if a directory is requested (e.g. http://webtest.class.tu/) and no default page exists (as described above), then IIS will return a 403 error. If directory browsing is enabled, then in this case IIS would return a listing of the files in the given directory.

Directory browsing can be enabled at either the server level or at the level of individual sites. To see how this occurs, rename the index.html file for the webtest site to something else- say indx.html. Load the page http://webtest.corp.class.tu both with and without directory browsing enabled.

As an added bonus- What are the contents of the file web.config? (If you have done everything described above and allowed directory browsing at the site level rather than the server level, the file will exist. If not, well, is that my fault?) Will that file be served? What is the content of the file? See also http://www.iis.net/ConfigReference/system.webServer/directoryBrowse

Note also that if Directory browsing is enabled, it propagates to all subdirectories.

Custom error pages

IIS can be set to provide customized error pages. By default, it provides an error page customized to the language of the browser. These error pages can be set at the server level or at the site level.

We saw above that, if directory browsing is not enabled and if no default page is present in a directory, then IIS will return a 403 error. Modify your system so that it returns a page of your choice when it encounters a 403 error, and verify that this works as expected from a machine other than the server.


In the action pane, notice the link for Edit Feature Settings. It gives three options for error responses

  • Custom error pages
  • Detailed errors
  • Detailed errors for local requests and custom error pages for remote requests.

Earlier you modified your system so that IIS would return a 403 error, as your directory has no default document and directory browsing is turned off. View that same page, but now from a browser on the server. Note the difference that detailed errors make. Note also the security implications of running a site where detailed errors are sent back to remote users.


For more details, see http://learn.iis.net/page.aspx/267/how-to-use-http-detailed-errors-in-iis-70/


Bindings are set on a per-site level, and determine to which requests a particular web site will respond. To see the bindings for a site, click on the site in the IIS manager, and then select bindings from the action pane. View the bindings for the default web site.

Now view the bindings for the new web site we created, webtest.


Here we see that for the WebTest site,

  • Protocl is http
  • IP address is all unassigned
  • Port is 80
  • Host name is webtest.corp.class.tu

Recall the odd behavior we saw above, where we got the right web site if we specified the right name but the IP address always resolved the default web site. Use bindings and correct this issue. [This may not be as obvious as you think! Be sure to test out each of the following cases

You should get the correct web site each time. To guide your decisions, consider the following questions: To which IP should each site respond? Does the name of the site matter?


You can set limits on the network resources available to a particular site on your IIS server. To do so, select Limits from the action pane.

Limit bandwidth usage (in bytes) refers to the number of bytes per second of bandwidth for that site; the default is 4294967295.

Connection time-out specifies the time that IIS will wait before it disconnects a connection that is considered inactive. The default is 2 minutes.

Limit number of connections refers to the maximum number of allowable simultaneous connections to the site. The default is 4294967295.

Advanced topics

Virtual directories

Virtual directories can be used in IIS in roughly the same fashion as we used aliases in Apache. In IIS, a virtual directory is a URL path that is mapped to a portion of the file system.

They are configured from the action menu on each web site.

Let us illustrate this with an example. Create the directory c:\webtest\dir1 and put an index file in that directory. Verify that the URL http://webtest.class.tu/dir1 can be used to retrieve that file.

Create the new directory c:\outside and put an index file in that directory. Note that this is now outside the document root for either of our web sites.

From IIS manager, right-click on the web site WebTest, and select Add Virtual Directory. For the alias, select dir2, and for the physical path, select c:\outside.


Verify that the URL http://webtest.class.tu/dir2 now retrieves the index.html document from C:\outside.

One fun fact is that now the same directory can be served by the different websites in different locations in the web site.

Command Line tools- appcmd.exe

This program is located in %SystemRoot%\system32\inetsrv\Appcmd.exe. This is not part of the system path, so the file must be started directly from this directory, or the path variable must be modified.

This is _the_ command line tool for working with IIS

It must be run from an administator level command prompt. Note that, just because you started a command prompt as an administrator, this does not mean that you have an administrator command prompt. You must right-click on the entry in the Start Menu, and select “Run as administrator”

In general, Appcmd looks for a verb and a noun

Noun Verbs
site list set add delete start stop
app list set add delete
apppool list set add delete start stop recycle
vdir (virtual directories) list set add delete
config list set search lock unlock clear reset migrate
wp (worker processes) list
request list
module (web server modules) list set add delete install uninstall
backup list add delete restore
trace list configure inspect

As examples, try
To list all of the sites that IIS is serving:

C:\Windows\System32\inetsrv>appcmd.exe list sites
SITE "Default Web Site" (id:1,bindings:http/,state:Started)
SITE "WebTest" (id:2,bindings:http/,state:Started)

To stop IIS serving a particular site

C:\Windows\System32\inetsrv>appcmd.exe stop site WebTest
"WebTest" successfully stopped

To have IIS start serving a particular site

C:\Windows\System32\inetsrv>appcmd.exe start site WebTest
"WebTest" successfully started.

To have IIS list all of the virtual directories in use

C:\Windows\System32\inetsrv>appcmd.exe list vdir
VDIR "Default Web Site/" (physicalPath:%SystemDrive%\inetpub\wwwroot)
VDIR "Default Web Site/test" (physicalPath:C:\Outside)
VDIR "WebTest/" (physicalPath:c:\WebTest)
VDIR "WebTest/dir2" (physicalPath:C:\Outside)

Suppose that we want to change the default document to home.html. Create the document home.html in the main web site (C:\inetpub\wwwroot\home.html); then run the following

c:\Windows\System32\inetsrv> appcmd.exe set config
"Default Web Site" /section:defaultDocument /enabled:true
Applied configuration changes to section "system.webServer/defaultDocument" for
"MACHINE/WEBROOT/APPHOST/Default Web Site" at configuration commit path "MACHINE
/WEBROOT/APPHOST/Default Web Site"

Check that the default web page has been changed by viewing your default site in a web browser. Go to the Default Document section for the Default Web Site in the IIS Manager and verify that the configuration there has changed.

Let’s enable directory browsing in the WebTest site. Rename any default documents in your document root; run the following

C:\Windows\System32\inetsrv>appcmd.exe set config "WebTest" 
-section:system.webServer/directoryBrowse /enabled:"True" 
/showFlags:"Date, Time, Size, Extension"
Applied configuration changes to section "system.webServer/directoryBrowse" for
"MACHINE/WEBROOT/APPHOST/WebTest" at configuration commit path "MACHINE/WEBROOT/

Verify the change, both by loading the page and by examining IIS manager.

Just about anything that can be done through IIS manager can be done through appcmd.exe

Configuration files.

The configuration files are kept in a few location in .xml format. IIS is tightly integrated with the .NET framework (which we cannot cover in any significant detail.)

The .NET framework global settings for the server is


Though this is a .NET file, this lets IIS share configuration information with ASP.NET.

Now I am not going to say that the documentation here is a bit sketchy; I will simply point out that that file C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config\machine.config is kind enough to provide a link to documentation "For a full documentation of the schema please refer to http://go.microsoft.com/fwlink/?LinkId=42127". You guessed it though- that leads to a "Content not Found" page. I should have seen that 404 coming, shouldn’t I?

The IIS global configuration are in:


This file has two important sections: <system.applicationHost> and <system.webServer>. This file is only modifiable by machine administrators. This is the main configuration file for IIS

Each web site has its own file web.config in its root directory. This file may be hidden and you may need to enable “Show hidden files and folders” (File Explorer → Tools → Folder Options → View → Advanced Settings) to see it. If you compare the web.config file for the Default Web Site and the web.config for webtest, you will see which (if either) allows directory browsing.

There is a file to allow IIS to load its configuration from a remote location. This way multiple servers can share the same configuration. The file is


There is a separate file to configure IIS manager; it is


We will not need to edit these files manually.

IP Address and Domain Restrictions

One can deny access to the entire web site or just to a directory (including a virtual directory) or to an application by IP address range. Go to IIS manager and select the component (web site / directory / etc.), then select IPv4 Address and Domain Restrictions. Rules to allow or deny connections can then be simply set from the action pane. Rules will match in the order specified in the configuration.

A rule at one level that contradicts a rule at a lower level appears to cause the server to throw an error (Code 500 rather than 403.6 is sent; checking the rules set will inform you that an error condition exists.)

Note that if the server is accessible via IPv4 and IPv6 then denying an IPv4 host may let them simply connect via IPv6. It is possible to do IPv6 denials, but not using the tool in IIS manager.

Try out the feature- choose one web site, and choose two systems to use to browse your site. Add a rule that disallows one site to view the site, and verify that this
works as expected.


Request Filtering

We can use Request filtering to blacklist certain URL’s, verbs (e.g. GET, POST, HEAD, PUT, DELETE), or even query strings. A user that makes a blacklisted request would receive a 404 error, and the server would record this as a 404.19 error, indicating that the request was blocked by a filtering rule.

As an example, let’s block any URL where the text "%00" appears in the query. We say last week how this could be used to null terminate a string in preparation for some sort of attack.

From either the web server, a single web site, or even a single virtual directory, select Request Filtering. Select "Add Filtering Rule" from the action pane. Give the rule a name, and add "%00" as the Deny String.


Visit the web site, once with the usual URL http://pakmara.corp.class.tu, and then once again with a null string as a GET parameter, like http://pakmara.corp.class.tu?a\%00. You should then be denied access to that page:

For more details on request filtering, visit http://www.iis.net/configreference/system.webserver/security/requestfiltering.


This is the process of determining the identity of a user requesting an IIS resource. In some cases, this will let IIS impersonate that user to access resources (c.f. Authorization above). Choices are:

  • Anonymous authentication. This provides an identity for users who do not present
    credentials. The authenticated user identity will be a Windows anonymous user account. If you do not want a portion of your web site accessed by anonymous users, then you must disable anonymous authentication for that portion of the web site- even if
    you enable other forms of authentication.
  • Basic authentication. This is the same RFC 2617 HTTP protocol based technique we we discussed for Apache. In particular, credentials are sent in plain text. This is not part of the default IIS install; we did install it. Users must authenticate with a valid local or domain account.
  • Windows authentication. This uses windows techniques for authentication (NTLM or Kerberos). This is not part of the default IIS install; we did install it. This does work on e.g. Firefox on Linux or Chrome on Windows (tested) but fails on Konqueror on Linux. This uses a challenge-response system that is more resistant to sniffing. (e.g. Cain & Abel did not sniff the hashes from FF/Linux → IIS).
  • ASP.NET Authentication. Used by ASP.NET applications; this will not be discussed.
  • Client certificate mapping authentication or IIS Client certificate mapping authentication. Neither of these were installed on our test system. These map SSL certificates to particular windows accounts which are then used to perform authorization. We will not discuss these in detail.

To illustrate these principles, let us apply some test cases to our default web site. From IIS Manager, select the Default Web Site, then select the Authentication button. Notice that four types of authentication are listed (Anonymous, Basic, Windows, and ASP.NET) and that two of the three are disabled.

IIS Auth
Disable Anonymous Authentication, and try to load a page from the web site. What occurs?

Enable Basic Authentication to the web site and try again. For credentials, try a domain account, where you specify the domain. Between each attempt, close and restart your browser; you do not want to be sending or using cached credentials.

Repeat, but for credentials, try a domain account without specifying the domain.

What happens if you change the default domain when you configure basic authentication?


Use a sniffer to watch this traffic. Can you find the passwords in cleartext? [Hint- Yes.]

Disable Basic Authentication and enable Windows Authentication. Does anything change? Does it matter if you are using a Windows machine or a Linux machine?

Now enable both Anonymous Authentication and Basic Authentication. What behavior do you observe?


Getting a certificate

When we enabled basic authentication, we were warned that SSL was not enabled for the site. Let’s set it up.

We start by creating a certificate request, getting it signed by our CA (the same CA we set up last week!), and installing it.

First, we need to make sure that our CA is going to be trusted by the server. Grab the stored the CA Server certificate (not the private key!) from the file /etc/pki/CA/certs/ca.crt. Copy that file from the CA to the web server.

From the Start menu, select Run and choose "mmc"

From mmc, select Add/Remove Snap-in, and select Certificates. You want the snap-in to manage certificates for Computer accounts, and then for the Local Computer. Hit Finish to be presented with a Window like the following.
Right-click on Trusted Root Certificates → All Tasks → Import. From the Certificate Import Wizard, select the certificate CA.crt that you brought over from the CA. Be sure that you store the result in the Trusted Root Certification Authorities store.

Now that we have told the system to trust certificates signed by our CA, we need to create a certificate signing request (.csr) as we did in Apache. To do so, return to IIS manager. From the server (not from the site(s)) select Server Certificates.

Select Create Certificate Request from the Action Pane. Complete the form, but be sure to use your host name for your site (e.g. pakmara.corp.class.tu) as your Common Name.


Select Microsoft RSA SChannel Cryptographic Provider and choose a bit length. Specify the name of the request, say pakmara.csr. If you don’t specify a directory, the file ends up in C:\Windows\System32.

Open the file in notepad and note how this is essentially the same format we saw for Apache.

Copy the csr to your CA. Sign the certificate as we did in Week 6; e.g.

[root@furies CA]# openssl x509 -req -days 365 -in
/etc/pki/CA/pakmara.csr -CA /etc/pki/CA/certs/ca.crt 
-CAkey /etc/pki/CA/private/ca.key -set_serial 02 -out 

Signature ok
subject=/C=US/ST=MD/L=Towson/O=Towson University/OU=Security 
Getting CA Private Key
Enter pass phrase for /etc/pki/CA/private/ca.key:

Copy the signed certificate pakmara.crt back to the IIS server.

Return to IIS Manager → Server Certificates and select Complete Certificate Request from the Action Pane. Complete the form, including the location of the certificate and a “Friendly name” for the result- say PakmaraSSL. Leave the certificate store as "Persona;".

At this point, the SSLTest certificate should appear in the list of server certificates.

Server Cert 3

Looking at the properties of the certificate, you should see it issued to the common name you selected earlier (pakmara.corp.class.tu) and issued by the common name of the CA, which we called furies.cosc.tu.


Creating the site

Now let us create a new site that will use SSL and the certificate we just installed. To create a new site, we use IIS Manager, and from the tree select IIS → Sites (right click) → Add Web Site. Complete the form. Use any Site name you wish, say PakmaraSSL

Let’s create a new directory (C:\SSL) to hold our site. We can continue to use pass-through authentication. Change the binding to use https, on port 443. Be sure to select the IP address that matches the host name (the common name) you selected for your certificate. Speaking of that certificate, select the certificate PakmaraSSL we had signed earlier.


Add some content to our web site- say an index.html page

Be sure to require SSL to visit the site; navigate IIS Manager → Web Site → SSL Settings; select “Require SSL”.


Client certificates allow the server to trust the client rather than the (traditional) other direction. The client will need a certificate signed by a CA that the server trusts. These are rare, and we can happily ignore them.

Visit the web page from a browser that has the CA’s certificate listed as trusted. Be sure to specify https in the address!

Hey- how do we get internet explorer to import our certificate? Navigate IE → Tools → Internet Options; Content → Certificates then select Import. Leave the Intended Purpose as <All>. From the Certificate Import Wizard, select the file that contains the certificate for the CA (ca.crt).

Windows 8- Olivaw-2013-03-17-15-42-06

Windows 8- Olivaw-2013-03-17-15-43-46

For the purpose of our class, you can use as your certificate store the Trusted Root Certification Authorities. Note that Windows will be unable to automatically
validate the certificate; this is expected behavior.


Logging can be configured at the site level or at the IIS level. Select Logging from the IIS Manager, either for a site or for the IIS installation as a whole.


The default location for the logs is %SystemDrive%\inetpub\logs\LogFiles. The logs are plain text files, stored either as UTF-8 (default) or ANSI (which is a superset of ISO 8859-1).

There are a number of log file formats.

  • W3C (default). You can specify what is logged from the following list
    1. Date
    2. Time
    3. Client IP
    4. User name
    5. Service name
    6. Server name
    7. Server IP
    8. Server port
    9. Method
    10. URI stem
    11. URI query
    12. Protocol status
    13. Protocol substatus
    14. Win32 status
    15. Bytes sent
    16. Bytes received
    17. Time taken
    18. Protocol version
    19. Host
    20. User agent
    21. Cookie
    22. Referer
  • NCSA format is a fixed format that record remote host name, user name, date, time, request type, HTTP status code, and the number of bytes sent by the server. Items are separated by spaces; time is recorded as local time.
  • IIS format is an extension of NCSA that also records elapsed time, number of bytes sent, action and target file. The items are separated by commas.
  • It is possible to use other logging formats by creating a new COM component that implements the ILogPlugin or ILogPluginEx interface. We did not install this feature.

Logs can also be sent directly to a database via ODBC logging. We did not install this feature.

Logs can be centralized by having them written to a remote network share.

You can write your own Powershell scripts to analyze and parse these logs. As an example, let’s tweak the work of Steven Askwith to pick out all of the unique client IP addresses that visited our web site. We can do that with the simple script

$IISLogPath = "C:\inetpub\logs\LogFiles\W3SVC2\u_ex140315.log" 
$IISLogFileRaw = [System.IO.File]::ReadAllLines($IISLogPath)
$headers = $IISLogFileRaw[3].split(" ")
$headers = $headers | where {$_ -ne "#Fields:"}
$IISLogFileCSV = Import-Csv -Delimiter " " -Header $headers -Path $IISLogPath
$IISLogFileCSV = $IISLogFileCSV | where {$_.date -notlike "#*"}
$clientIP = $IISLogFileCSV | foreach {$_.$("c-ip")} | Select-Object -Unique

foreach ($ip in $clientIP ) {

Remember to allow for unsigned script execution before running the script!

The first line is the path to the log being analyzed; if we wanted to we could loop over all of the web sites and all of the logs, but for simplicity here I chose one log on one web site. You can see how the entire log file is read, with each line being split into parts on empty spaces. The headers for the log are extracted from the fourth row, skipping the comment text "$Fields" in that line. The first header in the log is for the date; this script then ignores any line with a hash in the first field- these are comments. The list of client IP addresses is then stored in $clientIP, where we only keep unique entries. Right now, all the script then does is print the result to the screen; I am sure you can think of better things to do with this kind of data.

Now you may think that this is a bit boring, so let’s try something more interesting. Recall that if request filtering was enabled, then the response to a blocked request would be a 404.19 error. Let’s write a script to pull up the details on any such blocked request. We can do that with a script like

$IISLogPath = "C:\inetpub\logs\LogFiles\W3SVC1\u_ex140317.log" 
$IISLogFileRaw = [System.IO.File]::ReadAllLines($IISLogPath)
$headers = $IISLogFileRaw[3].split(" ")
$headers = $headers | where {$_ -ne "#Fields:"}
$IISLogFileCSV = Import-Csv -Delimiter " " -Header $headers -Path $IISLogPath
$IISLogFileCSV = $IISLogFileCSV | where {$_.date -notlike "#*"}

foreach( $entry in $IISLogFileCSV) {
   $status_code = [int]$entry.("sc-status")
   $status_subcode = [int]$entry.("sc-substatus")
   if( ($status_code -eq 404) -and ($status_subcode -eq 19)){

When this is run, it will dump the details of any such request to the screen:

PS C:\Windows\system32> C:\Users\mcole\Desktop\Logs.ps1

date            : 2014-03-17
time            : 01:51:52
s-ip            :
cs-method       : GET
cs-uri-stem     : /
cs-uri-query    : a=%00
s-port          : 80
cs-username     : -
c-ip            :
cs(User-Agent)  : Mozilla/5.0+(X11;+Ubuntu;+Linux+i686;+rv:11.0)+Gecko/20100101
cs(Referer)     : -
sc-status       : 404
sc-substatus    : 19
sc-win32-status : 0
time-taken      : 0

date            : 2014-03-17
time            : 02:03:59
s-ip            :
cs-method       : GET
cs-uri-stem     : /
cs-uri-query    : a=%00
s-port          : 80
cs-username     : -
c-ip            :
cs(User-Agent)  : Mozilla/5.0+(X11;+Ubuntu;+Linux+i686;+rv:11.0)+Gecko/20100101
cs(Referer)     : -
sc-status       : 404
sc-substatus    : 19
sc-win32-status : 0
time-taken      : 1

I think that we can all agree on the value of this ability, especially if you are responding to a suspected web site or database compromise.

Web Application Firewall

ModSecurity is available for IIS systems. The catch here is that the installation process for Windows systems is not as clean and as clear as one might hope. Downloading the current Windows installer for version 2.7.7 (x64) and installing it following the directions on Windows Server 2012 results in an installer failure each time. Digging around some mailing lists suggests that the developers are aware of some of the problems. In this example, I am going to fall back a few versions to ModSecurity 2.7.2 (which is on the labshare), as the installer there does work.


Before we install ModSecurity though, we need to first install the Microsoft Visual Studio 2010 runtime libraries. There are two different libraries depending on whether the underlying system is 32-bit or 64-bit. The catch here is that if you skip this step, the ModSecurity installation will complete. It won’t actually work, and will cause your website to essentially die and cover your logs with errors, but the installation won’t actually fail, as such.

After the runtime libraries are installed, the ModSecurity 2.7.2 installation process is straightforward. The installer lets you customize a directory for the the installer and the users for which the system is installed, however he default directory and installation for all users suits us well. Agree to the license, and the tool will install.

To configure ModSecurity, we start in the same fashion we did for our Apache server. The default install sets ModSecurity in C:\inetpub\wwwroot\owasp_crs, which is the location of the configuration file modsecurity.conf. Open that file. As before the first directive is

SecRuleEngine DetectionOnly

which tells ModSecurity to only perform detection, but not to take any action to modify or disrupt the connection. Once again, we modify this to read

SecRuleEngine On

As we did before, we also add a testing rule to our ModSecurity installation in the form

SecRule ARGS, "zzz" phase:1,log,deny,status:503,id:1

We can put this rule at the end of the ModSecurity.conf file. Save the result.

What? It won’t save. Happy, happy, joy, joy.

This is caused by a couple of factors. First, the file is marked read-only. You can see that by checking the properties tab for the file

You can change that property so that the file is no longer read-only if you wish, though it will require UAC elevation. Even so, if you open the file in notepad and try to save, you will still be presented with an Access Denied message, even if you are a Domain Admin. This is because of the (very) restrictive set of permissions used in Windows servers. I found it simplest to save the file to the Desktop, and then copy it over; this allows for the additional required UAC elevation to take place.

At this point, we now need to tell IIS to actually use ModSecurity. Suppose that we want to apply ModSecurity to the default web site, located at c:\inetpub\wwwroot. Earlier we saw that configuration changes in IIS manager for that web site would be reflected in the contents of the XML file c:\inetpub\wwwroot\web.config. [If we want to modify a different web site, then we modify the web.config file in the corresponding directory.]

Update that file to include the contents

<?xml version="1.0" encoding="UTF-8"?>
        <ModSecurity enabled="true" 
           configFile="c:\inetpub\wwwroot\owasp_crs\modsecurity_iis.conf" />

Note that if you have made other changes to he configuration for this web site, they will also be reflected in this file, and the result should be modified appropriately. Remember, this is XML, so be sure that your tags fall in the correct places!

Test the result as we did before. If you visit a web page like http://pakmara.corp.class.tu/index.html?a=zz, then you should receive the correct page, but if you add the third "z" to the GET parameter and request http://pakmara.corp.class.tu/index.html?a=zzz then your request should be blocked:


This will also be recorded in the logs. ModSecurity for IIS uses the Windows Application logs to store its results, and you will see an log entry of the following form to match the block action:


If you want to take a quick pass through the Windows Application log looking for ModSecurity denies, you can try some simple Powershell again. The following will simply print out the entries for each ModSecurity deny rule; I am sure you can customize it to your needs.

$logs = Get-EventLog -LogName application -Source ModSecurity
foreach ($entry in $logs) {
   if( $entry.("Message").Contains("Access denied")){

When run, you get the result

PS C:\Windows\system32> C:\Users\mcole\Desktop\Logs2.ps1
The description for Event ID '0' in Source 'ModSecurity' cannot be found.  The
local computer may not have the necessary registry information or message DLL 
files to display the message, or you may not have permission to access them.  
The following information is part of the event:'[client] 
ModSecurity: Access denied with code 503 (phase 1). Pattern match "zzz" at 
ARGS:a. [file "c:\inetpub\wwwroot\owasp_crs\modsecurity.conf"] [line "216"] 
[id "1"] [hostname "PAKMARA"] [uri "/index.html?a=zzz"] 
[unique_id "18086456105667395629"]'

Only those rules that are in the directory c:\inetpub\wwwroot\owasp_crs\activated_rules will be used by ModSecurity. You can move additional rules from the base_rules, experimental_rules, optional_rules, or slr_rules subdirectories to the activated_rules subdirectory if you wish to use them.

Fingerprinting a Web Server

Now let’s turn around and put on our black attacker’s hats for a moment. One of the first things an attacker wants to do when attacking a web server is to determine the precise version of the target web server. Finding this information out actually is not all that difficult, at least in most cases. How? We simply ask!

One way to ask is to use telnet; in this case we connect to the web server, and issue a HEAD / HTTP/1.0 request (with two carriage returns!), and read the output:

valen@hyach:~$ telnet pakmara.corp.class.tu 80
Connected to pakmara.corp.class.tu.
Escape character is '^]'.

HTTP/1.1 200 OK
Content-Length: 55
Content-Type: text/html
Last-Modified: Sun, 16 Mar 2014 18:33:56 GMT
Accept-Ranges: bytes
ETag: "5cfcb4a4641cf1:0"
Server: Microsoft-IIS/8.0
Date: Mon, 17 Mar 2014 20:12:42 GMT
Connection: close

Connection closed by foreign host.

Trying the same thing on our Apache server, we find instead

zathras@achilles:~$ telnet excalibur.cosc.tu 80
Connected to excalibur.cosc.tu.
Escape character is '^]'.

HTTP/1.1 403 Forbidden
Date: Mon, 17 Mar 2014 20:16:34 GMT
Server: Apache/2.2.15 (CentOS)
Accept-Ranges: bytes
Content-Length: 5039
Connection: close
Content-Type: text/html; charset=UTF-8

Connection closed by foreign host.

Thus, our simple telnet command was able to determine that pakmara.corp.class.tu is running IIS 8.0 (and so is on a Windows 2012 system), while excalibur.cosc.tu is running Apache 2.2.15 on a CentOS system. Not bad for telnet!

You may be wondering why the IIS system returned a 200 (OK) code while the Linux system returned a 403 (Forbidden) Error. Well, ModSecurity was set up on both of these hosts. If you look at the log on the Linux system, you will see that /var/log/httpd/error_log contains the note:

[Mon Mar 17 13:16:34 2014] [error] [client] ModSecurity: Access denied
with code 403 (phase 2). Operator EQ matched 0 at REQUEST_HEADERS. [file "/etc/
httpd/crs/activated_rules/modsecurity_crs_21_protocol_anomalies.conf"] [line 
"29"] [id "960008"] [rev "2"] [msg "Request Missing a Host Header"] [severity 
"WARNING"] [ver "OWASP_CRS/2.2.9"] [maturity "9"] [accuracy "9"] [tag "OWASP_
"OWASP_TOP_10/A7"] [tag "PCI/6.5.10"] [hostname "excalibur.cosc.tu"] [uri "/"] 
[unique_id "UydYIn8AAAEAAAkRDx8AAAAC"]

showing the ModSecurity blocked the connection because it did not have a host header. It is interesting that this rule (modsecurity_crs_21_protocol_anomalies.conf) is not in the activated rules section for a Windows installation. If you add them, you will see that the request is similarly blocked

valen@hyach:~$ telnet pakmara.corp.class.tu 80
Connected to pakmara.corp.class.tu.
Escape character is '^]'.

HTTP/1.1 403 ModSecurity Action
Content-Length: 1233
Content-Type: text/html
Server: Microsoft-IIS/8.0
Date: Mon, 17 Mar 2014 20:19:49 GMT
Connection: close

Connection closed by foreign host.

and as an added bonus we discover that ModSecurity is the reason for the block.

Of course, you often don’t even need to be this sophisticated. Sometimes just grabbing the wrong page is enough. What happens on our Apache server is we ask for a non-existent page, say http://excalibur.cosc.tu/fibble?


Oh look- it’ Apache 2.2.15!

IIS is not quite so nice by default, but we will certainly know that it is IIS:

  1. Davy
    June 3, 2016 at 11:54 am


    I installed modsecurity 2.8 but i got error:
    I try to do on your installation document
    bu i still got error. Could you tell me how i can this?

    Thanks your answer

    Log Name: Application
    Source: ModSecurity
    Date: 6/3/2016 3:53:36 PM
    Event ID: 1
    Task Category: None
    Level: Error
    Keywords: Classic
    User: N/A
    Computer: WIN-RNA83N2IDID
    The description for Event ID 1 from source ModSecurity cannot be found.
    Either the component that raises this event is not installed on your local computer or the installation is corrupted.
    You can install or repair the component on the local computer.

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s

%d bloggers like this: