Bind: Blackhole für ungültige rekursive Abfragen?

13

Ich habe einen Nameserver, auf den öffentlich zugegriffen werden kann, da er für einige Domains der maßgebliche Nameserver ist .

Derzeit ist der Server mit gefälschten ANYTypanforderungen für isc.org, mature.net und ähnliches überflutet (dies ist eine bekannte verteilte DoS-Attacke ).

Der Server führt BIND aus und hat allow-recursionsich auf mein LAN eingestellt, damit diese Anfragen abgelehnt werden. In solchen Fällen antwortet der Server nur mit authorityund additionalAbschnitten, die auf die Stammserver verweisen.

Kann ich BIND so konfigurieren, dass diese Anforderungen vollständig ignoriert werden, ohne dass eine Antwort gesendet wird?

Udo G
quelle

Antworten:

5

Angesichts des gleichen Problems habe ich beschlossen, alle rekursiven Anforderungen zu ignorieren. Alle Resolver senden eine nicht rekursive Abfrage, wenn sie meinen Server als autorisierenden Server verwenden möchten. Nur falsch konfigurierte Clients und Angreifer verwenden in meinem Fall rekursive Abfragen.

Leider habe ich keine Möglichkeit gefunden, BIND das zuzulassen, aber für den Fall, dass iptables für Sie gut genug ist, habe ich verwendet

iptables -t raw -I PREROUTING -i eth0 -p udp --destination-port 53 \
    -m string --algo kmp --from 30 \
    --hex-string "|01000001000000000000|" -j DROP
pino42
quelle
Nein, diese Regel blockiert auch autorisierende Anfragen (zumindest auf meinem Computer). Anscheinend blockiert es alle Arten von DNS-Anfragen.
Udo G
Ich habe es zweimal überprüft und verwende genau diese Regel. Hier ist ein Ausschneiden und Einfügen vom Live-Server. Befehl: iptables -t raw -S PREROUTING. Ausgabe: -P PREROUTING ACCEPTgefolgt von -A PREROUTING -i eth0 -p udp -m udp --dport 53 -m string --hex-string "|01000001000000000000|" --algo kmp --from 30 --to 65535 -j DROP. Ich habe getestet, dass es richtig funktioniert host -ar exampledomain.com dns-server.example.net. Natürlich hat es nicht richtig funktioniert, bis ich die -rOption hinzugefügt habe .
Pino42
Okay, die -rOption macht den Unterschied. Ich persönlich mag es nicht, dass einfache hostAbfragen nicht mehr funktionieren und das kann sehr verwirrend sein. Dies ist wahrscheinlich eine gültige (bisher beste) Antwort, und ich gebe Ihnen das Kopfgeld, da es im Begriff ist, abzulaufen, auch wenn ich weiterhin meinen eigenen Ansatz durch Filtern von OUTPUT verwende.
Udo G
Vielen Dank! Wenn ich auf eine bessere Lösung stoße, werde ich sie unbedingt posten. Ich stimme dir zu: Dieser ist ein Hack. Ein funktionierender, aber immer noch ein Hack.
pino42
2

Ich würde versuchen:

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

Die Antworten, die Clients an die Root-Server weiterleiten, werden von der "Redirect" -Zone gesteuert. Dies sollte es sagen, nicht auf diese zu antworten.

Dies ist in den Bind9-Dokumenten angedeutet: http://ftp.isc.org/isc/bind9/cur/9.9/doc/arm/Bv9ARM.ch06.html#id2592674

Sie können mit durch "none"Ihr lokales Subnetz ersetzen .

Wenn Sie bereits eine zone "."Erklärung haben, fügen allow-query "none";Sie diese einfach hinzu .

freiheit
quelle
Ich habe eine zone "." { type hint; file "/etc/bind/db.root"; };Deklaration mit db.root, in der die Stammserver aufgelistet sind. Das Entfernen dieser Deklaration beendet die Antwort für fremde Domains, der Server reagiert jedoch mit einem "Serverausfall" und kann daher weiterhin für DoS verwendet werden.
Udo G
@UdoG: Hast du versucht allow-query "none";, der zone "."Konfiguration etwas hinzuzufügen ?
freiheit
Dies spart anscheinend nur Upstream-Bandbreite, was jedoch ausreichend sein sollte. Mit Ihrem Fix hat der Angreifer die Downstream-Bandbreite und die Rechenleistung Ihrer Server bereits aufgebraucht
TheLQ
@TheLQ: Die Frage bezieht sich darauf, dass es sich um einen DDoS-Angriff handelt. Der übliche DNS-basierte DDoS-Angriff besteht darin, DNS-Abfragen mit der gefälschten IP des Ziels zu senden. Da das DNS-Antwortpaket größer als die Abfrage ist, wird ein Multiplikator bereitgestellt. Wenn Ihr Server nicht mit einem wesentlich größeren Paket antwortet, haben Sie den Grund beseitigt, warum er Ihren Server für den Angriff verwendet.
freiheit
@UdoG: Das Server-Fehlerpaket umfasst nur 31 bis 32, während der Verweis auf die Stammserver wahrscheinlich mehrere hundert Byte betrug. Wenn die Antwort Ihres Servers dieselbe Größe wie die Abfrage hat oder nur ein kleines bisschen größer ist, ist Ihr Server bei einem DNS-DDoS-Angriff unbrauchbar, da die Angreifer so viel Bandbreite verbrauchen, wie Sie zum Senden an ihr Ziel benötigen. Ich habe eine Reihe von wahrscheinlich gut konfigurierten autorisierenden Nameservern (z. B. Google) getestet und sie haben mit "Rekursion angefordert, aber nicht verfügbar" geantwortet.
freiheit
1

Generell würde ich vorschlagen:

Aktivieren Sie Bindungsprotokolle und zeichnen Sie IPS auf, deren Antwort abgelehnt wird. Installieren Sie das fail2ban-Programm und fügen Sie eine Blackhole-Aktion hinzu: http://pastebin.com/k4BxrAeG ( fügen Sie die Regel in die Datei in /etc/fail2ban/actions.d ein)

Erstellen Sie eine Bindungsfilterdatei in /etc/fail2ban/filter.d mit so etwas (muss getestet werden!)

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

Editiere fail2ban.conf, füge Abschnitt hinzu:

[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

Hoffe das wird helfen!

Andrei Mikhaltsov
quelle
TODO: Beispiel für das Binden einer Protokolldatei.
Andrei Mikhaltsov
1

Grundlegende Idee: Lassen Sie Bind die DNS-Antwort als "Abgelehnt" klassifizieren und verwenden Sie dann iptables, um "Abgelehnt" in "Im Hintergrund ignoriert" zu konvertieren.

Abgelehnt ist der einfache Teil im Abschnitt named.conf options:

allow-recursion { none;};

Oder natürlich Ihre bevorzugten ACLs für lokale Ausnahmen ...

Als nächstes magische verrückte iptables, passe "-o eth0" nach Bedarf an oder entferne es. Bei diesem Befehl wird ein Standard-20-Byte-IPv4-Schicht-Header vor UDP vorausgesetzt.

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

Dieser Schlüssel im Flags-Feld der DNS-Antwort enthält die folgenden gesetzten Bits

  • DNS-Antwort
  • Rekursive Abfrage
  • Antwortcode abgelehnt

Bemerkte Protokollnachricht, die beim Debuggen bind ausgeführt wird "Fehler beim Senden der Antwort: Host nicht erreichbar", wenn die Regel übereinstimmt, um Feedback zum Testen zu erhalten.

Ich muss zugeben, dass dies alles eine etwas sinnlose Übung ist. Wenn es keine Verstärkung gibt, kann ein Angreifer genauso gut TCP SYN widerspiegeln. Letztendlich ist DNS einfach keine praktikable Lösung außer der Verwendung von TCP oder der Bereitstellung von Eastlake-DNS-Cookies.

Scheibenfresser
quelle
0

Haben Sie versucht, die Zeichenfolge isc.org zu blockieren oder die Hex-Zeichenfolge dafür zu blockieren?

Das hat bei mir funktioniert:

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

Verhexen
quelle
Wäre es nicht besser, die hexadezimalen Zeichenfolgen für alle Domänen zu identifizieren, auf die der Server antworten soll, die oben genannten Schritte auszuführen, um diese zuzulassen und den gesamten anderen udp / 53-Verkehr zu löschen?
freiheit
Ich blockiere derzeit bereits UDP-Antworten, die sich auf die Stammserver beziehen. iptables -A OUTPUT -p udp -m string -hex-string "|726f6f742d73657276657273|" –algo bm –to 65535 -j DROPIch würde jedoch eine Lösung vorziehen, die nur auf der BIND-Konfiguration basiert, sofern dies überhaupt möglich ist.
Udo G
das ist schwach. Sie können jeden gewünschten Stich als Domain generieren. Wir stehen vor diesem Problem und es ist nicht die Möglichkeit, es über einen statischen Namen zu blockieren'bnrexex.www.sf97.net/A/IN' 'whzpkacpxpiuycm.www.tpa.net.cn/A/IN'
3h4x
0

Dieser Angriff wird als Amplified Denial of Service bezeichnet. Sie sollten die Bindung richtig konfigurieren, aber dieser Datenverkehr sollte nicht an erster Stelle zu Ihrer Bindung gelangen. Blockieren Sie es auf dem ersten Netzwerkgerät, das es in Ihrem Netzwerk ausführen kann. Ich hatte das gleiche Problem und behandelte es mit taubem Schnauben:

alert udp $ EXTERNAL_NET any -> $ HOME_NET 53 (msg: "PROTOKOLL-DNS übermäßige Anfragen vom Typ ANY - potentieller DoS"; byte_test: 1,! &, 0xF8,2; content: "| 00 00 FF 00 01 |"; Erkennungsfilter: track by_src, count 30, seconds 30; Metadaten: Service-DNS; Referenz: url, foxpa.ws / 2010/07/21 / das-isc-org-dns-ddos vereiteln /; Classtype: attempted-dos; sid : 21817; rev: 4;)

3h4x
quelle
0

Erstens weiß ich, dass dies eine alte Frage ist, aber ...

Ich habe jahrzehntelang meinen eigenen autorisierenden, nicht rekursiven DNS-Server betrieben, war aber noch nie Opfer von DNS-basierten DDoS-Angriffen - bis jetzt, als ich zu einem neuen ISP wechselte. Tausende von gefälschten DNS-Abfragen überfluteten meine Protokolle und ich ärgerte mich sehr - nicht so sehr über die Auswirkungen auf meinen Server, sondern vielmehr über die Tatsache, dass meine Protokolle überfüllt sind und das unangenehme Gefühl, missbraucht zu werden. Es scheint, dass der Angreifer versucht, mein DNS in einem " Authoritative Name Server-Angriff " zu verwenden.

Obwohl ich rekursive Abfragen auf mein internes Netzwerk beschränke (alle anderen verweigere), verbringe ich meine CPU-Zyklen lieber damit, Zeichenfolgen in iptables abzugleichen, als negative Antworten auf die gefälschten IP-Adressen zurückzusenden (weniger Unordnung in meinen Protokollen, weniger) Netzwerkverkehr und eine höhere Zufriedenheit von mir).

Ich begann damit, wie es alle anderen zu tun scheinen , herauszufinden, welche Domainnamen abgefragt werden, und eine Zeichenfolgenübereinstimmung für diese Domain mit einem Ziel-DROP zu erstellen. Aber mir wurde schnell klar, dass ich am Ende eine Menge Regeln haben würde, die jeweils CPU-Zyklen beanspruchen. Also, was ist zu tun? Da ich keinen rekursiven Nameserver betreibe, habe ich mir vorgenommen, den Abgleich für die tatsächlichen Zonen vorzunehmen, für die ich zuständig bin, und alles andere zu löschen.

Meine Standardrichtlinie in iptables ist ACCEPT. Wenn Ihre Richtlinie DROP ist, müssen Sie möglicherweise einige Anpassungen vornehmen, wenn Sie die folgende Lösung verwenden möchten.

Ich behalte meine Zonenkonfiguration in einer separaten Datei (/etc/bind/named.conf.local), verwenden wir dies als Beispiel:

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;
};

Beachten Sie den Kommentar „// Privat“ zu meinen ersten beiden Zonen. Ich verwende diesen im folgenden Skript, um sie aus der Liste der gültigen Zonen auszuschließen.

#!/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";

Führen Sie das obige Skript mit der Zonenkonfigurationsdatei als Argument aus.

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

Speichern Sie die Ausgabe in einem Skript, leiten Sie sie an eine Shell weiter oder kopieren Sie sie und fügen Sie sie in Ihr Terminal ein, um die neue Kette zu erstellen und alle ungültigen DNS-Abfragen herauszufiltern.

Führen Sie / sbin / iptables -L DNSvalidate -nvx aus , um die Paket- (und Byte-) Zähler für jede Regel in der neuen Kette anzuzeigen (möglicherweise möchten Sie die Zone mit den meisten Paketen an den Anfang der Liste verschieben, um sie effizienter zu gestalten).

In der Hoffnung, dass jemand dies nützlich finden könnte :)

Reich
quelle