Skip to content

Commit

Permalink
update to 1.2.6:
Browse files Browse the repository at this point in the history
- match more failure log entries for recent openssh versions
- resolve reverse dns records for blocked IPs
  • Loading branch information
dgerzo authored and Yasuhiro KIMURA committed Dec 18, 2018
1 parent fe9ffe9 commit fc3f3e4
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 13 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
BruteForceBlocker v1.2.6 - Nov 3 2018
- add new regexps to match more failure log entries of recent OpenSSH versions
- resolve reverse DNS of blocked IPs

BruteForceBlocker v1.2.5 - Feb 11 2018
- add a new regexp to match another failure log entry
- contributed by Yasuhiro KIMURA

BruteForceBlocker v1.2.4 - Sep 2 2017
- add a new regexp to match failure log entries of recent OpenSSH versions
- contributed by Max Khon
Expand Down
6 changes: 4 additions & 2 deletions CREDITS
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@

Thanks to:

- Jonas Davidsson and Matt Pearce for good ideas
- J.R. Oldroyd for great ideas, he is also one of the reasons why
BruteForceBlocker v1.2 was released
- Branislav Gerzo for some perl coding hints and help with code cleanup
- Kan Sasaki who sent me a patch for BruteForceBlocker which allows to
resolve reverze DNS to an IP address
resolve reverse DNS to an IP address
- Max Khon for regexp to match recent OpenSSH failure log entries
- Yasuhiro KIMURA for regexp to match another failure log entry
- Balazs Mateffy for new regexps to match more failure log entr and
an idea to resolve reverse DNS records for blocked IPs
2 changes: 1 addition & 1 deletion README
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
BruteForceBlocker v1.2.4
BruteForceBlocker v1.2.6

BruteForceBlocker is a perl script, that works along with pf - OpenBSD's
firewall (which is also available on FreeBSD and NetBSD) and its main
Expand Down
25 changes: 15 additions & 10 deletions bruteforceblocker.pl
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
require '/usr/local/etc/bruteforceblocker.conf';

my $work = {
version => '1.2.4',
version => '1.2.6',
ipv4 => '(?:\d{1,3}\.){3}\d{1,3}', # regexp to match ipv4 address
ipv6 => '[\da-fA-F:]+', # regexp to match ipv6 address
fqdn => '[\da-z\-.]+\.[a-z]{2,4}', # regexp to match fqdn
Expand All @@ -35,15 +35,15 @@
}
close(TABLE) or syslog("notice", "Couldn't close $cfg->{tablefile}");

syslog('notice', 'downloading blacklist from project site') if $cfg->{debug};
syslog('notice', 'downloading blacklist from the project site') if $cfg->{debug};

# download the list from project site and load IPs to @remoteIPs array
if ( my $content = download("$work->{projectsite}/blist.php?mindays=$cfg->{mindays}&mincount=$cfg->{mincount}") ) {
while( $content =~ /^($work->{ipv4}|$work->{ipv6})/gm ) {
push(@{$work->{remoteIPs}}, $1);
}
} else {
syslog('notice', "Can't download IP blacklist from project site") if $cfg->{debug};
syslog('notice', "Unable to download IP blacklist from the project site") if $cfg->{debug};
}

# get IPs that we don't have in local pf table
Expand All @@ -67,7 +67,7 @@
syslog('notice', "Couldn't add $work->{pool} to firewall");
}
}
syslog('notice', 'blacklist synchronized with project site') if $cfg->{debug};
syslog('notice', 'blacklist synchronized with the project site') if $cfg->{debug};
}

my %count = (); # hash used to store total number of failed tries
Expand All @@ -78,11 +78,13 @@

while (<>) {
if (/.*Failed password.*from ($work->{ipv4}|$work->{ipv6}|$work->{fqdn}) port.*/i ||
/.*Failed keyboard.*from ($work->{ipv4}|$work->{ipv6}|$work->{fqdn}) port.*/i ||
/.*Invalid user.*from ($work->{ipv4}|$work->{ipv6}|$work->{fqdn})$/i ||
/.*Did not receive identification string from ($work->{ipv4}|$work->{ipv6}|$work->{fqdn})$/i ||
/.*Bad protocol version identification .* from ($work->{ipv4}|$work->{ipv6}|$work->{fqdn})$/i ||
/.*User.*from ($work->{ipv4}|$work->{ipv6}|$work->{fqdn}) not allowed because.*/i ||
/.*error: maximum authentication attempts exceeded for.*from ($work->{ipv4}|$work->{ipv6}|$work->{fqdn}).*/i ||
/.*error: PAM: authentication error for.*from ($work->{ipv4}|$work->{ipv6}|$work->{fqdn}).*/i ||
/.*fatal: Unable to negotiate with ($work->{ipv4}|$work->{ipv6}|$work->{fqdn}).*/i) {

my $IP = $1;
Expand Down Expand Up @@ -124,8 +126,11 @@ sub download {
sub block {
my ($IP) = shift or die "Need IP!\n";

my $query = $res->search($IP, "PTR");
my $RDNS = $query ? ($query->answer)[0]->ptrdname : "not resolved";

if ($timea{$IP} && ($timea{$IP} < time - $cfg->{timeout})) {
syslog('notice', "resetting $IP count, since it wasn't active for more than $cfg->{timeout} seconds") if $cfg->{debug};
syslog('notice', "resetting $IP ($RDNS) count, since it wasn't active for more than $cfg->{timeout} seconds") if $cfg->{debug};
delete $count{$IP};
}
$timea{$IP} = time;
Expand All @@ -134,11 +139,11 @@ sub block {
$count{$IP}++;

if ($cfg->{debug} && ($count{$IP} < $cfg->{max_attempts}+1)) {
syslog('notice', "$IP was logged with total count of $count{$IP} failed attempts");
syslog('notice', "$IP ($RDNS) was logged with total count of $count{$IP} failed attempts");
}

if ($count{$IP} == $cfg->{max_attempts}+1) {
syslog('notice', "IP $IP reached maximum number of failed attempts!") if $cfg->{debug};
syslog('notice', "IP $IP ($RDNS) reached maximum number of failed attempts!") if $cfg->{debug};
if (!grep { /$IP/ } @{$cfg->{whitelist}}) {
$work->{pool} = $IP . '/32' if ($IP =~ /\./); # block whole ipv4 pool
$work->{pool} = $IP . '/128' if ($IP =~ /\:/); # block while ipv6 pool
Expand All @@ -149,14 +154,14 @@ sub block {
syslog('notice', "Couldn't add $cfg->{pool} to firewall");
system("$cfg->{pfctl} -k $IP") == 0 ||
syslog('notice', "Couldn't kill all states for $IP");
system("echo '$work->{pool}\t\t# $work->{timea}' >> $cfg->{tablefile}") == 0 ||
system("echo '$work->{pool}\t\t# $work->{timea} ($RDNS)' >> $cfg->{tablefile}") == 0 ||
syslog('notice', "Could't write $work->{pool} to $cfg->{table}'s table file");

# send mail if it is configured
if ($cfg->{email} && $cfg->{email} ne '') {
syslog('notice', "sending email to $cfg->{email}") if $cfg->{debug};
open(MAIL, "| $cfg->{mail} -s '$work->{hostname}: BruteForceBlocker blocking $work->{pool}' $cfg->{email}");
print (MAIL "BruteForceBlocker blocking $work->{pool} in pf table $cfg->{table}\n");
open(MAIL, "| $cfg->{mail} -s '$work->{hostname}: BruteForceBlocker blocking $work->{pool} ($RDNS)' $cfg->{email}");
print (MAIL "BruteForceBlocker blocking $work->{pool} ($RDNS) in pf table $cfg->{table}\n");
close(MAIL);
}
;
Expand Down

0 comments on commit fc3f3e4

Please sign in to comment.