Click here to Skip to main content
15,867,594 members
Articles / Programming Languages / C#
Article

How to Programmatically add IP Addresses to IIS's Deny Access List using C# and WMI

Rate me:
Please Sign up or sign in to vote.
4.80/5 (5 votes)
31 Jul 20033 min read 159.2K   1.3K   51   25
An article that shows the basic steps to programmatically adding an IP address to the IIS deny access list.

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:

  1. only the "kid" hackers using daddy's computer will get caught because they don't spoof their IP addresses
  2. the prevalence of dynamic IPs foils the blocking of reported IPs attempting to be malicious
  3. This does nothing for new types of attacks since this solution is dependant on what URLScan knows.
  4. 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

C#
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
         {
            // retrieve the directory entry for the root of the IIS server

            System.DirectoryServices.DirectoryEntry IIS = 
               new System.DirectoryServices.DirectoryEntry(
               "IIS://localhost/w3svc/1/root");

            // retrieve the list of currently denied IPs

            Console.WriteLine(
                "Retrieving the list of currently denied IPs.");

            // get the IPSecurity property

            Type typ = IIS.Properties["IPSecurity"][0].GetType();
            object IPSecurity = IIS.Properties["IPSecurity"][0];

            // retrieve the IPDeny list from the IPSecurity object
            Array origIPDenyList = (Array) typ.InvokeMember("IPDeny", 
                       BindingFlags.DeclaredOnly | 
                       BindingFlags.Public | BindingFlags.NonPublic | 
                       BindingFlags.Instance | BindingFlags.GetProperty, 
                       null, IPSecurity, null);

            // display what was being denied
            foreach(string s in origIPDenyList)
               Console.WriteLine("Before: " + s);

            // check GrantByDefault.  This has to be set to true, 
            // or what we are doing will not work.
            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});
            }

            // update the list of denied IPs.  This is a 
            // complete replace.  If you want to maintain what
            // was already being denied, you need to make sure 
            // those IPs are in here as well.  This area
            // will be where you will most likely modify to
            // your needs as this is just an example.
            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");

            // add the updated list back to the IPSecurity object
            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.");

            // commit the changes
            IIS.CommitChanges();
            IIS.RefreshCache();

            // check to see if the update took
            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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
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.

Comments and Discussions

 
GeneralSpecified cast is not valid Pin
Ben Merrills15-Oct-03 6:16
Ben Merrills15-Oct-03 6:16 
GeneralRe: Specified cast is not valid Pin
Scott Burgett15-Oct-03 6:22
Scott Burgett15-Oct-03 6:22 
GeneralRe: Specified cast is not valid Pin
Ben Merrills15-Oct-03 6:28
Ben Merrills15-Oct-03 6:28 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.