View Single Post
  #6   (View Single Post)  
Old 18th February 2009
jggimi's Avatar
jggimi jggimi is offline
More noise than signal
 
Join Date: May 2008
Location: USA
Posts: 7,983
Default

Here's an example of using overload...flush to block script kiddie ssh attacks. Any IP address who connects too often too quickly will have their state(s) killed, and they'll be added to the ssh-badguys table:
Code:
# Allow inbound ssh, block more than 3 connections in 30 seconds. 
#
pass in log on $external_nic proto tcp to any port ssh \
    keep state (max-src-conn-rate 3/30, \
    overload <ssh-badguys> flush global)
The ssh-badguys table is temporary. Here's a script that adds the IP address(es) from either the ssh-badguys or ftp-badguys tables into a single, large and permanent badguys table, updates a database with the IP address(es), date/time of the block and a reason for the block. The ftp-badguys table is no longer used, though, as I run a modified ftpd(8) instead, which drops connections from abusers so I don't need it unless I want to restart blocking them from all access. So far, these have all been script kiddies who have scripts that, without my mod, will loop forever attempting to log on to "Administrator":
Code:
#!/usr/bin/perl
# run by cron every 5 mins

# examine ssh-badguys table, if any records:
# 1) add to badguys
# 2) delete from ssh-badguys
# 3) update database

@ssh = `pfctl -t ssh-badguys -T show`;
foreach (@ssh) {
    my $ip = substr($_, 0, -1); # strip the newline char from the end
    system("pfctl -t badguys -T add $ip");
    system("pfctl -t ssh-badguys -T dele $ip");
    system("/root/blocked-add.pl $ip ssh cron");
    print "badguys: $ip added to table - ssh attack";
}

# examine ftp-badguys table, if any records:
# 1) add to badguys
# 2) delete from ftp-badguys
# 3) update database

@ftp = `pfctl -t ssh-badguys -T show`;
foreach (@ftp) {
    my $ip = substr($_, 0, -1); # strip the newline char from the end
    system("pfctl -t badguys -T add $ip");
    system("pfctl -t ftp-badguys -T dele $ip");
    system("/root/blocked-add.pl $ip ftp cron");
    print "badguys: $ip added to table - ftp attack";
}
Of course, shutting down the system requires putting the badguys table into a file for loading on reboot. Here's an excerpt from /etc/rc.shutdown:
Code:
# do a final update to badguys table, and then
# copy the badguys table to disk
#
# ---> if shutdown during single user, badguys may be 0 bytes.  Don't
# ---> overlay file if so.
#
pfctl -t badguys -T show > /tmp/badguys
test -s /tmp/badguys && /root/badguys.pl && \
    pfctl -t badguys -T show > /etc/badguys && \
    chmod 660 /etc/badguys
Lastly, I'd had trouble with ftpd(8), and used to have a cron job that monitored ftp console sessions, killing any states from IP addresses that exceeded some number of bytes in console sessions, and updating an ftp-badguys table.

I eventually decided that a patch to ftpd would solve my problem with less overhead, and submitted it to the tech@ mailing list. Part of it was accepted, but not the part that was actually useful -- dropping the connection -- so I run with this (-current) patch:
Code:
Index: ftpd.c
===================================================================
RCS file: /cvs/src/libexec/ftpd/ftpd.c,v
retrieving revision 1.185
diff -u -r1.185 ftpd.c
--- ftpd.c    30 Sep 2008 16:16:21 -0000    1.185
+++ ftpd.c    8 Oct 2008 01:30:51 -0000
@@ -825,7 +825,8 @@
         checkuser(_PATH_FTPCHROOT, name);
     if (anon_only && !dochroot) {
         reply(530, "User %s access denied.", name);
-        return;
+        dologout(0);
+        /* NOTREACHED */
     }
     if (pw) {
         if ((!shell && !dochroot) || checkuser(_PATH_FTPUSERS, name)) {

Last edited by jggimi; 18th February 2009 at 11:37 PM.
Reply With Quote