F*EX use case: anti-hacker configuration

To prevent brute-force hacking attacks with guessed user/auth-ID you can use the function $max_fail_handler() which is undefined in default installations.

$max_fail_handler(remote_ip_address) is called when there are more than $max_fail failed login attempts.

For example, I have the following setup (on Linux):

To allow sudo iptables for user fex:

  root@fex:/etc/sudoers.d# cat iptables
  fex ALL=(root) NOPASSWD:/sbin/iptables
  fex ALL=(root) NOPASSWD:/sbin/ip6tables

  fex@fex:~/bin: cat iptables
  #!/bin/sh
  exec sudo /sbin/iptables "$@"

  fex@fex:~/bin: cat ip6tables
  #!/bin/sh
  exec sudo /sbin/ip6tables "$@"

And then in fex.ph I have:

  my $iptables = '/home/fex/bin/iptables';
  my $ip6tables = '/home/fex/bin/ip6tables';
  my $mail = 'mailx';
  
  $max_fail = 10;

  $max_fail_handler = sub { 
    my $ip = shift;
    local $_;

    if ($ip =~ /:/) {
      system "$ip6tables -A BLOCK -s $ip -j LOGREJECT";
    } else {
      system "$iptables -A BLOCK -s $ip -j LOGREJECT";
    }
    if (open my $m,"| $mail -s 'FEX max_fail $ip' fex") {
      print {$m} "@_\n\n";
      if ($faillog and open $faillog,$faillog) {
        print {$m} $_ while <$faillog>;
        close $faillog;
      }
      close $m;
    }
  };
With this function every ip address will be blocked after there are more than 10 sequent login failures and a notification e-mail is sent to user framstag. A successfull login will reset the counter.

For the curious: If you have defined $max_fail_handler() and $max_fail in /home/fex/lib/fex.ph then you will find the last login failures in /home/fex/spool/.fail/

Another anti-hacking configuration can be done by defining $header_hook() in fex.ph to disallow certain headers. Example:

$header_hook = sub {
  my ($connect,$header,$ip) = @_;
  my (@dl);
  local $_;

  @dl = qw(
    ^GET.*\.\./\.\./
    ^Referer:.*(replica|[Bb]ags|[Gg]ucci|cheap|viagra|-sale)
    ^User-Agent:.MSIE
    ^User-Agent:.Internet.Explorer.4
    ^User-Agent:.Mozilla.*Win2000
    ^User-Agent:.*Windows.9[58]
    ^User-Agent:.Morfeus
    ^User-Agent:.Toplistbot
    ^User-Agent:.Toata
    ^User-Agent:.Sosospider
    ^User-Agent:.Hatena
    ^User-Agent:.bitlybot
    ^User-Agent:.Comodo
    ^User-Agent:.COMODO 
    ^User-Agent:.*daum.net
    ^User-Agent:.*puritysearch
    ^User-Agent:.*Mp3Bot
    ^User-Agent:.*TencentTraveler
    ^User-Agent:.*FunWebProducts
    ^User-agent:.chroot
    ^User-[Aa]gent:.*Baidu
    ^User-Agent:.facebook
    ^User-Agent:.WhatsApp
    ^User-Agent:.mattermost
    ^user-agent:.*Trident/6\.0
  );

  foreach my $dp (@dl) {
    if ($header =~ /$dp/) {
      fexlog($connect,@log,"BADREQUEST $dp");
      http_error(403);
      exit;
    }
  }  
};