bind: blackhole para consultas recursivas inválidas?

13

Eu tenho um servidor de nomes acessível publicamente, pois é o servidor de nomes autoritativo para alguns domínios .

Atualmente, o servidor é inundado com solicitações falsas do tipo ANY para isc.org, ripe.net e semelhantes (isso é um ataque DoS distribuído conhecido ).

O servidor executa o BIND e tem allow-recursion definido para minha LAN para que essas solicitações sejam rejeitadas. Nesses casos, o servidor responde apenas com authority e additional seções referentes aos servidores raiz.

Posso configurar o BIND para que ele ignore completamente essas solicitações sem enviar uma resposta?

    
por Udo G 15.10.2012 / 16:01

7 respostas

5

Perante o mesmo problema, optei por ignorar todos os pedidos recursivos. Todos os resolvedores enviam uma consulta não recursiva quando desejam usar meu servidor como um servidor autoritativo. Apenas clientes e atacantes mal configurados, no meu caso, usam consultas recursivas.

Infelizmente eu não encontrei uma maneira de deixar o BIND fazer isso, mas no caso do iptables ser bom o suficiente para você, eu usei

iptables -t raw -I PREROUTING -i eth0 -p udp --destination-port 53 \
    -m string --algo kmp --from 30 \
    --hex-string "|01000001000000000000|" -j DROP
    
por 03.11.2012 / 20:11
2

Eu tentaria:

zone "." {
  type redirect;
  allow-query "none";
}

As respostas referentes aos clientes para os servidores raiz são controladas pela zona de "redirecionamento". Isso deve dizer para não responder a eles.

Isso é sugerido nos documentos do Bind9: link

Você pode substituir o "none" pela sua sub-rede local.

Se você já tiver uma declaração zone "." , basta adicionar allow-query "none"; a ela.

    
por 28.10.2012 / 20:01
1

Geralmente, eu sugeriria:

Ative os logs de ligação e grave os ips que receberem a resposta rejeitada. Instale o programa fail2ban, adicione a ação blackhole: link (coloque a regra no arquivo em /etc/fail2ban/actions.d)

Crie um arquivo de filtro de ligação em /etc/fail2ban/filter.d com algo assim (precisa de depuração!)

[Definition]
failregex = ^.* security: info: client #<HOST>: query \(cache\) .* denied

Edite o fail2ban.conf, adicione a seção:

[bindban]

enabled  = true
filter   = bind
# "bantime" is the number of seconds that a host is banned.
bantime  = 6000
# A host is banned if it has generated "maxretry" during the last "findtime"
# seconds.
findtime  = 60
# "maxretry" is the number of failures before a host get banned.
maxretry = 150
action   = blackhole
logpath  = /var/log/named.log

Espero que isso ajude!

    
por 02.11.2012 / 16:58
1

A idéia básica permite vincular a classificação da resposta do DNS como Recusado, em seguida, usar o iptables para converter Recusado em silenciosamente ignorado.

Recusado é a parte fácil na seção de opções do named.conf:

allow-recursion { none;};

Ou, claro, suas ACLs favoritas para exceções locais ...

Próxima mágica iptables louca, ajuste ou remova "-o eth0" conforme necessário. Este comando assume o cabeçalho padrão da camada IPv4 de 20 bytes antes do UDP.

iptables -A OUTPUT -o eth0 -p udp --sport 53 -m string --from 30 --to 32 --hex-string "|8105|" --algo bm -j DROP

Estas chaves no campo flags da resposta do DNS com o seguinte conjunto de bits

  • Resposta do DNS
  • Consulta recursiva
  • Código de resposta recusado

Erro na mensagem de log em execução na depuração "erro enviando resposta: host inacessível" quando a regra corresponde a algum feedback para teste.

Deve admitir isso tudo é um exercício um pouco inútil. Se não houver amplificação, um invasor pode facilmente refletir o TCP SYN. Em última análise, o DNS está quebrado simplesmente sem uma solução viável que não seja o uso de TCP ou a implantação de cookies DNS da Eastlake.

    
por 04.06.2014 / 08:55
0

Você tentou bloquear a string isc.org ou bloquear a string hex para ela?

Isso funcionou para mim:

iptables -A INPUT -p udp -m string --hex-string "|03697363036f726700|" --algo bm -j DROP

    
por 28.10.2012 / 19:36
0

Esse ataque é chamado de Negação de Serviço Amplificada. Você deve configurar o bind corretamente, mas o tráfego não deve chegar ao seu bind em primeiro lugar. Bloqueie-o no primeiro dispositivo de rede que seja capaz de fazer isso em sua rede. Eu tive o mesmo problema e lidei com a regra do ronco surdo:

alert udp $EXTERNAL_NET any -> $HOME_NET 53 (msg:"PROTOCOL-DNS excessive queries of type ANY - potential DoS"; byte_test:1,!&,0xF8,2; content:"|00 00 FF 00 01|"; detection_filter:track by_src, count 30, seconds 30; metadata:service dns; reference:url,foxpa.ws/2010/07/21/thwarting-the-isc-org-dns-ddos/; classtype:attempted-dos; sid:21817; rev:4;)

    
por 17.03.2014 / 20:33
0

Primeiro, sei que essa é uma pergunta antiga, mas ...

Eu tenho executado meu próprio servidor DNS autoritativo, não recursivo por décadas, mas nunca fui uma vítima em nenhum ataque DDoS baseado em DNS - até agora, quando mudei para um novo ISP. Milhares de consultas DNS falsas inundaram meus registros e eu fiquei muito aborrecido - não tanto com o impacto no meu servidor, mas com o fato de que ele bagunçou meus logs e a desconfortável sensação de estar sendo abusada. Parece que o invasor tenta usar meu DNS em um “ ataque Authoritative Name Server ".

Então imaginei que, embora eu limite as consultas recursivas à minha rede interna (negando todas as outras), prefiro gastar meus ciclos de CPU em correspondência de cadeia de caracteres em iptables do que enviar respostas negativas aos endereços IP falsificados (menos confusão na minha logs, menos tráfego de rede e um nível de satisfação maior do que eu).

Comecei fazendo todo mundo parecer , descubra quais nomes de domínio são consultados e criei uma correspondência de seqüência de caracteres domínio com um DROP alvo. Mas logo percebi que acabaria com uma enorme quantidade de regras, cada uma delas consumindo ciclos de CPU. Então o que fazer? Como não executo um servidor de nomes recursivo, imaginei que poderia fazer a correspondência nas zonas reais para as quais tenho autoridade e largar todo o resto.

Minha política padrão no iptables é ACCEPT, se sua política for DROP, você provavelmente precisará fazer alguns ajustes se quiser usar a seguinte solução.

Eu mantenho minha configuração de zona em um arquivo separado (/etc/bind/named.conf.local), vamos usar isso como um exemplo:

zone "1.168.192.in-addr.arpa" { // Private
        type master;
        allow-query { 192.168.1.0/24; 127.0.0.1; };
        allow-transfer { 127.0.0.1; };
        file "/etc/bind/db.192.168.1";
};

zone "home.example.net" { // Private
        type master;
        allow-query { 192.168.1.0/24; 127.0.0.1; };
        allow-transfer { 127.0.0.1; };
        file "/etc/bind/pri/db.home.example.net";
};

zone "example.net" {
        type master;
        file "/etc/bind/pri/db.example.net";
        allow-transfer { 127.0.0.1; 8.8.8.8; };
};

zone "example.com" {
        type slave;
        masters { 8.8.8.8; };
        file "sec.example.com";
        allow-transfer { 127.0.0.1; };
        notify no;
};

zone "subdomain.of.example.nu" {
        type slave;
        masters { 8.8.8.8; };
        file "sec.subdomain.of.example.nu";
        allow-transfer { 127.0.0.1; };
        notify no;
};

Observe o comentário "// Particular" nas minhas duas primeiras zonas, faço uso disso no script a seguir para excluí-las da lista de zonas válidas.

#!/usr/bin/perl
# zone2iptables - Richard Lithvall, april 2014
#
# Since we want to match not only example.net, but also (for example)
# www.example.net we need to set a reasonable maximum value for a domain
# name in our zones - 100 character should be more that enough for most people
# and 255 is the absolute maximum allowed in rfc1034.
# Set it to 0 (zero) if you would like the script to fetch each zone (axfr)
# to get the actual max value.
$maxLengthOfQueryName=255;
$externalInterface="eth1";

print "# first time you run this, you will get error on the 3 first commands.\n";
print "# It's here to make it safe/possible to periodically run this script.\n";
print "/sbin/iptables -D INPUT -i $externalInterface -p udp --dport 53 -j DNSvalidate\n";
print "/sbin/iptables -F DNSvalidate\n";
print "/sbin/iptables -X DNSvalidate\n";
print "#\n";
print "# now, create the chain (again)\n";
print "/sbin/iptables -N DNSvalidate\n";
print "# and populate it with your zones\n";
while(<>){
        if(/^zone\s+"(.+)"\s+\{$/){
                $zone=$1;
                if($maxLengthOfQueryName){
                        $max=$maxLengthOfQueryName;
                } else {
                        open(DIG,"dig -t axfr +nocmd +nostats $zone |");
                        $max=0;
                        while(<DIG>){
                                if(/^(.+?)\.\s/){
                                        $max=(length($1)>$max)?length($1):$max;
                                }
                        }
                        close(DIG);
                }
                printf("iptables -A DNSvalidate -m string --from 40 --to %d --hex-string \"",($max+42));
                foreach $subdomain (split('\.',$zone)){
                        printf("|%02X|%s",length($subdomain),$subdomain);
                }
                print("|00|\" --algo bm -j RETURN -m comment --comment \"$zone\"\n");
        }
}
print "# and end the new chain with a drop\n";
print "/sbin/iptables -A DNSvalidate -j DROP\n";
print "# And, at last, make the new chain active (on UDP/53)\n";
print "/sbin/iptables -A INPUT -i $externalInterface -p udp --dport 53 -j DNSvalidate\n";

Execute o script acima com o arquivo de configuração da zona como argumento.

root:~/tmp/# ./zone2iptables.pl /etc/bind/named.conf.local 
# first time you run this, you will get error on the 3 first commands.
# It's here to make it safe/possible to periodically run this script.
/sbin/iptables -D INPUT -i eth1 -p udp --dport 53 -j DNSvalidate
/sbin/iptables -F DNSvalidate
/sbin/iptables -X DNSvalidate
#
# now, create the chain (again)
/sbin/iptables -N DNSvalidate
# and populate it with your zones
iptables -A DNSvalidate -m string --from 40 --to 297 --hex-string "|07|example|03|net|00|" --algo bm -j RETURN -m comment --comment "example.net"
iptables -A DNSvalidate -m string --from 40 --to 297 --hex-string "|07|example|03|com|00|" --algo bm -j RETURN -m comment --comment "example.com"
iptables -A DNSvalidate -m string --from 40 --to 297 --hex-string "|09|subdomain|02|of|07|example|02|nu|00|" --algo bm -j RETURN -m comment --comment "subdomain.of.example.nu"
# and end the new chain with a drop
/sbin/iptables -A DNSvalidate -j DROP
# And, at last, make the new chain active (on UDP/53)
/sbin/iptables -A INPUT -i eth1 -p udp --dport 53 -j DNSvalidate

Salve a saída em um script, canalize-a para um shell ou copie-a e cole-a em seu terminal para criar a nova cadeia e inicie o filtro de todas as consultas DNS inválidas.

executar / sbin / iptables -L DNSvalidate -nvx para ver os contadores de pacotes (e bytes) em cada regra na nova cadeia (você pode querer mover a zona com a maioria dos pacotes para o topo da lista para torná-la mais eficiente).

Na esperança de que alguém possa achar isso útil:)

    
por 08.04.2014 / 16:05