Introduction
Over the course of a few days, I've been spending a lot of time trying to secure my personal web server. I have used the IISLockDown tool and installed the latest URLScan. Since that time, I've been looking through my IIS logs and have found entries where people have been attempting to get into my system, either intentionally or because they've fallen victim to a "worm" or virus. It's annoying to see so many entries in my logs of where attacks have occurred.
So, one day as I was browsing other sites similar to CodeProject, I came across a snippet of code someone wrote to automatically report abuse to the ISP that owns the IP address of where the attack originated from. So, after modifying the code quite a bit to fit my needs, I got it up and running. Of course, the next thing I wanted to do was to ban these reported IP addresses from my site, hence this article.
Before I go any further, let me state that there are a few downsides with the approach I'm taking here to add additional "security" to my personal web server:
- only the "kid" hackers using daddy's computer will get caught because they don't spoof their IP addresses
- the prevalence of dynamic IPs foils the blocking of reported IPs attempting to be malicious
- This does nothing for new types of attacks since this solution is dependant on what URLScan knows.
- It's a reactive response to an attack that has already occurred.
With that said, it was still an interesting exercise.
The Catch
In order to gain access to the IIS server for my project, you have to use Windows Management Instrumentation (WMI) and Active Directory Service Interfaces (ADSI). For a general overview of these two items, refer to the MSDN website.
Since I've never worked with WMI, the first thing I did was look for examples. I found a few, but what I found were in VBScript. I'm not sure why, other than administrators wanting to write a few quick scripts to get something done or maybe it has something to do with the fact that you have to use late binding. I've had to work with objects that were late bound in ATL, and it was not fun. VB/VBScript makes it quite easy to do (which may be why I saw so many examples in VB). Anyway, I've never really had to do anything with late binding in C#, so it took me a few minutes to get acquainted with it. For those of you not familiar with early vs late binding, check here for an explanation:
http://support.microsoft.com/default.aspx?scid=http://support.microsoft.com:80/support/kb/articles/Q245/1/15.ASP&NoWebContent=1
Parameter passing and method execution are lots of fun if you're not used to it if late binding is involved.
The Code
using System;
using System.IO;
using System.Collections;
using System.DirectoryServices;
using System.Reflection;
namespace soccerwrek
{
class IISWMI
{
[STAThread]
static void Main(string[] args)
{
try
{
System.DirectoryServices.DirectoryEntry IIS =
new System.DirectoryServices.DirectoryEntry(
"IIS://localhost/w3svc/1/root");
Console.WriteLine(
"Retrieving the list of currently denied IPs.");
Type typ = IIS.Properties["IPSecurity"][0].GetType();
object IPSecurity = IIS.Properties["IPSecurity"][0];
Array origIPDenyList = (Array) typ.InvokeMember("IPDeny",
BindingFlags.DeclaredOnly |
BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Instance | BindingFlags.GetProperty,
null, IPSecurity, null);
foreach(string s in origIPDenyList)
Console.WriteLine("Before: " + s);
bool bGrantByDefault = (bool) typ.InvokeMember("GrantByDefault",
BindingFlags.DeclaredOnly |
BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Instance | BindingFlags.GetProperty,
null, IPSecurity, null);
Console.WriteLine("GrantByDefault = " + bGrantByDefault);
if(!bGrantByDefault)
{
typ.InvokeMember("GrantByDefault",
BindingFlags.DeclaredOnly |
BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Instance | BindingFlags.SetProperty,
null, IPSecurity, new object[] {true});
}
Console.WriteLine("Updating the list of denied IPs.");
object[] newIPDenyList = new object[4];
newIPDenyList[0] = "192.168.1.1, 255.255.255.255";
newIPDenyList[1] = "192.168.1.2, 255.255.255.255";
newIPDenyList[2] = "192.168.1.3, 255.255.255.255";
newIPDenyList[3] = "192.168.1.4, 255.255.255.255";
Console.WriteLine("Calling SetProperty");
typ.InvokeMember("IPDeny",
BindingFlags.DeclaredOnly |
BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Instance | BindingFlags.SetProperty,
null, IPSecurity, new object[] {newIPDenyList});
IIS.Properties["IPSecurity"][0] = IPSecurity;
Console.WriteLine("Commiting the changes.");
IIS.CommitChanges();
IIS.RefreshCache();
Console.WriteLine("Checking to see if the update took.");
IPSecurity = IIS.Properties["IPSecurity"][0];
Array y = (Array) typ.InvokeMember("IPDeny",
BindingFlags.DeclaredOnly |
BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Instance | BindingFlags.GetProperty,
null, IPSecurity, null);
foreach(string s in y)
Console.WriteLine("After: " + s);
}
catch (Exception e)
{
Console.WriteLine("Error: " + e.ToString());
}
}
}
}
In Closing
As you can see it's not terribly difficult or complicated. The hardest part of this exercise is just looking up what you need to know and putting it all together.
Currently a manager at a healthcare IT company, I've spent the last 7 years managing a variety of projects that range from web based kiosk applications to larger transaction based applications. Previously, I spent 8 years as a software engineer developing messaging, image editing, web based applications, and mainframe applications.