'****************************************************************************
' This script created by Chrissy LeMaire (clemaire@gmail.com)
' Website: http://netnerds.net/
' Modifications done by J.R. @ MicroTECH (jr@microtechusa.net) from Chrissy's
' 2006/12/18 build 
' Most notably is the If NOT section to block ANY usernames that don't match,
' or fail the password the first time.
' Yes, it is rather harsh, but security has to be sometimes. :(
'
' NO WARRANTIES, etc.
'
' This script instantly bans IP addresses trying to login to FTP
' using ANY account not authorized or fails the password the first time.
'
' Run this script on the FTP server. It sits in the back and waits for an 
' event viewer "push" that lets it know someone failed FTP authentication.
'
' This script has only been tested on Windows Server 2003. It assumes, as it 
' should, that there are no legitimate Administrator account FTP logins.
'
' "What it does"
' 1. Sets an Async Event Sink to notify the script when someone fails MS-FTP auth
' 2. When alerted, the script parses the last day's FTP logs for all FTP sites (this
'    is because the Event Viewer doesn't tell you which FTP site, if you have more than
'    one, is the one getting hit)
' 3. Compiles the list of IPs to be banned and then bans them using IIS /and/
'    IP level banning (thanks Spencer @ netortech.com for the idea)
'
' Also, remember that IPs are null-routed in the routing table! So if you need
' to remove a banned IP, run ROUTE DELETE X.X.X.X from a CMD prompt.
'*****************************************************************************
 
' Push Event Viewer Alert
    Set objWMIService = GetObject("winmgmts:{(security)}!root/cimv2")
    Set eventSink = wscript.CreateObject("WbemScripting.SWbemSink", "EVSINK_")
    strWQL = "Select * from __InstanceCreationEvent where TargetInstance isa  'Win32_NTLogEvent' and TargetInstance.SourceName = 'MSFTPSVC' and TargetInstance.EventCode = 100"
    objWMIService.ExecNotificationQueryAsync eventSink,strWQL
 
' Keep it going forever
While (True)
    Wscript.Sleep(1000)
Wend
 
Sub EVSINK_OnObjectReady(objObject, objAsyncContext)
' NOTE: Here is part 1 of 2 that you need to set. Replace the username1 and username2 with LEGIT usernames.
  If Not InStr(LCase(objObject.TargetInstance.Message),"username1") > 0 or InStr(LCase(objObject.TargetInstance.Message),"username2") > 0 Then
    Set objFTPSVC = GetObject("IIS://localhost/MSFTPSVC")
    Set WshShell = CreateObject("WScript.Shell")
    Set objFSO = CreateObject("Scripting.FileSystemObject")
    Set objLog = CreateObject("MSWC.IISLog")
    Set objDictionary = CreateObject("Scripting.Dictionary")
    Set objFTPIPSec = objFTPSVC.IPSecurity
    
    'Get IP address of server so we can use it later to give the offending IP a bad route
    Set IPConfigSet = GetObject("winmgmts:\\.\root\cimv2").ExecQuery("SELECT * FROM Win32_NetworkAdapterConfiguration WHERE IPEnabled=TRUE")
    for each IPConfig in IPConfigSet
      if Not IsNull(IPConfig.DefaultIPGateway) then serverIP =  IPConfig.IPAddress(0)
    Next
    Set IPConfigSet = Nothing
 
    'Iterate through each FTP site. See #2 up above.
      For Each objSITE in objFTPSVC
        If lcase(objSITE.class) = "iisftpserver" Then
          ftpLogFilePath =  WshShell.ExpandEnvironmentStrings(objSITE.LogFileDirectory) & "\msftpsvc" & objSITE.Name
      
          Set objFolder = objFSO.GetFolder(ftpLogFilePath)
            Set objFiles = objFolder.Files
              For Each fileName In objFiles
                lastFile = fileName
              Next
            strLogFile = lastFile
            Set file = Nothing
          Set objFolder = Nothing
          
          'Use the IIS log file parser provided by MSFT
          objLog.OpenLogFile strLogFile, 1, "MSFTPSVC", 1, 0 
            '(FileName,IOMode,ServiceName,ServiceInstance,OutputLogFileFormat) 
            ' 0 = NotApplicable, 1 = ForReading  
            While NOT objLog.AtEndOfLog
              objLog.ReadLogRecord
' NOTE: Here is part 2 of 2 that you need to set. Replace the username1 and username2 with LEGIT usernames.              
              If Not LCase(objLog.URIStem) = "username1" or LCase(objLog.URIStem) = "username2" Then 
                ClientIP = objLog.ClientIP
                  If objDictionary.Exists(ClientIP) = False Then
                      'Kill the route to the machine then add it to the array of banned IPs.
                      Set WshShell = WScript.CreateObject("WScript.Shell")
                    WshShell.Run "ROUTE ADD " & clientIP & " MASK 255.255.255.255 " & serverIP, 1, True
                    Set WshShell = Nothing
                    objDictionary.Add ClientIP, "255.255.255.255" '255 is just there for padding.
                  End If 
              End If
            Wend  
          objLog.CloseLogFiles 1
        End If
      Next
    
      'Append the newly banned IPs to the currently banned IPs  
      If objDictionary.Count > 0 And objFTPIPSec.GrantByDefault = True Then 
        bannedIPArray = objFTPIPSec.IPDeny
          For i = 0 to ubound(bannedIPArray)
          clientIP = Left(bannedIPArray(i),InStr(bannedIPArray(i),",")-1)
            If objDictionary.Exists(ClientIP) = False Then
              objDictionary.Add bannedIPArray(i), "255.255.255.255"
            End If 
          Next
          
        objFTPIPSec.IPDeny = objDictionary.Keys
        objFTPSVC.IPSecurity = objFTPIPSec
        objFTPSVC.SetInfo
      End If

  strComputer = "."
  Set objWMIService = GetObject _
  ("winmgmts:{authenticationLevel=pktPrivacy}\\" _
  & strComputer & "\root\microsoftiisv2")

  Set colItems = objWMIService.ExecQuery _
  ("Select * From IIsFtpServer Where Name LIKE " & _
  "'%MSFTPSVC/%'")

  For Each objItem in colItems
    objItem.Stop
    objItem.Start
  Next
      
    Set objFTPIPSec = Nothing
    Set objDictionary = Nothing
    Set objLog = Nothing
    Set objFSO = Nothing
    Set objFTPSVC = Nothing
    Set objWMIService = Nothing
    Set colItems = Nothing

  End If
  End Sub

