Compartilhamento de IPs banidos por fail2ban

14

Estou usando o fail2ban em todos os servidores com serviços visíveis publicamente e me pergunto:

  1. Existe uma maneira fácil de compartilhar IPs proibidos entre hosts que eu controle?
  2. Existe um serviço que coleta e publica esses dados?

Tenho recebido inúmeras tentativas de login desde o primeiro dia de configuração deste servidor.

    
por ndemou 02.09.2014 / 12:20

6 respostas

5

Uma vez vi um sistema para centralizar os dados do fail2ban neste site , e criou uma versão modificada. O banco de dados é o mesmo, mas eu mudei e criei alguns scripts.

Meu sistema tem 4 componentes:

  1. banco de dados fail2ban

    É um banco de dados MySQL contendo apenas uma tabela: erp_core_fail2ban :

    CREATE TABLE IF NOT EXISTS 'erp_core_fail2ban' (
      'id' bigint(20) unsigned NOT NULL AUTO_INCREMENT,
      'hostname' varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
      'created' datetime NOT NULL,
      'name' text COLLATE utf8_unicode_ci NOT NULL,
      'protocol' varchar(16) COLLATE utf8_unicode_ci NOT NULL,
      'port' varchar(32) COLLATE utf8_unicode_ci NOT NULL,
      'ip' varchar(64) COLLATE utf8_unicode_ci NOT NULL,
      PRIMARY KEY ('id'),
      KEY 'hostname' ('hostname','ip')
    ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
    
  2. fail2ban.php

    Toda vez que um host for banido, ele será preenchido pelo banco de dados:

    
    <?php
    require_once("/etc/fail2ban/phpconfig.php");
    
    $name = $_SERVER["argv"][1];
    $protocol = $_SERVER["argv"][2];
    $port = $_SERVER["argv"][3];
    if (!preg_match('/^\d{1,5}$/', $port))
        $port = getservbyname($_SERVER["argv"][3], $protocol);
    $ip = $_SERVER["argv"][4];
    
    $hostname = gethostname();
    
    $query = "INSERT INTO 'erp_core_fail2ban' set hostname='" . addslashes($hostname) . "', name='" . addslashes($name) ."', protocol='" . addslashes($protocol) . "', port='" . addslashes($port) . "', ip='" . addslashes($ip) . "', created=NOW()";
    $result = mysql_query($query) or die('Query failed: ' . mysql_error());
    mysql_close($link);
    exit;
    ?>
    
  3. cron2ban

    Você coloca isso para rodar no crontab, a cada minuto. Ele recuperará os últimos hosts adicionados e os banirá.

    
    <?php
    // phpconfig.php will have database configuration settings
    require_once("/etc/fail2ban/phpconfig.php");
    
    // file with only a line, containing the last id banned
    $lastbanfile="/etc/fail2ban/lastban";
    
    $lastban = file_get_contents($lastbanfile);
    
    // select only hosts banned after last check
    $sql = "select id, ip from erp_core_fail2ban where id > $lastban";
    $result = mysql_query($sql) or die('Query failed: ' . mysql_error());
    mysql_close($link);
    
    while ($row = mysql_fetch_array($result)) {
            //
            $id = $row['id'];
            $ip = $row['ip'];
    
    
        exec("fail2ban-client set $jail banip $ip");
    
    } // $ id contém o último host banido, adicione-o ao arquivo de configuração file_put_contents ($ lastbanfile, $ id); >
  4. phpconfig

    Este arquivo vai para / etc / fail2ban e tem configuração do banco de dados e seleção de cadeia.

    
    <?php
    // jail to be used
    $jail = "ssh";
    
    // file to keep the last ban
    $lastbanfile="/etc/fail2ban/lastban";
    
    // database configuration
    $dbserver="localhost";
    $dbuser="root";
    $dbpass="root";
    $dbname="fail2ban";
    
    // connect to database
    $link = mysql_connect($dbserver, $dbuser, $dbpass) or die('Could not connect: ' . mysql_error());
    mysql_select_db($dbname) or die('Could not select database');
    
    ?>
    

Crie esses arquivos e altere a configuração do fail2ban:

Após a linha com actionban = ..... , uma nova linha inserida para invocar o script PHP:

/root/fail2ban.php <name> <protocol> <port> <ip>

Usar essa estrutura em todos os seus servidores garantirá que toda vez que um host for banido em um servidor, todos os outros servidores o banirão também.

    
por 02.09.2014 / 18:08
3

Então eu fiz um monte de pesquisas sobre como fazer isso depois de ver o mesmo endereço IP atingir meu cluster de servidores web um após o outro. Como estou usando a AWS, percebi que poderia haver uma maneira fácil e está funcionando perfeitamente nos primeiros dois dias de teste de 5 servidores.

A primeira coisa que eu recomendo é temporariamente desabilitar o SELinux, nós vamos lidar com isso no final. Eu não sou um especialista em SELinux, mas o que eu fiz até agora.

O principal requisito é uma fonte de arquivo compartilhada, uso o AWS EFS. Uma vez que a nova unidade é provisionada e montada, alterei logtarget dentro de /etc/fail2ban/fail2ban.conf para uma subpasta na unidade EFS.

logtarget = /efsmount/fail2ban/server1.log

Então eu escrevi um filtro simples e coloquei em /etc/fail2ban/filter.d/fail2ban-log.conf

[Definition]

failregex = .* Ban <HOST>

ignoreregex =

Adicionado o filtro para /etc/fail2ban/jail.local

[fail2ban-log]
enabled = true
port = http,https
findtime = 86400 ; 1 day
logpath  = /efsmount/fail2ban/server1.log
        /efsmount/fail2ban/server2.log
        /efsmount/fail2ban/server3.log
        /efsmount/fail2ban/server4.log
maxretry = 1

Em seguida, reiniciei o fail2ban

sudo fail2ban-client reload

Até aí tudo bem! Nenhuma parte dolorosa é o SELinux. Depois que eu deixei o fail2ban rodar um pouco, eu executei esse comando que permitiria que o fail2ban passasse pelos filtros.

sudo grep fail2ban /var/log/audit/audit.log | sudo audit2allow -M fail2ban-nfs

Audit2allow dirá para você executar este comando

sudo semodule -i fail2ban-nfs.pp

Ainda estou verificando meus logs do SELinux aqui e ali para ver se há mais negações. Se alguém tiver uma dica sobre como obter esse claro SELinux com outro método que seria incrível.

sudo cat /var/log/audit/audit.log |grep fail2ban |grep denied

Neste ponto, eu ainda estava recebendo erros ao reiniciar o fail2ban. Há um bug ao usar action = action_mwl em jail.local. Depois de um pouco de googling eu encontrei isso que está funcionando até agora. Pelo que eu li é por causa das quebras de linha na diretiva de logpath apontando para vários arquivos. Eu tentei com vírgulas, espaços, etc nada mais funcionou com action_mwl.

action_mwm = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
             %(mta)s-whois-matches[name=%(__name__)s, dest="%(destemail)s", chain="%(chain)s"]

action = %(action_mwm)s

Não se esqueça de ligar novamente o SELinux!

    
por 06.07.2016 / 23:42
1

Acabei de implementar isso e até agora parece estar funcionando bem. No entanto, tive que atualizar alguns dos php porque os scripts na resposta original usam funções obsoletas.

Aqui estão os scripts atualizados

phpconfig.php

#!/usr/bin/php
<?php
// jail to be used
$jail = "ssh";

// file to keep the last ban
$lastbanfile="/etc/fail2ban/lastban";

// database configuration
$dbserver="[your.mysql.hostname]";
$dbport="[sql.port.default.is.3306]";
$dbuser="[sql.user";
$dbpass="[sql.password]";
$dbname="[sql.table]";

// connect to database
$link = mysqli_connect($dbserver, $dbuser, $dbpass, $dbname, $dbport) or die('Could not connect: ' . mysqli_error());
mysqli_select_db($link,$dbname) or die('Could not select database');

?>

fail2ban.php

#!/usr/bin/php 
<?php
require_once("/etc/fail2ban/phpconfig.php");

$name = $_SERVER["argv"][1];
$protocol = $_SERVER["argv"][2];
$port = $_SERVER["argv"][3];
if (!preg_match('/^\d{1,5}$/', $port))
    $port = getservbyname($_SERVER["argv"][3], $protocol);
$ip = $_SERVER["argv"][4];

$hostname = gethostname();

$query = "INSERT INTO erp_core_fail2ban (hostname,created,name,protocol,port,ip) VALUES ('$hostname',NOW(),'$name','$protocol','$port','$ip')";
echo $query;
$result = mysqli_query($link,$query) or die('Query failed: ' . mysqli_error($link));
mysqli_close($link);
exit;
?>

cron2ban.php

#!/usr/bin/php
<?php
// phpconfig.php will have database configuration settings
require_once("/etc/fail2ban/phpconfig.php");

// file with only a line, containing the last id banned
$lastbanfile="/etc/fail2ban/lastban";

$lastban = file_get_contents($lastbanfile);
// select only hosts banned after last check
$sql = "SELECT id,ip FROM erp_core_fail2ban WHERE id > $lastban";
$result = mysqli_query($link,$sql) or die('Query failed: ' . mysqli_error($link));
mysqli_close($link);

while ($row = mysqli_fetch_array($result)) {
        //
        $id = $row['id'];
        $ip = $row['ip'];

    exec("fail2ban-client set $jail banip $ip");


}

// $id contains the last banned host, add it to the config file
file_put_contents($lastbanfile, $id);
?>

Além disso, onde quer que você coloque a ação fail2ban.php, ela deve ser indentada tanto quanto a linha acima dela. Por exemplo:

actionban = ...
            /etc/fail2ban/fail2ban.php

Caso contrário, o fail2ban não será iniciado. Espero que isso ajude alguém tentando implantar isso.

    
por 06.02.2015 / 15:54
0

Sim e sim. Ambos podem ser feitos.

Você precisa encontrar um mecanismo adequado para compartilhar a lista de IPs. Se você estiver usando o AWS, por exemplo, poderá aproveitar o s3. Você poderia usar rsync entre hosts Linux ou um banco de dados comum a todos os hosts. Você pode criar um serviço com sua linguagem de programação favorita que fornece uma API tranquila. A escolha é sua.

Em termos de compartilhamento de lista aliado ao público, você poderia criar um site e hospedar um arquivo de texto simples, alguns já fornecem essas listas (não crowdsourcing que eu conheço). Como criar seu próprio site / serviço estaria fora do escopo de uma resposta, no entanto, não deveria ser terrivelmente difícil de fazer.

    
por 02.09.2014 / 12:22
0
Is there an easy way to share banned IPs between hosts I control?

Uma configuração bastante manual seria alterar a configuração que chama iptables para atualizar as regras para que ele chame um script criado por você, que percorra uma lista de hosts (lida de um arquivo?) e torne o iptables chama cada um via SSH. Você precisaria de autenticação baseada em chave entre todos os hosts configurados para isso funcionar. As ferramentas de automação de administração, como o boneco, podem facilitar essa configuração e mantê-lo. Isso não seria terrivelmente eficiente, mas a menos que você veja uma enorme quantidade de tráfego sondagem (e / ou tem um grande número de hosts), então eu tenho certeza que seria bom o suficiente. Se você tem apenas alguns hosts, então você nem precisa percorrer um arquivo: configure cada um para apenas chamar os outros em ordem. O esforço de script será mínimo.

Is there a way to share banned IPs publicly?

Não há dúvidas de muitas maneiras. Ter o (s) script (s) acima soltando os dados em um banco de dados e fazer com que os clientes leiam a partir dele, pesquisando novas regras e executando-as quando elas chegarem. O simples "executar uma regra como você a vê" não será perfeito se hosts estão enviando informações, por exemplo, neste caso:

  1. Às 12:00, o servidor 1 diz "ban host X now" e "unban host X em uma hora".
  2. Às 12:45, o servidor 2 diz "banir host X agora" e "anular o host X em uma hora".
  3. A sobreposição significa que o servidor 3 banirá o host X por uma hora, não uma hora + 45 minutos, se seguir as instruções na ordem.

mas isso não deve ser um problema significativo, e se você for um pouco mais inteligente com o banco de dados, você poderá gerenciar vários envios com mais clareza se decidir que valeu a pena o esforço.

Executar isso como um serviço público abriria você para um mundo de aborrecimento administrativo:

  • Gerenciando a largura de banda e outros recursos se você conquistar muitos usuários.
  • Organizando e aplicando métodos de pagamento caso você tente lidar com a questão do recurso, cobrando pelo acesso de alguma forma.
  • Lidando com tentativas de poluir seu banco de dados, um ator mal intencionado tentando impedir que um concorrente seja banido dos lugares que assinaram a lista como uma tentativa comercial de inconveniência ou chantagem.
  • Lidar com reclamações quando alguém é banido e acha que não deveria ser.
  • Lidar com ataques DDoS que serão acontecerão se o seu serviço tiver sucesso em incomodar os robôs de alguém.
por 02.09.2014 / 15:42
0

Uma alternativa para fail2ban é DenyHosts , que vem com uma funcionalidade de sincronização. A instalação é bastante semelhante a fail2ban , consulte O tutorial da Cyberciti para mais detalhes .

O problema é que o serviço de sincronização é centralizado e o código-fonte do lado do servidor parece não estar disponível , então você não pode facilmente iniciar seu próprio serviço DenyHosts e você tem que confiar em terceiros (o que pode ser bom para alguns casos de uso).

    
por 13.02.2017 / 11:39

Tags