Friday 8 July 2016

ISAPI URL Rewriting for ASP Classic on IIS 8

ISAPI URL Rewriting for ASP Classic on IIS 8


By Strictly-Software

I recently had to setup a dedicated server for some sites that we had to move from in-house hosting and outsource.

It was a move from Windows 2003 to a Windows 2012 server with IIS 8. 

As usual the person setting up the system was as useful as a glass hammer and I had to spend ages learning things outside my job description just to get the system to work.

Not only was the web server side of things a pain but he copies databases with a backup/restore method which means having to re-link all the users and logins, re-create MS Agent jobs, set execute permissions, trustworthy settings and install CLR assemblies and handle collation conflicts etc. All things I could do without!

As everything is so costly for Windows Hosting, licences for everything, moving the Helicon ISAPI .httpd.ini file was a no no due to the fees. Luckily you can install for free the IIS URL Rewrite Module and use that to replicate any rules you may be using.

IIS 8 is a lot different from IIS 6.5 which I was working on before but once you get the IIS URL Rewrite 2.0 component installed from Microsofts website you will see it (after restarting IIS), in the bottom section of each site in your IIS panel.

You can then use the GUI interface to create the rules which is a bit cumbersome when you are used to just knocking out regular expressions in a text file.

However it does make it easier for people not as skilled at writing regular expressions as they can choose the type of expression from a drop down, rewrite or redirect or abort request, but you can use the "Test Pattern" tool to ensure your rule will work.

This article is a great guide for people wanting to set up rules using the interface and it shows you the output which is a web.config file placed in the root of your site. It doesn't matter if your site is .NET or ASP classic the web.config rule will work as long as .NET is installed and enabled in IIS.

This means you can easily open up the file and edit it when adding rules.

A simple example which shows you some of the rules you can do is below. Remember as it's an XML file you need to HTML Encode any characters that may malform the XML such as angled brackets. This is where using the GUI Tool is useful as it will auto encode everything for you and tell you if the XML is valid.

This example starts with a simple rewrite rule for SEO to make /promo go to the page /promo.asp and then it has an SQL injection example and an XSS injection example.

Obviously all input should be sanitised anyway but it doesn't harm to have multiple rings of security. At the end is a list of common HTTP libraries to ban. These are the sort of user-agent that scrapers and script kiddies use. They often download the tools off the web and don't know how to OR forget to change the user-agent.

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <httpErrors errorMode="Detailed" />
        <rewrite>
            <rules>                
  <rule name="Promo SEO to Promo" stopProcessing="false">
                    <match url="^promo$" />
                    <action type="Rewrite" url="/promo.asp" />
                </rule>
  <rule name="Login Reminder SEO to Login" stopProcessing="false">
                    <match url="^loginreminder$" />
                    <action type="Rewrite" url="/logonreminder.asp" />
                </rule>
                <rule name="RequestBlockingRule1 SQL Injection" stopProcessing="true">
                    <match url=".*" />
                    <conditions>
                        <add input="{QUERY_STRING}" pattern=".*?sys\.?(?:objects|columns|tables)" />
                    </conditions>
                    <action type="AbortRequest" />
                </rule>
                <rule name="RequestBlockingRule1 XSS" stopProcessing="true">
                    <match url=".*" />
                    <conditions>
                        <add input="{QUERY_STRING}" pattern=".*?(<svg|alert\(|eval\(|onload=).*" />
                    </conditions>
                    <action type="AbortRequest" />
                </rule>                
                <rule name="RequestBlockingRule2" stopProcessing="true">
                    <match url=".*" />
                    <conditions>
                        <add input="{HTTP_USER_AGENT}" pattern=".*?(?:ColdFusion|libwww\-perl|Nutch|PycURL|Python|Snoopy|urllib|LWP|PECL|POE|WinHttp|curl|Wget).*" />
                    </conditions>
                    <action type="CustomResponse" statusCode="403" statusReason="Forbidden" statusDescription="Access Denied" />
                </rule>        
            </rules>
        </rewrite>
    </system.webServer>
</configuration>


As you can see I am aborting the requests for hackers and bad BOTs rather than returning a 403 status code in all but the last example, and I am just doing it there to show you how a 403 is carried out.

The syntax is slightly different from normal .htaccess rules due to being inside the XML file and the properties that are specified but in reality if you know regular expressions you won't go wrong.

By Strictly-Software

© 2016 Strictly-Software