IIS: Instantly Ban IPs Attempting to Login to MS-FTP as Administrator

UPDATE 12/18/06: The startup script has been modified slightly (cscript.exe was changed to wscript.exe). Now, console users will no longer encounter a blank black box upon login.
UPDATE 11/21/06: Now that banning at the IP level has been added to the script, offending users are completely banned before they can even attempt a second login on Windows 2003 machines. Windows 2000 machines still have a slight delay.
UPDATE 1/18/07: I updated the code so that it does not throw out an “unknown” error on line 48 for Win2k users. Thanks to the commenters for figuring that out. Also, check the comments for some really great script modification and ideas posted by blog visitors. Thanks to everyone who has posted!

Recently while reviewing my Windows Events, I noticed over 2800 failed login attempts to my Microsoft FTP server. Apparently, a bot was trying to brute force the Administrator password. Thankfully, I soon determined that there were only two IPs I needed to ban. The FTP server needs to be accessed by my employer’s clients so I couldn’t just change the port (as I did when I found 30,000+ SSH login attempts to my Linux box). Thus, I decided to instantly ban any IPs attempting to login as Administrator. I did this using a VBScript file (saved as: C:\Scripts\Startup\banftpips.vbs) that is set to execute upon boot-up. This can be done like so.


' This script created by Chrissy LeMaire ([email protected])
' Website: http://netnerds.net/
' This script instantly bans IP addresses trying to login to FTP
' using the NT account "Administrator"
' 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)

' 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)

Sub EVSINK_OnObjectReady(objObject, objAsyncContext)
If InStr(LCase(objObject.TargetInstance.Message),"administrator") > 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)
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
strLogFile = lastFile
Set file = Nothing
Set objFolder = Nothing

'Use the IIS log file parser provided by MSFT
objLog.OpenLogFile strLogFile, 1, "MSFTPSVC", 1, 0
' 0 = NotApplicable, 1 = ForReading
While NOT objLog.AtEndOfLog
If LCase(objLog.URIStem) = "administrator" 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 " & serverIP, 1, True
Set WshShell = Nothing
objDictionary.Add ClientIP, "" '255 is just there for padding.
End If
End If
objLog.CloseLogFiles 1
End If

'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), ""
End If

objFTPIPSec.IPDeny = objDictionary.Keys
objFTPSVC.IPSecurity = objFTPIPSec
End If

Set objFTPIPSec = Nothing
Set objDictionary = Nothing
Set objLog = Nothing
Set objFSO = Nothing
Set objFTPSVC = Nothing
End If
End Sub

Once the IP has been added to the ban list, the user will no longer be able to connect to the machine via TCP/IP as it has been given a bad route. If the server reboots, it will lose the route but the IP will still be banned in IIS. The offending user will then see the following message:

Connected to ftpserver
530 Connection refused, unknown IP address.
421 Service not available, closing control connection.
Connection closed by remote host.

Note that this bans the IPs on a global FTP level. You will find the banned IPs listed under Windows 2003 @ IIS -> FTP -> Properties and under Windows 2000 @ IIS -> Hostname -> Properties -> FTP Service -> Edit -> Directory Security. This means you will not find it on the properties of the Default FTP Site. This pro-actively bans the IPs from hitting other FTP sites in an IIS setup with multiple FTP sites. In addition, with the new ban at the IP level, the machine can’t even contact your server until your Windows server has been rebooted and the manual routes have thus been reset.

Chrissy is a Cloud and Datacenter Management & Data Platform MVP who has worked in IT for over 20 years. She is the creator of the popular SQL PowerShell module dbatools, holds a master's degree in Systems Engineering and is coauthor of Learn dbatools in a Month of Lunches. Chrissy is certified in SQL Server, Linux, SharePoint and network security. You can follow her on Twitter at @cl.

Posted in IIS, Security, VBScript
157 comments on “IIS: Instantly Ban IPs Attempting to Login to MS-FTP as Administrator
  1. Really useful !!!


  2. Chrissy says:

    Hey Vittorio,
    Make sure you don’t put this script into the GPO startup. Since it’s a monitoring script that doesn’t end until you kill the process, the machine hangs at “Running startup scripts…” Not too sure what the default time-out is for GPO scripts but it was too long for me. I’m going to update the blog to let others know.

  3. Spencer Ruport says:

    Thanks for this.

    Your code helped me write my own script which I now use to curb dictionary attacks.

  4. Rick says:

    Hey Chrissy,
    This snippet rocks. Thank you again for sharing.
    I would like to ask you about an ASP solution that is similar in concept…adding an IP to a specific site where the IIsIPSecuritySetting DenyByDefault is used instead of GrantByDefault. I have a IIS Web Site that is configured to use an Admin account in which NTLM auth is disabled, and an ASP login form where the user/pass is validated against a SQL record (MySQL5) — no NTLM involved period. If the user is validated, I would like the ASP script to add the IP addy dynamicaly to a couple of other web sites hosted on the same server. My WSH/WMI skills are pretty weak to say the least and was hoping maybe if you have time one day you could maybe point me in the right direction….oh hell, who am I kidding…I need code girl, plain and simple, lol. I am not beyond begging, so let me know if there is anything that maybe I could do for you. The only part I have no clue on is the WSH/WMI interaction with IIS to accomplish this specific task.
    Shouts from the Mississippi Delta!

  5. Jeri Morris says:

    Looks like an excellent script–thank you for posting it!

    I’d like to get this running on my Windows 2000 server. I’m not familiar with Group Policy objects or startup scripts (other than reading the Windows 2000 help, which isn’t too helpful). Can you suggest how to install the script on a Windows 2000 server so that the script runs asynchronously and doesn’t hang the system on reboot?

    Thanks again,


  6. Steven De See says:

    You are a lifesaver. After logging upwards of 10K attempts at administrator logins from ~12 different IP’s we needed something to combat the inherent stupidity of being locked out of logging into the server as administrator because some other clown(s) was banging away illictly at that server!

    Two questions, one dumb & the other hopefully not so:
    >how do I tell that it’s actually working?
    >how can I add this BANIPFTP functionality to a couple other usual suspects (“admin”, “guest”)? Duplicate the section of code starting with ‘Sub EVSINK_OnObjectReady(objObject…’ and sub the desired name? Of couse it’s not a big deal because these logins don’t exist and/or are securely disabled, but would still like to ban the uninvited.

    Many thanks,

  7. Steven De See says:

    p.s. I asked the dumb “how do I know…” question because after a dry spell of no attempts there was a recent dictionary attempt by someone and the first few hundred logins attempted was with “administrator” (then ‘admin’, ‘guest’, etc.) – I was suprised that this attempt was able to continue after first trying with ‘administrator’

  8. Chrissy says:

    Hey Jeri,
    You can add it to the startup registry. http://blog.netnerds.net/code/startup.txt lists how to do it though I don’t know if Win2k supports “reg add” if not, just add it using regedit.

  9. Chrissy says:

    Hey Rick,
    That’s completely doable. I’ll think about it and get back to you.


  10. Chrissy says:

    Hey Steven,
    first, to add other users, just add to the following line

    If InStr(LCase(objObject.TargetInstance.Message),”administrator”) > 0 Then

    So in your case, that line would say

    If InStr(LCase(objObject.TargetInstance.Message),”admin”) > 0 or InStr(LCase(objObject.TargetInstance.Message),”guest”) > 0 Then

    Also, make a similar change on the objLog.URIStem line…

    Since the “instr” doesn’t look for exact matches, “admin” would work for both admin and administrator.

    To see if its running, go to Task Manager and order by name. Look for Wscript.exe ..if you see that running, it may be this script.

    To see if it’s working, go to IIS -> FTP -> Properties -> Directory Security.

    For the record, on ONE of my machines.. there was a delay in IIS enforcing the policy. It took about 4 hours and then hasn’t had a problem since. Weird!

    EDIT: I took a snapshot of the wrong location. It should be under Windows 2003 @ IIS -> FTP -> Properties and under Windows 2000 @ IIS -> Hostname -> Properties -> FTP Service -> Edit -> Directory Security. This means you will not find it on the properties of the Default FTP Site.

  11. Chrissy says:

    Hey Jim,
    I ran this on the new domain controller though you should be able to run it on any computer that both domains trust.

    You are right about the TheDomain, I changed the object name to be more representative in one place and forgot to change it in the other. I've updated the script.

    Let me know how it works for you!

  12. Rick says:

    Hey Chrissy, I am experiencing an anomaly I have been unable to solve with the startup method of your script on a server I manage remotely…it works fine on my VMWare instance that I initialy tested the script on, but I logon to it local.

    I used the “reg add” method you posted, double-checked the paths and NTFS perms, but on the remote server the script does not appear to be running until I login via RDP, and then terminates when I logoff of the remote server…at least it appears to be so…I mean, I tried to login to FTP as Administrator and it never banned my IP addy and I waited for a day as I see in your comment above that sometimes it might take a while for it to appear under Directory Security.

    The remote server is not part of a domain (workgroup only), and is running 2003SE+all current patches.

    Penny for your thoughts?


  13. Rick says:

    Ok Chrissy, I can be a little scatter brained sometimes…I was lloking at the Default FTP Site properties instead of the FTP Sites Master Properties…there I found the Denied IP addys I have been testing with.
    Thanks again for this wonderful script!
    Best Regards,

  14. MK says:

    Hello Chrissy,

    I had tried the script, but I had encounter some problem after run the seript. So I don’t have any idea what is the error.

    It show :

    Script: c:\baniisadm.vbs
    Line: 28
    Char: 5
    Error: Access denied

    Code: 80041003
    Source: SWbemServices

    Thanks in advance,

  15. MK says:

    Sorry, I had missing some information, I had test it in the Server2000 /wSP4 and under a Domain (Server2003 Std)

  16. chris says:

    I copied the sctript to notepad as saved as vbs then ran it on server 2003 sp1 and i get a error.
    (96,1) Microsoft VBScript compilaiton error: Exspected ‘End’
    Any Ideas?

  17. chris says:

    Added…At the end of the script I needed to add ‘End Sub’ on a new last line, line 96. All works GREAT now and initialized as soon as I ran it with a CMD window. As you guessed, this script can manually be run with a command promt minimized (suggested for testing to minimize the restart times). Now the big test will be if these idiot attackers have thier bots set to realize their IP’s are blocked and the attacks stops there.

  18. vern says:

    Chrisy: I got hit hard the other day and none of the offending addresses were banned.

    I made some additions to the words to check similar to what you showed Stevan above, but nothing was checked.
    Here’s what I changed;
    If InStr(LCase(objObject.TargetInstance.Message),”admin”) > 0 or InStr(LCase(objObject.TargetInstance.Message),”user”) > 0 or InStr(LCase(objObject.TargetInstance.Message),”tomy”) > 0 or InStr(LCase(objObject.TargetInstance.Message),”guest”) > 0 or InStr(LCase(objObject.TargetInstance.Message),”Www”) > 0 Then

    Does that look ok?

  19. vern says:

    Is there anyway to have a whitelist of acceptable userames and everything else gets banned?

  20. vern says:

    Something else I was thinking about that could (I think) use part of this code; add those same IPs to the www service ban list, and, perhaps even more importantly, the SMTP Virtual Server Connection Control Deny list(s).

    Or just add it to the Global Settings Message Delivery Connection Filtering Deny list…

    Whatcha think?

  21. Andy says:

    Cool script – thanks. It’s added an internal ip to the ban list after logging in from the lan (to test) but I can still connect to the ftp server and get a login prompt which I wasn’t sure should happen.
    I’m going to try a bit more debugging to see whats going on.

  22. Sean says:

    I am getting the same access enied error, any thoughts on why?

  23. sam says:

    Hi Chrissy.

    This script is just what I need – thx! Having a problem with it, tho. It seems to be runing (I see the script process), but it doesn’t ban my test IP- even after waiting the “four hours” you observed.

    Few questions: what format does the log file need to be in? Mine is set for daily using W3C Extended. Also, does it matter if I have added a few ‘deny’ IP’s manualy?

    I’m running Windows Small Business Server2003 Standard.

    Thank for any help…

  24. Phi says:

    Hello Chrissy,

    Thanks for sharing with us your very nice script. :)

    I’m just wondering if the script is to handle multiple login accounts, e.g. admin and guest, shouldn’t this line be changed too?

    If LCase(objLog.URIStem) = “administrator” Then

    Btw, if the script can be modified to block IP only if that particular IP has entered the wrong password for, say 6 times withing 10 minutes, that will be awesome. :)


  25. Chrissy says:

    Whoa, lots of responses! Sorry I haven’t been on the ball, guys.. I’ve been slammed at work and schoool.

    Right off the top of my head..not sure what the access denied error is about. As for the lag in enforcing the IP ban, someone said rebooting IIS fixed their prob. That’s not a solution, of course..but it may mean I’m missing one finalizing line from my code. I’ll check around it when I can. That was the mysterious “four hours” i spoke of..I probably restarted the service at some point.

    And Phi, you are totally right. I’ll update my comment to reflect that. Thanks!

  26. john andrews says:

    Very nice script Chrissy, thank you for posting this. Just installed on win2k3 SE SP I with much sucess. Kudos is also due to those who listed the multi username catch mods.

    Quick question… is there an easy way to supress the cscript.exe window from loading? Everytime I RDS into the server a blank cscript window pops up.

    Thanks Again,
    John Andrews

  27. Mike says:

    If LCase(objLog.URIStem) = “administrator” Then

    Can someone please post the modified version of this line to include multiple login names? I made a few attempts and can’t seem to NOT screw it up.

  28. G says:

    Access denied error (80041003): I got this error on a Windows XP machine. The problem was that the Win32_NTLogEvent class needed the wbemPrivilegeSecurity (SeSecurityPrivilege) privilege to be enabled. Change the moniker string:

    Set objWMIService = GetObject(“winmgmts:{(security)}!root/cimv2”)

    Unfortunately, Chrissy’s script doesn’t work on Windows XP. It contains IIS 5.1, which doesn’t support denying IP addresses (as far, as I know).

  29. Sean says:

    G … That worked perfectly.

    Now I get the same behaviour as others have reported which is that the newly banned ips do not take effect immidiately. I verified that they are on the list and when I restart the FTP service they take affect .

    I just added a script to restart the FTP service every night which seems to work.

  30. Jim says:

    Well this would be great but my FTP runs on a Win 2K Server. Im not sure this works on 2K.

    I cant seem to see the process running, and IPs dont seem to be being banned even after the restart of the service.



  31. Phi says:

    Mike, here’s my modified version to include multiple login names:

    If InStr(LCase(objLog.URIStem),”admin”) > 0 or InStr(LCase(objLog.URIStem),”guest”) > 0 or InStr(LCase(objLog.URIStem),”root”) > 0 or InStr(LCase(objLog.URIStem),”test”) > 0 or InStr(LCase(objLog.URIStem),”user”) > 0 Then

    Does anyone know how to use a script to auto restart the FTP service when there is no active connection?

  32. Tomas Krug says:

    objDictionary.Add ClientIP, “” ‘255 is just there for padding.

    This line dosnt add the IP to the blocked list… anyone have any idea what can cause this? I am running this on an w2k3 EE SP1 Server with lots of s/w installed.

    The variable ClientIP contains the correct IP.

    Tomas Krug
    Stockholm, Sweden

  33. Chrissy says:

    They Thomas,
    You are right, that line doesnt add the IP to the blocked list. It just adds it to the dictionary when then adds the IP to the blocked list.

    objFTPIPSec.IPDeny = objDictionary.Keys is the line that actually does the work.

  34. Chrissy says:

    I swear I’ll find the way to add those IPs for good w/o restarting.. I just havent had a chance to look. Worst case, I’ll ask the Scripting Guys.

  35. Randy says:

    I love the ftp anti-hack script…but let’s take this to the next level. The script currently doesn’t stop them from hammering and generating huge logs, or from trying to hack anything else on the server. How would you modify the script to ban them from even connecting to the server in the first place? I am guessing that the script would need to be changed to add the offending IP address to the denied list in the Routing & Remote Access?

    Thanks for the great script. :)

  36. Clayten says:

    Great script! Running it as a service using srvany.exe utility so I don’t have to leave the server logged in. The IP’s aren’t banned unless I restart my FTP server so I put this at the end of the script.

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

    Set colItems = objWMIService.ExecQuery _
    (“Select * From IIsFtpServer Where Name LIKE ” & _

    For Each objItem in colItems

  37. Phi says:

    Thanks Chrissy. I admire your persistence and will be looking forward to your solution.

    Meanwhile, have fun! :)

  38. sam says:

    Clayten, where exactly in th script did you add your “restarting” code?

  39. Dan says:

    Hey everyone! I used this idea plus a lot of modification to create a windows service which does this and a little more. Let me know what you think!


  40. Clayten says:


    Add it between the:

    End If

    Set objFTPIPSec = Nothing
    Set objDictionary = Nothing

    in Chrissy’s code.

  41. Todd says:

    Wouldn’t your stop and start code eject any users that were currently connected to the FTP service?

  42. sam says:

    Thx Clayten. That works, but there seems to be a delay in the time it takes the service to restart, sometimes 1-2 minutes. Of course in that time, the newly-detected IP is not banned, and dozens more attempts are allowed.

    Any idea what may cause the delay??

  43. Andie says:

    Anyone get this working with windows 2000?


  44. Clayten says:


    I happens to me as well. Attackers normally get about a dozen or two tries before they are locked out.

    If I had to take a guess, that 1 or 2 minutes is the time it takes for the Event to get logged to trigger the script (if you do a lot auditing it has to wait in line), processing your entire log file for the day (which could be big), then restarting the ftp servers.

    If Chrissy can find out how to ban IPs instantly that will solve the delay.

  45. Chrissy says:

    Ahhh! You know.. Clayten .. I think I may have just figured out a solution.

    First, you got me thinking.. IIS Log files take a little bit to write from memory to disk…perhaps that is where the delay comes in? But I wonder if the MSWC.IISLog object can read “unwritten” data.

    If it does, what I can do is combine Spencer Rupert’s script with mine to temporarily create a bad route to the offending IP address which will stay in effect (I’m guessing until the next reboot) at least until the FTP server catches up.

    I tried newsgroups for a way to solve that delay but received 0 responses. Perhaps I should get around to writing to David Wang. Till then, I’ll rewrite the script and add that in then email you guys with the new script.

  46. Chrissy says:

    Hey Guys,
    Okay, the script has been retooled and it now stops attackers before they can even login a second time.

    The modifications I made was to figure out the server’s IP address (so that Spencer’s fakeGateway variable wouldnt have to be manually set) then use that to add a route to the IP routing table that instantly kills off the attacker’s packets. While Spencer’s script writes all the IPs to a batch file for permanent banning, I decided to just take my chances and do a “temporary” ban. How temporary? Depends on how often you reboot. So if you go for a year without rebooting, then the bad route will last for a year.

    So for the record MSWC.IISLog reads data that is still unwritten to disk. This script now works so quickly, that again, I couldn’t even get a second login attempt in when testing.

    When implementing the new script at work, I also randomly ran into the access denied error that another commenter encountered. Thankfully “G” solved that by suggesting that the the WMI object string change slightly. That worked wonderfully and I’ve modified the original script to reflect the change.

    I didn’t add the IIS restarter script that Clayten so graciously posted because I didn’t want to chance kicking off legit users. Hopefully the IP level ban will take care of that time delay.

    Now to figure out the slickest way to get this going each time the computer boots up. The run key works but my coworkers who login to the console always see a black box. Not cool.

  47. Clayten says:


    I figured you’d find a better way and render my restart part moot. :-) Thanks again for the script! Note: Running the script as a service eliminates the black box.

  48. Mike says:


    Thanks so much for posting this script. We have been getting pounded by login attempts and this has really helped.

    Your excellent solution is greatly appreciated.

    Thanks again, Mike

  49. Gaelan says:

    I am a total nube to this so excuse my nube issue but I get Microsoft VBScript runtime error: Object required: ‘WshShell’
    when running the script. The machine is running server 2003 SE. Can anyone shed some light here

  50. DIV says:

    This looks like a kickin script to get running… been looking for a solution like this … does anyone have the source for the new script crissy was talking about I would like to take a look.. also has anyone tried to script in some variables so that you could possibly set a attempt limit instead off banning them if they get it wrong the first time … typos can really suck in that case and sometimes half asleep at the keyboard it does happen ;)

  51. Gaelan says:

    OK ignore my question. It works, I was broken. Chrissy YOU ARE MY PERSONAL HERO!!!!!
    I cannot express in words how unbelievably awesome this script is. YOU ROCK!

  52. Charles says:

    Takes a lot to impress me.. I’m impressed..

  53. Dave Savage says:

    Thanks for this script! I was getting hit everyday with so many unauthorized login attempts that it was avg. 4 attempts every SECOND!!! Not anymore!! Saweeeeeeeeeeeeeeeeet!

  54. Jim says:

    One problem I had with this script is that if you don’t have a folder called “MSFTPSVC1” in “%WinDir%\System32\LogFiles” you will receive the Object required: ‘WshShell’ error that Gaelan received just above. If you create a dummy folder with that name the script will run without error.

    If I had to guess, I would say this is because the script assumes that the log file location hasn’t changed for the Default FTP site. If it has, it errors out before even getting to the second FTP site. (But I’m no scripting expert.)

    If anyone is wondering; If you are testing this script and it does lock your IP address out, you can simply run “route delete ” in a command prompt and you will be allowed again for further testing.

  55. Jim says:

    To add to my previous post, you have to type “route delete xxx.xxx.xxx.xxx”

    Also, if your running a Windows 2000 server and the command-line tool “reg” isn’t available, you can copy and past the following into a text file, rename it to a .reg extension, and run the file:

    Windows Registry Editor Version 5.00

    “banftpip”=”C:\\WINDOWS\\system32\\wscript.exe C:\\WINNT\\SYSVOL\\sysvol\\biomedix.local\\scripts\\banftpips.vbs”

  56. Jim says:

    Sorry, I forgot to tell you to rename the path in the last part of that .reg file.

  57. Chrissy says:

    Thanks Jim.

    Clayten, I’m getting a delay on my Windows 2000 machine.. I was all confused thinking the delay was at the IIS end. It is indeed on the Event service end. I don’t really think there’s a way to get around that other than “tailing” the log file forever and that seems to be way more overhead. Perhaps Vista and Longhorn will have some better solutions!

  58. Rogue says:

    I installed the above script on 21/12/06 so I assume this is the latest evolution. (script “retooled” 21/11/06)….unless the above is not the “retooled” version of the script.

    If it is….
    I have it working fine in winK2 and between 21/12/06 and 02/01/07 it banned some 15 IP’s. The problem remains, however, that the attacks can last up 20+ minutes and all of the “premier attack period” is still reflected in the log …some times as many as 2 per second. The attacker may only get one shot but the “shot” is still lasting quite awhile.

    If the above isn’t the “retooled” version of the script and the new version really stops the attacker from a second log on (not just a second attack) where can a copy be obtained? mucho thanx

  59. Chrissy says:

    Hey Rogue, I tested it on Windows 2003 and the ban is instant but that doesn’t seem to be the case on the Windows 2000 machine I tested on. Not sure at this point how to speed things up.

  60. niTz says:

    i just tried this script and when i attempt a logon with adminstrator from another computer. my server pops out an error about the vbs script

    Line: 57
    Char: 11
    Error: Path not found
    Code: 800A004C
    Source: Microsoft VBScript runtime error

    im pretty nub on scripting any help would be great

  61. Chrissy says:

    Hey Nitz,
    You changed the default path for the FTP logs.. line 57 is this

    ftpLogFilePath = WshShell.ExpandEnvironmentStrings(objSITE.LogFileDirectory) & “\msftpsvc” & objSITE.Name

    just change that to whatever the path of your FTP logs are.. ie

    ftpLogFilePath = “D:\Logfiles\FTPSite”

  62. Chrissy says:

    Btw. this script WILL ban IPs on XP. As it turns out, IP banning works in XP programatically — just not in the GUI. Awes!

  63. niTz says:

    thank you so much Chrissy that worked =)

  64. Anthony says:

    Chrissy, first of all great work on this very handy script. thank you. I am wondering if you can figure out why normal ‘user’ users logging in over terminal services get this error pop up:

    line 27
    char 5
    Access denied
    source swbemservicesex

    & how to correct it? Thank you! :)

  65. Josh says:

    Has anyone tested the script with a FTP site that logs to a SQL DB? We currently log the site to a DB for better reporting. It gets huge from the attacks but that is how the powers that be want to log. This is the perfect script to help me but will it still work with a DB?

  66. Theo says:

    Thanks for this great script Chrissy! It works like a charm. I’ve got it running on WinXP-SP2 IIS 5.1…flawlessly. It blocks IPs as if the door is slammed! I’ve been looking for a tool like this for ages. Thanks again!

  67. Louay Farag says:

    Why not just rename the default administrative account “Administrator” to another name??

  68. Chrissy says:

    Louay, for a number of reasons. No administrator account should have a password easy enough for any of this bots to crack. Thus, I’m not concerned about a cracked password. I’m concerned about intense resource usage by thousands of attempted logins per minute as well as the Event Viewer getting so filled up.

  69. David says:

    Thanks for the code!

    I am having some problems with it though. I adapted it to ban any IP that used any unknown username (I have a security group that has valid usernames). It works for the first ban, then doesn’t catch events from the even log anymore until I restart it the script.

    I have been running the script as a scheduled task to run at system startup, but the behavior is exhibited if I run it directly from the shell or from the task scheduler.

    Has anyone seen this behavior?

  70. David says:

    I guess my post above this one is a bit off. Eventually, the event’s get processed but there is quite a large delay in when they get processed.

    Has anyone seen this?

  71. Patrick says:

    Awesome, thank you so much, this works perfectly right out of the … uhh… “box”. It stopped 2 attackers within 5 seconds of being launched.

  72. Mat says:

    Nice script!

    I too am having the speed issue… Im running on Windows 2000. It eventually does catch the offending IP address, but not before the attacker has been allowed hundreds or thousands of administrator login attempts. Has anyone resolved the speed issue on W2K?

  73. David says:

    I forgot to mention, I am running Windows 2003 Standard SP1.

    Still have the delay. Sometimes it’s as short as 5 seconds, sometimes it’s 5 minutes. It has something to do with the timing of that event being generated that triggers the meat of the script.

    I wonder how we can control that?

  74. Bob Marley says:

    Thanks a TON for this. I’ve been routinely going through our logs and manually banning IP addresses as they show up. As someone mentioned above, I’ve combined this script with srvany.exe. Just make sure you use CScript.exe to execute it, otherwise you’ll get an error when you try to start the service.

    Thanks again, this works great. I actually saw one of the bots get banned as I was messing around with it. :)

  75. Frijoles says:

    (This is the Bob Marley guy above :) )

    I posted an article on your script on my own blog, mainly how to turn it in to a service (I send them here to get the script and read about it):


    This is a step-by-step instruction guide on how to make it run as a service. Thanks again!

  76. insidejazz says:

    First , thanks Chrissy for the usefull script.
    I’ve a questiom :) we work with plesk and we have multiple ftp sites also log directories.like ;


    How can i set or is it possible to set multiple log directories ?
    thanks again…

  77. afterburn says:

    The event is fired from NON-root FTP site. The result is that it gets the directory for the logs from the wrong site Id.

  78. MrFurious says:

    Uh oh…

    I got this successfully working on my IIS 5.0 Windows 2000 Professional Box (Sp4). It blocks IPs wonderfully, but I can’t seem to remove them. Unfortunately, even after a reboot I cannot remove entries from the denied list. I’ve manually tried removing it from the routing table at the command prompt with:
    route delete

    It has removed it from the table, but even then it still appears under directory security tab as denied. Unfortunately, in 2000 Professional the Directory Security table is all grayed out, so I cannot click on the entry and select remove! I’m stock with an IP I don’t want to block.

    Like an idiot, I tested this out with my home box and now can’t get into my FTP site. :x Any suggestions?

  79. afterburn says:

    no you can use

    route -f

    this is the incorrect method to do this.


    it is the correct method. I am sorry but i would rather have it added to IIS where it is easy to manage, rather than using routing. It would have been nice to use IPSec instead for this peice of code. but i created it to go to the MSFTPSVC node in the metabase it works well.

  80. Chrissy says:

    afterburn, thanks for the pointer about it firing from a non-root site. When I get a chance, I’ll adjust the script to handle situations with multiple FTP sites or sites with non-standard ftp logging directories.

    As for the routing, if you don’t want it, you can remove it. The script bans at the IIS level in addition to the routing level. Route banning was added to this script because people were experiencing delays with pure IIS banning. And while IPSec would be nice, it’s also a pain to work with. If you’ve got easy code, please feel free to post.

    As for Mr. Furious, anyone with win2k workstation or xp pro that experience similar problems can do one of two things
    1. Backup the metabase before trying the script, and replace it if necessary (which is what he ended up doing)
    2. Use scripting to add/remove ips as can be seen here.

  81. afterburn says:

    Const c_strDomainControllerName = “DomainServer”
    Const c_strServerName = “WebServer”

    Dim objDsIpSec
    Set objDsIpSec = CreateObject(“ExIpSec.ExIpSecurity”)

    objDsIpSec.BindToSmtpVsi c_strServerName , “1”, c_strDomainControllerName

    redim Preserve objDsIpSec.IpGrant(UBound(objDsIpSec.IpGrant)+1)

    listGrant(UBound(objDsIpSec.IpGrant)) = “”


    set objDsIpSec = Nothing

  82. Chrissy says:

    Hey afterburn,
    Thanks for posting the code. I thought you were referring to IPSec at the network level. This looks like IP Security at the IIS level, specifically SMTP. I’m not sure how it relates to banning at the FTP level.. In my script, I used objFTPSVC.IPSecurity to accomplish that.

  83. Rewesh says:

    Thanks for the script however i have some questions
    1-is the new script the one that is published at the top of this blog. if not where is it?
    2- i have tried to unban an IP with the script the you listed but it is not working.
    3-While there is a banned IP , and has been removed form the security directory of the default site, this ip still can not connect and your script does not list this ip before or after the manual removal.
    4- What about the specific times of logging instead of the second time.
    The script is running on w2k sp4 with IIS 5.0.

    Thanks for the great script again…you are doing an awesome job

  84. Chrissy says:

    Hey Rewesh:
    1. Yes
    2. Not sure why.. but I’ve only tested this on win2k3.
    3. It bans the IP both at the IIS level and the network level. To remove from the network level, run cmd then type route DELETE ip.add.res.s
    4. Not sure what you mean by that

    As for running it in win2k, I don’t think the script works as well under win2k.. the events are slower to register.

  85. Dan says:

    Why don't you just download the Windows Server 2003 resource kit from Microsoft? It contains the Command Here utility and installs without any issues in Server 2003.


  86. Don says:

    Can someone explain what makes the route added in the code a “Bad Route”?

  87. Tim says:

    Hi Chrissy (and all)….

    I’ve installed your script as a service (as detailed above). The network level IP block works GREAT. Instantaneous.

    It’s been HOURS now since my tests, and still no sign of any IPs in the FTP blocked IP listing. I’ve looked at the Global level and the Default website level and… nada.

    Can you give me a clue what I might do to troubleshoot this?

    PS…. you’re hot! Your script is hot! If I can get this working right, you’re my HERO forever!!! And you’re my hero right now just for the part that IS working!!!!!

  88. CrimsonSmear says:

    Chrissy, thank you for the awesome script!
    Frijoles, thank you for showing how to add as a service.

    I’d never tried vbs before yesterday, very cool stuff.

    Thought I might share the script I whipped up for unbanning. It’ll show you the banned IPs and let you unban single IPs, as I haven’t figured out how to make it ‘purge’ the list… yet.

    strComputer = “localhost”

    ‘Set Objects
    Set objFTPSVC = GetObject(“IIS://” & strComputer & “/MSFTPSVC”)
    Set WshShell = CreateObject(“WScript.Shell”)
    Set objIPRestrict = objFTPSVC.IPSecurity

    arrDeny = objFTPSVC.Get(“IPSecurity”).IPDeny
    For i = 0 to Ubound(arrDeny)
    strBannedIPs = strBannedIPs & arrDeny(i) & vbCrlf

    If len(strBannedIPs) > 0 Then
    strUnbanIP = InputBox(“IP, Subnet: ” & vbCrLF & strBannedIPs ,”Banned FTP IP List”,”Enter IP To Unban”)
    arrIPAddresses = objIPRestrict.IPDeny
    For i = 0 to ubound(arrIPAddresses)
    strClientIP = Left(arrIPAddresses(i),InStr(arrIPAddresses(i),”,”)-1)
    If strClientIP strUnbanIP Then
    If Len(strStillBanned) = 0 Then
    strStillBanned = strClientIP
    strStillBanned = strStillBanned & “,” & strClientIP
    End If
    End If

    WshShell.Run “ROUTE DELETE ” & strUnbanIP
    arrStillBannedIPs = split(strStillBanned,”,”)
    objIPRestrict.IPDeny = arrStillBannedIPs
    objFTPSVC.IPSecurity = objIPRestrict
    msgbox “No IPs have been banned.”,,”Banned FTP IP List”
    End if

    ‘Kill Objects
    Set objIPRestrict = Nothing
    Set WshShell = Nothing
    Set objFTPSVC = Nothing

  89. Chrissy says:

    Hey Crimson,
    You’re totally welcome! I remember the first time I made a .vbs file and ran it, I was freakin pumped. I knew ASP but never understood how to run VBScript on a workstation as opposed to an IIS Server.

    Thanks a ton for pasting your code too. Very useful!


    That has a purge script that may help you.

  90. Chrissy says:

    You’re hot too!

    I really don’t know why it works instantly sometimes, within X minutes other times, then X hours other times. Thats one of the reasons I added the ban at the network level.

    Yeah… I’ll update the blog if I ever find out ;)

  91. CrimsonSmear says:

    I have a feeling that you’re looking in the wrong spot for the bans.
    Don’t look at the Default FTP Site-Properties-Directory Security, instead look in the FTP Sites “Folder”-Properties-Directory Security for your banned IPs.
    My .vbs script (above) will unban single test IPs from FTP Directory Security and the Route List, giving instant access again.

  92. Tim says:

    Crimson… Nope: I don’t think I’m looking in the wrong spot. I’ve checked the top level FTP Sites FOLDER properties-Directory Security tab too. No banned IPs ever show up.

    Chrissy: It’s been DAYS, and no IPs have shown up. I can only assume there is something wrong with my install. I’ve done ftp tests numerous times from several different machines. I DO get banned instantaneously. But I never get ANY IPs in the banned IP list.

    Any ideas what else it might be?

  93. Chrissy says:

    Ok….. Let’s see.

    1. Make sure there’s no on error resume next in there so that if an error comes up, you’ll be notified
    2. Run this script and see if anything shows up

    strComputer = “localhost”

    ‘Set Objects
    Set objWebSite = GetObject(“IIS://” & strComputer & “/MSFTPSVC”)
    Set objIPRestrict = objWebSite.IPSecurity

    arrDeny = objWebSite.Get(“IPSecurity”).IPDeny
    For i = 0 to Ubound(arrDeny)
    strBannedIPs = strBannedIPs & arrDeny(i) & vbCrlf

    If len(strBannedIPs) > 0 Then
    msgbox “IP, Subnet: ” & vbCrLF & strBannedIPs
    msgbox “No IPs have been banned.”
    End if

    ‘Kill Objects
    Set objIPRestrict = Nothing
    Set objWebSite = Nothing

    3. If that doesn’t work.. I have no idea :|

  94. Tim says:

    Thanks Chrissy…

    Your script showed NO banned IPs. But there WERE banned IPs for the network because I couldn’t connect from two test machines at all until rebooting.

    Interestingly… I started taking apart your original script and found that if I remove the network ban code, then the FTP banned IPs show up just fine. But, if I add in the network ban code, the FTP banned IPs do NOT show up. So, there must be something going wrong right there… at least for my machine.

    Anyway… The FTP banned IP list works instantly for me, so I’ve removed the network ban. This gives me the ability to “manage” the list better than for the network bans.

    Finally… I’ve added a couple of lines to auto-delete ftp logs older than X days.

    So.. for now, for what I need, it’s all working like a charm. I’m eternally in your debt. Feel free to call on me anytime for anything.

    Warm regards…


  95. Chrissy says:

    Hey Tim,
    That’s really interesting. Can you do me a favor and add the network banning back /after/ the IIS ban? Let me know if that works?

    Hopefully this will all be easier with IIS 7…

  96. Tim says:

    Hi again Chrissy…

    Putting the network ban AFTER the FTP ban works for me.

    But I did something else at the same time, so I’m not certain which change did the trick….

    I noticed that in the first few lines of the EVSINK sub, you create all the objects, one of which is the line…

    Set WshShell = WScript.CreateObject(“WScript.Shell”)

    You use this object to get the FTP log file path.

    Later you recreate the same WshShell for the network IP ban.

    Could the re-creation of the object perhaps be the problem. You don’t destroy the previous WshShell object anywhere in your code before this.

    I removed the 2nd WshShell creation code, and also moved the Set WshShell line to the bottom of the code where you destroy all the other objects.

    And now… it all seems to be working in harmony!


    PS… can you possibly give me some guidance for how I would add this IP to existing IPSec settings?

    I’ve added a list of banned IPs to the IPSec “Security Settings on Local Computer” under a folder I created called “FireWall”. I would MUCH rather add the Banned IPs to this list rather than do the network ban to the route table.

    Any suggestions?

  97. Don says:

    I added the following code to email me when an FTP attack occurs. Put it right after the ” WshShell.Run “ROUTE ADD ” & clientIP & ” MASK ” & serverIP, 1, True” statement.

    strFrom = “[email protected]
    strTo = “[email protected];[email protected]
    strSub = “FTP Attack on FILESERV”
    strBody = “FTP attack on Fileserv by IP ” & clientIP
    strSMTP = “”
    set objEmail = CreateObject(“CDO.Message”)
    objEmail.From = strFrom
    objEmail.To = strTo
    objEmail.Subject = strSub
    objEmail.Textbody = strBody
    objEmail.Configuration.Fields.Item(“http://schemas.microsoft.com/cdo/configuration/sendusing”) = 2
    objEmail.Configuration.Fields.Item(“http://schemas.microsoft.com/cdo/configuration/smtpserver”) = strSMTP

  98. Don says:

    Bob – Thanks for the heads-up on the email bug. Because the “bad route” step doesn’t seem to work for me, I was greeted by 30,000 emails this morning!

  99. Preston says:


    You are awesome!! Thank you so much for script. It worked like a charm.

  100. MJ says:

    Stellar! Trying it out now.

  101. michelle says:

    I just installed this and it’s not banning (2003 sp2). I’m getting the Object required: ‘WshShell’ error. I saw that someone suggested creating a MSFTPSVC1 directory to fix the error, but I already have that directory. Are there any permissions I might be missing?

    Tim’s solution looked interesting, but I didn’t quite understand what his final file looked like – Tim, if you’re there – can you post?


  102. JKPCHEWY says:


    The script is great but I have run into a problem where not all of my FTP sites follow the msftpsvc naming. I could create a script for each FTP site that is in a sub directory of logfiles but that would be to hard on the system. Will there be an update that will loop through the logfiles directory pulling logs for each subdirectory? Hope this question makes sense.


  103. Eric Greer says:

    Thanks tons for writing this, and thanks tons for answering my emails so helpfully!

    I created a psexec installer package for this that runs with a batch file. Basically that means you can deploy this to lots of remote computers on your network easily with one swoop. Check it out here on my blog: http://blog.integrii.net/?p=18

    Tons of thanks to Chrissy!

  104. Tim says:

    I’ve posted my current solution on our website (I can’t seem to get this site to accept my code without cutting it short).

    See it at http://www.vizimetrics.com (Ban FTP Logins).


  105. Ralph says:

    Sorry – I’m trying to understand this code and … why, exactly, does the code to add the client’s ip to the routing table (as the destination) with the server’s ip as the gateway result in the client being unable to connect to the server via TCP?
    I thought you could use the routing table to block access TO a destination, not FROM a client. And, is the serverIP supposed to be an unused address in the local network, or my actual server IP (which wouldn’t seem to work).
    Thanks a million, and thanks for posting this code in the first place.

  106. James says:

    Strange this is one of the few websites I could find on the internet that addresses this problem at all and Ive done all kinds of searches.

    Thanks to the ideas on this site, I got the idea to block the ips on our cisco firewall.

    if anyone is interested in persueing this method, I downloaded sock.dll from

    and another file, winsck.ocx from here

    so I could vbscript a telnet session.

    Instead of creating an event alert, I used a scheduled tasked to check the last log every couple of minutes. The alert does stop the hacker faster though.

    I used a 2nd script to clear the blocked ips once a day since our hackers seem to use a different ip everyday. The nice thing about blocking at the firewall is it completely stlops the IP from doing anything, including FTP. Cisco firewalls have a shun command that does this, and I would think most other firewalls have a similar command.

    The full script is below.

    Const NotApplicable = 0
    Const ForReading = 1
    Const ForWriting = 2
    Const ForAppending = 8
    Const AllOpenFiles = 32

    strScriptLogFile = “\\server01\schedule\shunIPs\shunips.log”
    strIPS = “\\server01\schedule\shunIPs\bannedips.txt”
    strFtpLogFilePath = “\\server01\c$\windows\system32\LogFiles\MSFTPSVC392258225”

    ‘Get the last log file
    Set objFSO = CreateObject(“Scripting.FileSystemObject”)
    Set objFolder = objFSO.GetFolder(strFtpLogFilePath)
    Set objFiles = objFolder.Files
    For Each fileName In objFiles
    lastFile = fileName

    strLogFile = lastFile
    ‘strLogFile = “\\server01\schedule\shunips\test.log”
    ‘wscript.echo strLogFile

    Set objFiles = Nothing
    Set objFolder = Nothing

    ‘read in a list of IPs that are already banned so we dont keep banning the same IPs
    set bannedips = objfso.OpenTextFile(strIPs, ForReading, True)

    Set objDictionary = CreateObject(“Scripting.Dictionary”)
    Do While not bannedips.atendofstream
    strIP = bannedips.readline
    if NOT(strIP = “clear”) AND NOT(strIP=””) then
    objDictionary.add strIP, “bannedIP”
    end if


    ‘re-open the bannedips list so we can possibly add to it.
    set bannedips = objfso.OpenTextFile(strIPs, ForAppending, True)

    ‘open the log file and see if anyone is hacking us, test to see if someone is logging in as administrator, test, or root.
    set scriptLog = objfso.OpenTextFile(strScriptLogFile, ForAppending, True)

    Set objLog = CreateObject(“MSWC.IISLog”)
    ‘Use the IIS log file parser provided by MSFT
    objLog.OpenLogFile strLogFile, ForReading, “MSFTPSVC”, 1, NotApplicable
    ‘ 0 = NotApplicable, 1 = ForReading

    While NOT objLog.AtEndOfLog
    If InStr(LCase(objLog.URIStem),”admin”) > 0 or InStr(LCase(objLog.URIStem),”root”) > 0 or InStr(LCase(objLog.URIStem),”test”) > 0 Then
    ClientIP = objLog.ClientIP
    If objDictionary.Exists(ClientIP) = False and objDictionary.Count ”
    objw3sock.SendLine “enable”
    objw3sock.WaitFor “Password:”
    objw3sock.SendLine “SwitchM3”
    objw3sock.WaitFor “ZERO#”
    objw3sock.SendLine “shun ” & IP
    objw3sock.WaitFor “ZERO#”
    objw3sock.SendLine “exit”
    set objW3Sock = NOTHING
    wscript.sleep 1000
    end sub

  107. James says:

    looks like i might have exceeded the line limit, heres how the script is suppose to end

    While NOT objLog.AtEndOfLog
    If InStr(LCase(objLog.URIStem),”admin”) > 0 or InStr(LCase(objLog.URIStem),”root”) > 0 or InStr(LCase(objLog.URIStem),”test”) > 0 Then
    ClientIP = objLog.ClientIP
    If objDictionary.Exists(ClientIP) = False and objDictionary.Count ”
    objw3sock.SendLine “enable”
    objw3sock.WaitFor “Password:”
    objw3sock.SendLine “SwitchM3”
    objw3sock.WaitFor “ZERO#”
    objw3sock.SendLine “shun ” & IP
    objw3sock.WaitFor “ZERO#”
    objw3sock.SendLine “exit”
    set objW3Sock = NOTHING
    wscript.sleep 1000
    end sub

  108. David Landy says:

    Thanks, Chrissy, for a brilliant script – and to frijoles for the instructions on running it as a service. You guys rock!

    I’ve been playing with a version that defends agains brute-force attacks direct on the server, too (not just via FTP) and thought some of you may be interested.

    The reason I started doing this is that – by the time I found this page – I’d already solved the FTP problem by installing the free (and secure) zFTP Server from http://www.zftpserver.com. This has a feature which can block IPs of reapeat bad logins, so the problem went away.

    However, I was still left with the problem of people trying to hack in directly via RDC; the logs (emailed out via EventSentry) show that my server had been the target of sporadic bursts of rapid-fire password guesses, for example 60 attempts in 4 seconds and, on another occasion, 800 attempts in 18 minutes.

    To try to deter this kind of rapid-fire brute force attack, the script I’ve developed — based heavily on Chrissie’s — detects the IP address from the Windows Event Log and then blocks the offending IP for a user-definable period (defaulting to 10 seconds), after which the block is released.

    The advantage of this is that brute-force attempts would be discouraged, but people sitting being a firewall or public proxy wouldn’t be locked out of a website simply because an offending machine was using the same gateway, they’d just get a delay in seeing the web page (or perhaps have to try again in a little while).

    Thanks again to Chrissie for getting the ball rolling and being (I think) the first (only?) person on the net to tackle this problem!

    Best wishes,


    ‘ BanIP.vbs version 0.02

    ‘ Greatly reduces brute-force password cracking attempts

    ‘ Created by David Landy ([email protected])
    ‘ 2 Aug 2007

    ‘ Adapted from the script by Chrissy LeMaire ([email protected])
    ‘ IP level banning (thanks Spencer @ netortech.com for the idea)

    ‘ To run this as a service see http://blogs.mscorlib.com/Home/tabid/111/EntryID/42/Default.aspx
    ‘ Thanks, frijoles!

    ‘ NO WARRANTIES, etc.

    ‘ This script instantly bans IP addresses trying to login to windows
    ‘ using the NT account “Administrator”

    ‘ This script has only been tested on Windows Server 2003.

    ‘ “What it does”
    ‘ 1. Sets an Async Event Sink to notify the script when a login fails because of bad username/password,
    ‘ locked-out account, or disabled account
    ‘ 2. When alerted, parses the log entry to get the ip address of the machine attempting to login
    ‘ 3. The offending ip address is banned (blocked) for a user-specified period
    ‘ 3. After the user-specified period has elapsed, unbans the offending ip

    ‘ Event Logs are posted on startup, ban, and unban events


    option explicit

    const app = “BanIP” ‘App Title
    const unBanDelay = 10 ‘The number of seconds to wait before unbanning an IP. Specifying a negative value will prevent automatic unbanning

    const ForReading = 1, ForWriting = 2, ForAppending = 8
    const elSuccess = 0, elError = 1, elWarning = 2, elInformation = 4, elAuditSuccess = 8, elAuditFailure = 16

    dim objWMIService
    dim eventSink
    dim strSQL

    dim serverIP
    dim IPConfigSet
    dim IPConfig

    dim run
    dim ips

    dim wshell
    Set wshell = WScript.CreateObject(“WScript.Shell”)

    ‘Log startup
    EventLog elSuccess, app & ” Starting”

    ‘Push Event Viewer Alert
    Set objWMIService = GetObject(“winmgmts:{(security)}!root/cimv2”)
    Set eventSink = wscript.CreateObject(“WbemScripting.SWbemSink”, “EVSINK_”)
    strSQL = “Select * from __InstanceCreationEvent ”
    strSQL = strSQL & “where TargetInstance isa ‘Win32_NTLogEvent’ and ”
    strSQL = strSQL & “TargetInstance.SourceName = ‘Security’ and (”
    strSQL = strSQL & “TargetInstance.EventCode = 529 Or ”
    strSQL = strSQL & “TargetInstance.EventCode = 531 Or ”
    strSQL = strSQL & “TargetInstance.EventCode = 539)”
    objWMIService.ExecNotificationQueryAsync eventSink, strSQL

    ‘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)
    Set IPConfigSet = Nothing

    ‘Initialise banned IP array
    ips = array()

    ‘Keep it going forever
    do While true

    Sub EVSINK_OnObjectReady(objObject, objAsyncContext)
    dim msg
    dim msgout
    dim tag
    dim clientIP
    dim userName
    dim eventID
    dim eventType

    msg = objObject.TargetInstance.Message
    msgout = “”

    tag = “Source Network Address:”
    clientIP = GetField(msg, tag)
    msgout = msgout & “clientIP ='” & clientIP & “‘” & vbCrLf

    tag = “User Name:”
    userName = GetField(msg, tag)
    msgout = msgout & “userName ='” & userName & “‘” & vbCrLf

    tag = “Event ID:”
    eventID = objObject.TargetInstance.EventCode
    msgout = msgout & “eventID ='” & eventID & “‘” & vbCrLf

    tag = “Type:”
    eventType = objObject.TargetInstance.Type
    msgout = msgout & “Type ='” & eventType & “‘” & vbCrLf

    ‘msgbox msgout, vbOKOnly, app

    select case eventID
    case 529, 531, 539 ‘unknown username or pwd, disabled account, or locked-out account
    ‘Could test here for LCase(userName) = “administrator” but this script
    ‘locks out all failed logins for a short period, just to be safe

    ‘Log the event
    EventLog elWarning, “Banning ” & clientIP & ” – User Name: ” & userName & “, Event: ” & eventID

    ‘Ban the IP
    Shell “ROUTE ADD ” & clientIP & ” ” & serverIP ‘No need to specify MASK as is the default

    ‘Add the IP to the array so it can be unbanned later
    aadd ips, array(clientIP, Now())

    End select
    End Sub

    Sub UnBanIPs()
    if unBanDelay = unBanDelay then
    ‘Log the event
    EventLog elWarning, “Unbanning ” & ips(i)(0)

    ‘Restore the route and delete it from the array of banned IPs
    Shell “ROUTE DELETE ” & ips(i)(0)
    adel ips, i
    i = i + 1
    end if
    End Sub

    Function GetField(s, tag)
    Dim i
    Dim j
    i = InStr(s, tag)
    If i > 0 Then
    i = i + Len(tag)
    j = InStr(i, s, vbCrLf)
    GetField = MyTrim(Mid(s, i, j – i))
    GetField = “Not Found”
    end if
    End Function

    Function MyTrim(s)
    dim t
    t = Trim(s)
    if t > “” then
    do while left(t, 1) = chr(9)
    t = mid(t, 2)
    end if
    MyTrim = t
    End Function

    Function aadd(a, s)
    redim preserve a(ubound(a)+1)
    a(ubound(a)) = s
    End Function

    Function adel(a, i)
    dim j
    for j = i to ubound(a) – 1
    a(j) = a(j + 1)
    redim preserve a(ubound(a) – 1)
    End Function

    Function afind(a, s)
    dim i
    for i = 0 to ubound(a)
    if not isarray(a(i)) then
    if a(i) = s then
    afind = i
    exit function
    end if
    end if
    afind = -1
    End Function

    Function afind2(a, s, j)
    dim i
    for i = 0 to ubound(a)
    if isarray(a(i)) then
    if a(i)(j) = s then
    afind2 = i
    exit function
    end if
    end if
    afind2 = -1
    End Function

    Function Shell(s)
    shell = wshell.Run(s, 0, false) ‘command, windowstate, waitforreturn
    End Function

    Function EventLog(t, s)
    wshell.LogEvent t, app & “: ” & s
    End Function

  109. Joe says:

    Hi, I tried running the script at the top of the page, on Win2003 SE tried invalid admin login via FTP and it blocked me on second attempt – ok – however my IP is completly blocked from the server I cant access websites or RDC – is this correct or should it jsut block FTP – or is there something that I need to change to just block FTP?

  110. David says:

    Chrissy.. you are a GOD!!!!!

    Installed the script a last week and today it did its job!

    Running Win2k Server and it caught and stopped a Brute Force attack in 10 seconds(8 attempts).

    Thank you for the script!

  111. John Marston says:

    if we have edited the file to block more than just “Administrator” ala Phi’s modification on October 15th, 2006 at 11:45 pm

    If InStr(LCase(objLog.URIStem),”admin”) > 0 or InStr(LCase(objLog.URIStem),”guest”) > 0 or InStr(LCase(objLog.URIStem),”root”) > 0 or InStr(LCase(objLog.URIStem),”test”) > 0 or InStr(LCase(objLog.URIStem),”user”) > 0 Then

    shouldn’t we also add those same bogus usernames to the section

    ‘Use the IIS log file parser provided by MSFT

    If LCase(objLog.URIStem) = “administrator” Then
    ClientIP = objLog.ClientIP


    like this?

    If LCase(objLog.URIStem) = “admin” or If LCase(objLog.URIStem) = “guest” or If LCase(objLog.URIStem) = “root” or If LCase(objLog.URIStem) = “test” or If LCase(objLog.URIStem) = “user” Then
    ClientIP = objLog.ClientIP

  112. Bavaria says:

    Great script! You are my hero of the day :-)

  113. Martin says:

    Thank you for this script, and also thank you David L. for your version as well. I took the two and made a new version. Some things i noticed in them:

    Chrissy’s – Your’s parses through the entire log file at every event. The “route add client mask fakeIP” just reroutes back to the server, which does nothing (or at least thats what happened for me).

    David’s – I liked your setup, but you only banned using the routing table, and not within IIS too.

    I didn’t really write down the problems as I was going, so I am probably forgetting to mention something. =\

    I had to learn vbs as I went, so it took me a little longer than it should have. I am used to C/C++/Java/PHP/etc..

    Here is a link to the code, which I will update, should there be any problems found:

    I also added some features. I hope you like it, and thanks again!

    (The first post did not copy the code correctly, so just visit the link provided to view it.)

  114. jmarston says:

    Thanks Martin! The other script wasn’t working for me on my 2003 server. I’ll give yours a try. I get hit every day from several locations so I should know pretty quickly if it works smoothly and will report back.

  115. axel.scheiwe says:

    thanks for the inspiration!
    Though I tried to use your skript, it does not work the way I like (ban IPs regardless of username).
    So I simply wrote my own.

    It takes use of LogParser and has to be scheduled as task.
    You can find it here:

  116. LucidObscurity says:

    Well, those scripts will make sure that no matter how many times they try, the brute force robot will never get in, but your server will still respond to every request for hours on end using precious resources and bandwidth. I’ve written a small application in .NET that will stop your server from responding completely. You’ll see a few entries in your logs, but once the app sees the attack those entries will cease from that IP. It works for me, but I would need to add some additional configuration options if I were to distribute it. So, that being said, would anyone here pay 3-5 bucks for something that would solve this problem once and for all? Also let me know if you’d prefer a windows service over a desktop application though I’ll probably write both and give you guys a choice.

    Please reply in this thread or contact me.


  117. Duncan says:

    How could I not post anything? :P

    Complete life saver! The script installed as a service works wonderfully and is as close to damn it instant. Very impressed and some great vbs code.

    I see you got hacked and didn’t restore all the posts to your blog. So this one is blank but you can still get the original script from this address:

    The zip file contains the original vbs from this site. Really struggled to find a copy of it – so thought I’d share. Really teasing to see the happy comments but not know what they are talking about!

    In response to someone asking about the logging type – yes you need to change it to Microsoft IIS Log File Format to get it to work. I was puzzled for a while but changing that and it all sprung into life.

    Again thanks Chrissy – great work.

  118. koz says:

    I would suggest logging to an sql db and add triggers on the table, looking for insert action. Checking the servicestatus field should get u there.
    Thanks Chrissy 4 a great site and reading!

  119. Pedro Rodriguez says:

    Those wanting Crissy to run for President of the US say I!

  120. havefun says:

    Thanks for this code, found it very usefull.

    For a server running win2k, I found that setting the gateway to the server IP address did not block routing. I had to set it to an unused IP address on the local subnet of the server. Also, on the command line, the metric keyword and value are required, so I added it to the script.

    With Win2k, I am showing the ip address as denied in the Directory Security properties, however, if I clear the bad route, the ip address is still allowed to connect. I guess this is the lag issue that was mentioned regarding win2k. Regardless, the IP route ban accomplishes the necessary goal.

    I believe there is an error in the posted code at the top. For some reason winmgmts:\.\root\cimv2 was causing an error on my box. Adding a second slash seemed to resolve it winmgmts:\\.\root\cimv2 (as per the way it is in David’s script)

    thanks again, very useful

  121. havefun says:

    Just a followup. I was incorrect in assuming setting the gateway to the server IP address did not block routing. I was testing from a computer on the local subnet.

  122. Popolou says:

    Wow, excellent script!

    It seems that this blog/site is still the authority when it comes to searching for blocking failed attempts via FTP. Great Job Chrissy.

    One snag i’ve encountered and would appreciate any guidance.

    It seems that the following code is causing problems for my W2K server box it’s running on: –

    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)

    I understand its purpose but the “Set IPConfigSet = GetObject…..” throws up an “Error: Unspecified Error” and “.ExecQuery” entry returns “Error: Not a Collection”.

    Is it too much to process or am i missing something else here?



  123. Popolou says:

    Wow, excellent script!

    It seems that this blog/site is still the authority when it comes to searching for blocking failed attempts via FTP. Great Job Chrissy.

    One snag i’ve encountered and would appreciate any guidance.

    It seems that the following code is causing problems for my W2K server box it’s running on: –

    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)

    I understand its purpose but the “Set IPConfigSet = GetObject…..” throws up an “Error: Unspecified Error” and “.ExecQuery” entry returns “Error: Not a Collection”.

    Is it too much to process or am i missing something else here?



  124. Popolou says:

    Sorry for the double post. Havefun’s problem seemed to be the same error we were experiencing and once i added the extra slash it fixed the scripting error.



  125. Tommy says:

    When someone try to brute force it I get this error :

    Line : 46
    Char : 5
    Error : Error not specified

    Code : 80004005

    Can you help me out? I’m running it on win2k server

  126. Chrissy says:

    Hey poplou, I think the slash may have fallen off when I migrated the posts. I’ve updated the code, thanks for writing!

    Also to everyone else with questions..sorry, I no longer have time to test but be sure to check out the comments, a lot of smart people have great ideas!

  127. ISDPCMAN says:


    Where can I get the latest code for this FTP screener? We too have an FTP site that gets hammered every night and i want to implement an IP ban solution but I didn’t see a clear “Download latest” anywhere on the site here.

    Thanks to all for this great utility. I can’t wait to implement it.

  128. Bensode says:

    I have this script installed and set to run through the HKLM key as it should be. I’ve added a task scheduler to run the script with my credentials (I have admin access to the machine) at startup but it won’t start until I log in and as soon as I log off, wscript.exe stops running. I am running pslist remotely to the server to confirm that it starts when I am logged in and then stops when I log out. Is there something I am missing? Server 2003 Standard latest and greatest Windows Updates are all installed.

  129. Rick Kelly says:

    I installed the script on one of our servers which runs multiple sites.
    I had to change line 78 from ‘Set WshShell = Nothing’ to ‘Set WshShell = CreateObject(“WScript.Shell”)’
    This is to prevent it from bailing out with a “Object requiered
    ‘WshShell” on line 55 while looping through the EVSINK sub. Unaltered the
    script will bail out on the 2nd loop.

    Thanks for the script!
    It works as expected after my modification.

  130. BobG says:

    Chrissy, Gang, this is all too cool and appreciated. I got it all installed, running and updated for some more names. I seem to get a lot of hits trying to login as ‘test’.

    Let me note that after all of that it seems that this issue has caught the attention of the gang in Redmond. I found that they have developed an IIS add-on to address the same issues.


    Oh well, I needed to brush up on my scripting anyway!

    Keep up the good fight, what you have done is bring attention to an issue the big guys should have taken care of two years ago.

    You are definitely ahead of the curve! :)

  131. BobG says:

    Oh, I gave the gang from Redmond too much credit, the fix is from Kansas! :)

  132. ziyaul_quadri says:

    c:\users\ziyaul\app data\local\temp\.tt166c.temp.vbs
    line: 4
    char: 1
    error: access denied
    code: 80041003
    source: swbemobjectex

    how to correct it? thank u.

  133. ziyaul_quadri says:

    how to correct it?

    c:\users\ziyaul\app data\local\temp\.tt166c.temp.vbs
    line: 4
    char: 1
    error: access denied
    code: 80041003
    source: swbemobjectex

    thank u.

  134. Rob says:

    Has anyone successfully deployed this script on Server 2008?



  135. Salt says:

    Just another extremely grateful person – thanks very much for this Chrissie (and everyone else who took the time to add their suggestions)

  136. Martin says:

    I too have the same issue with the script seemingly taking a long time to kick in and am on Windows 2003.

    I’ve just had an automated dictionary attempt on the administrator account. I can see in the event log that there were 71,088 attempts in about 18 minutes. The attack may well have been going on for longer but the event log reached it’s maximum log size so these will have been lost.

    It works fine when I test it by attempting to login from an FTP client though. I wonder if it is the sheer number of attempts that overwhelms it?

  137. Phil Allen says:

    Thanks for the code Chrissy :-)

    Over a period of time on 2003 server occasionally the script failed to work, the error being related to WshShell

    To solve it I changed your code from

    ‘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


    ‘Iterate through each FTP site. See #2 up above.
    For Each objSITE in objFTPSVC
    If lcase(objSITE.class) = “iisftpserver” Then
    ‘ Phil Nov 2008
    Set WshShell = Nothing
    Set WshShell = WScript.CreateObject(“WScript.Shell”)
    ftpLogFilePath = WshShell.ExpandEnvironmentStrings(objSITE.LogFileDirectory) & “\msftpsvc” & objSITE.Name
    Set WshShell = Nothing
    ‘ End Phil nov 2008

    and since then it has been purfect :-)



  138. aVoN says:

    Nice script, but it has an issue: Everytime a login-request is send, the script takes resources. It even starts running if the IP is already blocked.
    This results to the issue, my CPU is at nearly 100% when someone tries to login as “Administrator”.

  139. Patrick says:

    Nice script.

    Does anyone know if there is a way to mod the code to allow certain IP addresses? A couple of our web apps end up getting blocked internally when users fail to enter the password correctly. They aren’t even using the admin username but I take it the connection string is calling on it somehow.



  140. Andy says:

    Very nice script.

    But one problem I have:
    Code: 8004106C
    Quelle: SWbemServicesEx
    Error: Quota violation

    can you help with this Prob…?


  141. Andy says:

    Thanks for so much help!!!

    The Problem still exist…

  142. Andy says:

    I start the service with user network and this stop the messges… hope that will help

  143. Pierre says:

    The script doesn’t seem to work with Windows Server 2008. Has anyone got it running on Windows 2008?

  144. kajiba says:

    Dear All
    The scripts looks great

    I am getting error on line 150, saying path not found

    Any idea, Please

    And I am using WK3 server

    149. ftpLogFilePath = wshell.ExpandEnvironmentStrings(objSITE.LogFileDirectory) & “\msftpsvc” & objSITE.Name
    150. Set objFolder = objFSO.GetFolder(ftpLogFilePath)
    151. Set objFiles = objFolder.Files

  145. Isprin says:

    Is there a way to list the address’ that have been placed in the BAN ..?? and then an UNBAN method..??

    • kajiba says:

      It seems the scripts worked for you.

      On my windows 2003 server is not running, it gives me the error I am getting error on line 150, saying path not found.

      any help please !!!

      149. ftpLogFilePath = wshell.ExpandEnvironmentStrings(objSITE.LogFileDirectory) & “\msftpsvc” & objSITE.Name
      150. Set objFolder = objFSO.GetFolder(ftpLogFilePath)
      151. Set objFiles = objFolder.Files

  146. Julio says:

    @Isprin: This script adds the ban directly into your IIS settings. Just go to IIS administrator to manage the IP bans.

  147. Thank you very much for this execellent script. It runs without modifications om my Windows Server 2003.

    But, and this is essential, on Windows Server 2008, the NotificationQuery must be chnaged to contain TargetInstance.SourceName=’Microsoft-Windows-IIS-FTP’ instead of TargetInstance.SourceName=’MSFTPSVC’

  148. Mike says:

    (Attempting to run it on Server 2008) – I changed TargetInstance.SourceName=’MSFTPSVC’ to TargetInstance.SourceName=’Microsoft-Windows-IIS-FTP’ and I receive an error on line 41 ActiveX Component can’t create object: ‘MSWC.IISLog

    Any ideas?

  149. Larry says:

    Some notes on how to make it work nicely on Win2K IIS5…
    Copy the script into c:ScriptsStartup folder.
    Then check FTP logging is enabled on both the master FTP properties and the FTP server. In logfiles system32logfiles there should be two folders Logfiles (usually empty) and MSFTPSVC1 containing FTP logs. Do not name the log directories in IIS properties, the server will automatically create them. Leave it as %windir%system32logfiles for both. This is important so the script can find the logfiles.
    Then go to regedit and find the key for LM software microsoft current version run and make a new string value – call it banftpip and add the path to run wscript or cscript .exe and then the path to the vbs file scriptsstartupbanftpips.vbs.
    This is an example : c:winntsystem32wscript.exe C:scriptsstartupbanftpips.vbs You may have to change winnt to windows on some servers. Also if the script is the old version change wscript to cscript or change the instances in the script to wscript from cscript. Then reboot the server and the script will execute on startup. To verify it is running use taskmanager and wscript or cscript should then show as a process.
    Because the script only bans Administrator logins, check logfiles for the first username in an attempt and make a second script replacing Administrator (in two places) with the new user name and call this script banftpips1 and make a new registry key of the same name banftpips1 to also start that script. Common hacks use admin, abby, test, administrador and so on, make a script and registry entry for each one. Reboot and now each script will catch each new name and ban it – once the first attempt is stopped the hacker cannot then try additional names as his ip will not connect.

  150. Jesper G says:

    Great script Crissy. The 'like so' link to setup instructions are broken – just wanted to let you know.

  151. Julian says:

    Hi to Everyone.
    I'm very sorry to go against all these nice comments but I personally think this script is *no good* for one simple reason: you must restart FTP service to make the BAN effective… (well, that's what happens on my two W2K3 boxes). Although the banned IP are listed in the "Directory Security" of IIS and are also propagated in all the sublevels… you are forced to restart FTP.

    And that means that my log gets filled with millions (yes,millions) of Failed Login events…

    Now, on a production machine with 100 users there's no way I can restart the service after every ban.

    I could restart the service during the night… but this way the BAN simply doesn't work!!! And I get my LOG FULL OF Events 529 & Co.; I can get something like 1,2 million in a day.

    My solution is another one: the BAN must happen on another level, adding it to and IPSEC policy via a BATCH program and not to IIS. The VBS scans the log and if an IP is found it can execute a BATCH which does something like this:

    netsh ipsec static add filter filterlist=BlockIP srcaddr=me dstaddr=%1

    Where %1 is the parameter the VBS passes to the BATCH.

    What you need is an IPSEC policy active (yes, talking about standalone servers, no AD) where both the Policy has "BlockIP" name.

    And that works in real time, no restarts and no delay… only the time for IIS to flush the log buffer.

    Bye, and thanks for the script, it's good a part from the fact it's not suitable for me!


  152. Mahname says:

    That's somewhat what is happening at this line: WshShell.Run "ROUTE ADD " & clientIP & " MASK " & serverIP, 1, True

    That takes effect immediately (until reboot) and the FTP ban keeps it permanent.

  153. MVA says:

    Hello. I ran this on a Windows 2008 R2 Standard server. I tested logging in as Admin got my IP blocked. When looking through the IIS settings, I cannot find an entry where my IP is in order to unblock it. Can anyone help? Thanks.

  154. ChrisM says:

    Yeah, I’m in the same boat as MVA. Ran this, it’s setup as a service, running on the system account.

    It worked, in the sense that I had someone try administrator via cmd > ftp domain.com They were blocked.

    I checked everywhere, and the IP was not listed.
    I checked cmd > route print, and i saw his ip in the table, but it was not anywhere in the directory security under the ‘FTP Sites’, or any virtual site.

    Then the banftpview, only shows the IP ranges I entered manually.

    Windows Server 2003 SE SP2.

    Also, whats happening in the route table. How is this working? trying to understand this better. I read alllllll the comments, i feel like a tard, cause this is so old too.

  155. ronnie says:

    Uhm, I had quite a few problems with the script because maybe because my log file is very big.
    If I remember well I had [email protected]% problems, too.

3 Pings/Trackbacks for "IIS: Instantly Ban IPs Attempting to Login to MS-FTP as Administrator"

Leave a Reply

Your email address will not be published. Required fields are marked *