{"id":3,"date":"2007-09-04T08:15:08","date_gmt":"2007-09-04T13:15:08","guid":{"rendered":"http:\/\/blog.bitsofgenius.com\/?p=3"},"modified":"2012-09-12T09:15:20","modified_gmt":"2012-09-12T13:15:20","slug":"blocking-dictionary-attacks-on-a-personal-ftp-site-iis","status":"publish","type":"post","link":"https:\/\/blog.bitsofgenius.com\/?p=3","title":{"rendered":"Blocking Dictionary Attacks on a Personal FTP site (IIS)"},"content":{"rendered":"<p>Thanks to some scripts I found on various sources, I was able to piece together this script to detect and block ever-increasing dictionary attacks against the Administrator account on my FTP server. Basically, you start the script using WScript at system load. It hooks itself into WMI events for ftp log file entries. When an entry is created, the log file is scanned for any IP address which has 5 or more bad login attempts in the log file. The code then checks to see if that IP has already been assigned the invalid gateway address, and adds the bad routing instruction for that IP if it has not already done so.<\/p>\n<p>This is an enhancement to scripts I originally found at <a href=\"http:\/\/blog.netnerds.net\/2006\/10\/vbscript-stop-dictionary-ftp-attacks-in-iis-using-vbscript\" target=\"_blank\">NetNerds.net<\/a> and <a href=\"http:\/\/main.vizimetrics.com\/index.php?option=com_content&amp;task=view&amp;id=40&amp;Itemid=35\" target=\"_blank\">VisiMetrics.com<\/a>, which provided the base code to create the dead route. I&#8217;ve added the following:<\/p>\n<ul>\n<li>a sink to gracefully handle a Windows shutdown<\/li>\n<li>a flag file located in the same folder as the script file, which will cause the script to terminate when deleted. It&#8217;s a way to kill a specific WScript process, instead of guessing which one of the umpteen WScript processes to remove in the task manager.<\/li>\n<li>Logging to the NT Application Event Log when starting, stopping, or creating bad route entries for attackers.<\/li>\n<\/ul>\n<p>All you need to do to make the script run is change the values assigned to three variables.<\/p>\n<ul>\n<li>fakeGateWayIP = &#8220;192.168.1.200&#8221; &#8216;The black hole location in your sub-net to route the packets.<\/li>\n<li>xMax = 5 &#8216;Max number of invalid login attempts<\/li>\n<li>LogFiles = 10 &#8216;Max number of log files to keep in the folder before deleting them.<\/li>\n<\/ul>\n<p>The beauty of this script is that it does not persist the bad routing instructions in other than the routing table, meaning that they are lost at the next reboot. If the attack occurs again, the bad route is just re-established after 5-10 attempts from the attacker. Truly a remarkably simple and effective technique. Thanks Chrissy and Tim!<\/p>\n<pre lang=\"vb\" line=\"1\" escaped=\"true\">REM FtpBlocker.vbs\r\nREM Launch once at system startup. Monitors the ftp activity for bad login attempts (Status Code 530).\r\nREM If more than X failed login attempts are tried by a client, it's IP is added\r\nREM to the routing table, with a fake gateway (dead IP) as the routing target. Designed to thwart\r\nREM dictionary attacks.\r\nREM This script works with Windows 2000 and later.\r\nDim aIpRoute, bShuttingDown\r\nFunction FileExists (sFileName)\r\n\tDim oFSOSet oFSO = CreateObject(\"Scripting.FileSystemObject\")\r\n\tFileExists = oFSO.FileExists(sFileName)\r\n\tset oFSO = Nothing\r\nEnd Function\r\n\r\nSub DeleteFile (sFileName, bEvenIfReadOnly)\r\n\tDim oFSO\r\n\r\n\tSet oFSO = CreateObject(\"Scripting.FileSystemObject\")\r\n\tFileDelete = oFSO.DeleteFile(sFileName, bEvenIfReadOnly)\r\n\tset oFSO = Nothing\r\nEnd Sub\r\n\r\nFunction FileToString (sFileName)\r\n\tDim oFSO, oTS\r\n\tSet oFSO = CreateObject(\"Scripting.FileSystemObject\")\r\n\tSet oTS = oFSO.OpenTextFile(sFileName, 1)\r\n\r\n\tFileToString = oTS.ReadAll\r\n\toTS.Close()\r\n\r\n\tset oTS = Nothing\r\n\tset oFSO = Nothing\r\nEnd Function\r\n\r\nSub StringToFile (sFileName, sText)\r\n\tDim oFSO, oTS\r\n\tSet oFSO = CreateObject(\"Scripting.FileSystemObject\")\r\n\tSet oTS = oFSO.OpenTextFile(sFileName, 2, True)\r\n\r\n\toTS.Write sText\r\n\toTS.Close()\r\n\r\n\tset oTS = Nothing\r\n\tset oFSO = Nothing\r\nEnd Sub\r\n\r\nFunction RunOutput(cProgram, nWindowType)\r\n\tREM -- Obtain a Temporary File Name\r\n\tDim oFS\r\n\tSet oFS = CreateObject(\"Scripting.FileSystemObject\")\r\n\tDim cFile\r\n\tcFile = oFS.GetSpecialFolder(2).Path &amp; \"\\\" &amp; oFS.GetTempName\r\n\r\n\tREM -- Execute the command and redirect the output to the file\r\n\tDim oShell\r\n\tSet oShell = CreateObject( \"WScript.Shell\" )\r\n\toShell.Run cProgram &amp; \" &gt;\" &amp; cFile, nWindowType, True\r\n\tSet oShell = Nothing\r\n\r\n\tREM -- Read output file and return\r\n\tDim oFile\r\n\tSet oFile = oFS.OpenTextFile(cFile, 1, True)\r\n\tRunOutput = oFile.ReadAll()\r\n\toFile.Close\r\n\r\n\tREM -- Delete Temporary File\r\n\toFS.DeleteFile cFile\r\n\tSet oFS = Nothing\r\nEnd Function\r\n\r\nFunction GetRoutingEntries()\r\n\tREM Capture the content of the current routing table.\r\n\taRaw = Split (RunOutput(\"%COMSPEC% \/C ROUTE PRINT\", 0), vbCrLf)\r\n\r\n\tSet o = new RegExp\r\n\to.Pattern = \"((\\d)+\\.){3}(\\d)+\"\r\n\to.Global = True\r\n\to.MultiLine = False\r\n\to.IgnoreCase = False\r\n\taIP = Empty\r\n\tFor Each s In aRaw\r\n\t\tSet oMatches = o.Execute (s)\r\n\t\tIf oMatches.Count = 4 Then\r\n\t\t\tIf IsArray (aIP) Then\r\n\t\t\t\tReDim Preserve aIP (UBound (aIP, 1) + 1)\r\n\t\t\tElse\r\n\t\t\t\tReDim aIP (0)\r\n\t\t\tEnd If\r\n\t\t\taIP (UBound (aIP, 1)) = oMatches.Item(0) &amp; \"|\" &amp; oMatches.Item(2)\r\n\t\tEnd If\r\n\tNext\r\n\tGetRoutingEntries = aIP\r\nEnd Function\r\n\r\nREM -- Log the startup to the event log.\r\nSet oWsh = WScript.CreateObject(\"WScript.Shell\")\r\noWsh.LogEvent 0, \"FtpBlocker530.vbs begins\"\r\nSet oWsh = WScript.CreateObject(\"WScript.Shell\")\r\n\r\nREM Load a snapshot of the IP's in the routing table, and use this as the baseline for determining\r\nREM if the IP is in the list already.\r\n\r\naIpRoute = GetRoutingEntries()\r\nbShuttingDown = False\r\n\r\nREM Push Event Viewer Alert\r\nSet objWMIService = GetObject(\"winmgmts:{(security)}!root\/cimv2\")\r\nSet eventSink = wscript.CreateObject(\"WbemScripting.SWbemSink\", \"EVSINK100_\")\r\nstrWQL = \"Select * from __InstanceCreationEvent where TargetInstance isa 'Win32_NTLogEvent' and TargetInstance.SourceName = 'MSFTPSVC' and TargetInstance.EventCode = 100\"\r\nobjWMIService.ExecNotificationQueryAsync eventSink,strWQL\r\n\r\nSet objWMIService1 = GetObject(\"winmgmts:{(security)}!root\/cimv2\")\r\nSet eventSink1 = wscript.CreateObject(\"WbemScripting.SWbemSink\", \"EVSINK6006_\")\r\nstrWQL = \"Select * from __InstanceCreationEvent where TargetInstance isa 'Win32_NTLogEvent' and TargetInstance.SourceName = 'eventlog' and TargetInstance.EventCode = 6006\"\r\nobjWMIService.ExecNotificationQueryAsync eventSink1,strWQL\r\n\r\nREM Create a flag file named FtpBlocker530.flg\r\nREM When this file is not on the system, it is a signal to terminate this application.\r\n\r\nStringToFile \"FtpBlocker530.flg\", \"*** MARKER FILE ONLY ***\"\r\n\r\nREM Keep it going forever, or until the marker file is missing.\r\nWhile (FileExists (\"FtpBlocker530.flg\") And Not bShuttingDown)\r\n\tWscript.Sleep(1000)\r\nWend\r\n\r\nIf Not bShuttingDown Then\r\n\tSet oWsh = WScript.CreateObject(\"WScript.Shell\")\r\n\toWsh.LogEvent 0, \"FtpBlocker530.vbs stopped by file removal\"\r\n\tSet oWsh = Nothing\r\nElse\r\n\tDeleteFile \"FtpBlocker530.flg\", True\r\nEnd If\r\nSet eventSink = Nothing\r\nSet eventSink1 = Nothing\r\nSet objWMIService = Nothing\r\nSet objWMIService1 = Nothing\r\n\r\nSub EVSINK6006_OnObjectReady(objObject, objAsyncContext)\r\n\tbShuttingDown = True\r\nEnd Sub\r\n\r\nSub EVSINK100_OnObjectReady(objObject, objAsyncContext)\r\n\r\n\tSet objDictionary = CreateObject(\"Scripting.Dictionary\")\r\n\tSet objFSO = CreateObject(\"Scripting.FileSystemObject\")\r\n\tSet objLog = CreateObject(\"MSWC.IISLog\")\r\n\tSet WshShell = WScript.CreateObject(\"WScript.Shell\")\r\n\r\n\tfakeGateWayIP = \"192.168.1.200\" 'This is a black hole location on your subnet to route the packets.\r\n\txMax = 5 'Max number of invalid login attempts\r\n\txLogFiles = 10 'Max number of log files to keep in the folder before deleting them\r\n\r\n\tSet objFolder = objFSO.GetFolder(objFSO.GetSpecialFolder(0).Path &amp; \"\\system32\\LogFiles\\MSFTPSVC1\\\")\r\n\tSet objFiles = objFolder.Files\r\n\tFor Each fileName In objFiles\r\n\t\tlastFile = fileName\r\n\t\tSet f = objFSO.GetFile(fileName)\r\n\t\tIf f.DateCreated &lt;= Date - xLogFiles Then objFSO.DeleteFile FileName, True\r\n\t\tSet f = Nothing\r\n\tNext\r\n\tSet objFiles = Nothing\r\n\tSet objFolder = Nothing\r\n\r\n\tobjLog.OpenLogFile lastFile, 1, \"MSFTPSVC\", 1, 0\r\n\tWhile NOT objLog.AtEndOfLog\r\n\t\tobjLog.ReadLogRecord\r\n\t\tclientIP = trim(objLog.ClientIP)\r\n\t\txStatus = trim(objLog.ProtocolStatus)\r\n\t\tIf xStatus = \"530\" AND NOT (clientIP = fakeGateWayIP) then\r\n\t\t\tIf objDictionary.Exists(ClientIP) Then\r\n\t\t\t\tobjDictionary.Item(clientIP) = cStr(Clng(objDictionary.Item(clientIP)) + 1)\r\n\t\t\tElse\r\n\t\t\t\tobjDictionary.Add clientIP,\"1\"\r\n\t\t\tEnd If\r\n\t\tEnd If\r\n\tWend\r\n\tobjLog.CloseLogFiles 1\r\n\r\n\txChange = False\r\n\tFor Each xClient in objDictionary.Keys\r\n\t\txTest = False\r\n\t\tIf Clng(objDictionary.Item(xClient)) &lt; xMax then\r\n\t\t\tobjDictionary.Remove(xClient)\r\n\t\tElse\r\n\t\t\txTest = Not IsArray (aIpRoute)\r\n\t\t\tIf Not xTest Then\r\n\t\t\t\txTest = True\r\n\t\t\t\tFor Each ip In aIpRoute\r\n\t\t\t\t\tIf Split (ip, \"|\")(0) = xClient And Split (ip, \"|\")(1) = fakeGateWayIP Then\r\n\t\t\t\t\t\txTest = False ' Client already exists in the routing table with the fakeGateWayIP as the gateway\r\n\t\t\t\t\t\tExit For\r\n\t\t\t\t\tEnd If\r\n\t\t\t\tNext\r\n\t\t\tEnd If\r\n\t\t\tIf xTest Then\r\n\t\t\t\txChange = True\r\n\t\t\t\tWshShell.Run \"%COMSPEC% \/C ROUTE ADD \" &amp; xClient &amp; \" MASK 255.255.255.255 \" &amp; fakeGateWayIP, 0, True\r\n\t\t\t\tWshShell.LogEvent 1, \"BAD ROUTE(s) assigned: FTP max of \" &amp; xMax &amp; \" occurrences for 530 Event(s) exceeded for \" &amp; xClient\r\n\t\t\tEnd If\r\n\t\tEnd If\r\n\tNext\r\n\r\n\tSet WshShell = Nothing\r\n\tSet objLog = Nothing\r\n\tSet objFSO = Nothing\r\n\tSet objDictionary = Nothing\r\n\r\n\tIf xChange Then\r\n\t\taIpRoute = GetRoutingEntries()\r\n\tEnd If\r\nEnd Sub<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Thanks to some scripts I found on various sources, I was able to piece together this script to detect and block ever-increasing dictionary attacks against the Administrator account on my FTP server. Basically, you start the script using WScript at system load. It hooks itself into WMI events for ftp log file entries. When an [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[9],"tags":[],"class_list":["post-3","post","type-post","status-publish","format-standard","hentry","category-vbscript-intended-for-wscript-background"],"_links":{"self":[{"href":"https:\/\/blog.bitsofgenius.com\/index.php?rest_route=\/wp\/v2\/posts\/3","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.bitsofgenius.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.bitsofgenius.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.bitsofgenius.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.bitsofgenius.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3"}],"version-history":[{"count":1,"href":"https:\/\/blog.bitsofgenius.com\/index.php?rest_route=\/wp\/v2\/posts\/3\/revisions"}],"predecessor-version":[{"id":418,"href":"https:\/\/blog.bitsofgenius.com\/index.php?rest_route=\/wp\/v2\/posts\/3\/revisions\/418"}],"wp:attachment":[{"href":"https:\/\/blog.bitsofgenius.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.bitsofgenius.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.bitsofgenius.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}