Block failed FTP logins in IIS 7 and 7.5

2182102I have been administering Windows hosting servers for over 7 years now and one thing that really made me angry is the lack of BASIC security features in Microsoft’s FTP server.

Blocking the IP addresses based on the number of failed login is an ESSENTIAL feature for any FTP server, but it seems Microsoft doesn’t care about that ( until IIS 8 :) )

I swear, when I come to power, I will make that feature obligatory to every FTP server on the market, so…when it comes to that, vote for me! :D

Since I am seeing increasing numbers of brute force attacks in general ( FTP, email servers, application logins, etc… ) we had to come up with some solution that would harden our FTP servers.

I wrote a Powershell script that processes the FTP log file and if it detects over 50 failed logins from a particular IP address, it adds an “Deny” entry it in “FTP IPv4 Address and Domain Restrictions” .

I am running this script every 5 minutes using Scheduled Tasks and it has proven to be quite effective; In 8 hours, script banned over 20 IP addresses :)

ftpblocks

Script is not only Powershell based, but it uses LogParser tool from Microsoft, so in order for the script to work you will need to download the tool and save it in the same folder where your script will be located. You only need to save “LogParser.exe” and “LogParser.dll” in the same folder where your script is.

I have to admit that I am pretty amazed by the speed of the entire script. On my machine, parsing the 100 MB log file takes under 0.5 second, which, you have to admit is pretty awesome :)

 

Let me briefly explain how the script works.

1. Script starts the LogParser tool and searches for the response code “530″ which means that the login failed; Then it saves all IP addresses and the number of logins in the CSV file in the folder c:\work\temp\FTPUserAccountAttempts.csv .

2. Script parses the CSV file and extracts the IP addresses and add them to the “Deny” list in “FTP IPv4 Address and Domain Restrictions” module.

3. Exits :D

So, what do you need in order to get the script running on your machine?

1. Enter the correct pat to your FTP log files in the “$logpath” variable

2. Make sure you have “c:\work\temp” folder created or modify the script.

3. Edit the “-location” in the add-webconfiguration /system.ftpServer/security/ipSecurity -location "IIS:\Sites\FTP" -value @{ipAddress="$ipban";allowed="false"} -pspath IIS:\

My FTP site is called “FTP” . If you have some other name, enter the correct name in “IIS:\Sites\yoursite” .

Okay, we covered the basics,  so here is the code.
Function FTPBlock
{
#SETTINGS
$date = Get-date -Format yMMdd
$logpath = "C:\inetpub\logs\LogFiles\FTPSVC4\u_ex$date.log"
#END SETTINGS
Import-Module "WebAdministration" -ErrorAction Stop
$ErrorActionPreference= 'silentlycontinue'
.\logparser "select c-ip, count(sc-status) INTO c:\work\temp\FTPUserAccountAttempts.csv FROM $logpath where sc-status = '530' group by c-ip HAVING COUNT(*) > 50 order by count(sc-status),c-ip" -e:1 -i w3c -o:CSV
$testpath = Test-Path C:\work\temp\FTPUserAccountAttempts.csv
if ($testpath -eq "true")
{
$ip = Get-Content C:\work\temp\FTPUserAccountAttempts.csv | select -Skip 1
foreach ($_ in $ip)
{
$ip1 = $_.split(",")
$ipban = $ip1[0]
echo $ipban
add-webconfiguration /system.ftpServer/security/ipSecurity -location "IIS:\Sites\FTP" -value @{ipAddress="$ipban";allowed="false"} -pspath IIS:\
}
}
elseif ($testpath -eq "false")
{
exit
}
}
FTPBlock

You can also download the script from HERE.

I am working on the V1.1 version of the script that saves all entries to a SQL database. I am doing that so I can automatically add the blocked IP addresses on all of my machines and have a detailed tracking of the offending IP addresses.  Second feature is automatic cleanup, since I don’t want to hog my FTP server with a huge list of IP addresses.

Happy blocking :)

2 comments

  1. I have explored this on my own server. Like you, I have thousands upon thousands of failed logon attempts in my logs (FTP and others). I find this solution a bit inefficient in several respects. Primarily, scanning the log files (which can be huge), then rescanning the created secondary log file. Further, 50 failed logins is too high of a trigger point.

    Instead of scanning logs, it is more efficient to “hook” into the system Security event log. Whenever a failed login occurs, an event log entry is generated having the event code 4625. A Windows Service can programatically watch the System event log for these events–I’m writing code in C#. For a more PowerScript friendly solution, you can use the Event Viewer to “Attach a Task to this Event” — a Task Manager task that can run a script whenever a 4625 event occurs. At this point you can extract the IP address from the event data and decide what to do with it.

    The best part about Event 4625 is it is fired for Remote Desktop attempts (which are far more dangerous than FTP). Thus, an Event Log solution can protect your machine against more than just FTP attacks. Just ensure you figure which Event IDs are necessary to watch for.

    I’m setting my failed login limit MUCH lower than fifty. Possibly as low as five attempts. However, I intend to create an algorithm for automatic cleanup of blocked IP addresses which will remove the block in a very short amount of time. Five failed attempts my create a one-minute block, but further failed logins will progressively extend the block duration, probably in an exponential way (2^n). After some period of no failed attempts, the block duration will also exponentially decay such that the offending IP will eventually end up totally in the clear.

    In other words, more attempts equals a longer block. Repeats double the duration of the next block, but no offensive activity halves the duration of the next block until the IP address is in the clear again. The exponential curve really skyrockets the block time quickly for pervasive IP addresses, but allows legitimate and reasonable decay for fat-fingered users. Automatic cleanup is mandatory for me to prevent an endless list of blocked IP addresses. IPv6 blocking is also important to me.

    A requirement of any intelligent blocking scheme is some sort of persistent storage (Windows Registry, SQL, XML or data file, etc.) to track repeat offenders. I’m not certain that SQL is my first choice as I’d like my application to have no specific dependencies. I’m strongly considering the Windows Registry.

  2. Hi, yes, I agree that there are more “elegant” solutions than this, but as mentioned in the post, it was just a “dirty fix” solution. I’ll look into some of your suggestions in the v2 version of the script.
    About the limit, yes, 50 is a bit high, but one can easily replace the value in the script.
    Usage of some persistent storage mostly relies on the use case. Since I want to distribute the script among many servers, SQL looks like the most cost effective, safest and fastest way to go. XML is also a good option, but since we could potentially be dealing with thousands of IP addresses ( spreaded among all of my servers ), XML file can be relatively “expensive” to process. With SQL I can simply query the database for any data I want. With XML, its a bit harder to do that.

    Thank you for your response.
    Cheers, Alesandro.

Leave a Reply

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

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>