私は、がいくつかのドメインの権威ネームサーバーであるため、公的にアクセス可能なネームサーバーを持っています。
現在、サーバーはisc.orgやripe.netなどの偽のタイプANY
リクエストで溢れています(これは 既知の分散型DoS攻撃 です)。
サーバーはBINDを実行し、allow-recursion
これらの要求が拒否されるように私のLANに設定します。このような場合、サーバーはルートサーバーを参照するauthority
およびadditional
セクションのみで応答します。
応答をまったく送信せずに、これらの要求を完全に無視するようにBINDを構成できますか?
同じ問題に直面して、私はすべての再帰的なリクエストを無視することにしました。すべてのリゾルバーは、私のサーバーを権限のあるサーバーとして使用する場合、非再帰クエリを送信します。私の場合、誤設定されたクライアントと攻撃者のみが再帰クエリを使用します。
残念ながら、BINDにそれを実行させる方法は見つかりませんでしたが、iptablesで十分な場合は、
iptables -t raw -I PREROUTING -i eth0 -p udp --destination-port 53 \
-m string --algo kmp --from 30 \
--hex-string "|01000001000000000000|" -j DROP
私はしようとします:
zone "." {
type redirect;
allow-query "none";
}
クライアントをルートサーバーに参照させる応答は、「リダイレクト」ゾーンによって制御されます。これはそれらに返信しないようにそれを言うべきです。
これはBind9ドキュメントでほのめかされています: http://ftp.isc.org/isc/bind9/cur/9.9/doc/arm/Bv9ARM.ch06.html#id2592674
"none"
をローカルサブネットに置き換えることができます。
すでにzone "."
宣言がある場合は、それにallow-query "none";
を追加するだけです。
基本的な考え方は、バインドにDNS応答を拒否として分類させ、次にiptablesを使用して拒否を黙って無視するように変換します。
拒否はnamed.confオプションセクションの簡単な部分です:
allow-recursion { none;};
またはもちろん、ローカル例外のお気に入りのACL ...
次にクレイジーなiptablesの魔法、必要に応じて「-o eth0」を調整または削除します。このコマンドは、UDPの前に標準の20バイトのIPv4層ヘッダーを想定しています。
iptables -A OUTPUT -o eth0 -p udp --sport 53 -m string --from 30 --to 32 --hex-string "|8105|" --algo bm -j DROP
次のビットが設定されたDNS応答のフラグフィールドのこのキー
ルールが一致してテスト用のフィードバックがある場合に、デバッグでバインドを実行していることに気づいたログメッセージ「エラー送信応答:ホストに到達できません」。
これはすべてやや無意味な練習であることを認めなければなりません。増幅がない場合、攻撃者は同じように簡単に反映できますTCP SYN。最終的にDNSは壊れていますTCPまたはEastlakeのDNSの展開を使用する以外に実行可能な解決策はありませんクッキー。
一般的に、私はお勧めします:
バインドログをオンにし、拒否された回答を取得するIPを記録します。 fail2banプログラムをインストールし、ブラックホールアクションを追加します: http://Pastebin.com/k4BxrAeG (/etc/fail2ban/actions.dのファイルにルールを配置)
/etc/fail2ban/filter.dに次のようなバインドフィルターファイルを作成します(デバッグが必要です!)
[Definition]
failregex = ^.* security: info: client #<Host>: query \(cache\) .* denied
Fail2ban.confを編集し、セクションを追加します。
[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
これが役立つことを願っています!
この攻撃は、増幅サービス拒否と呼ばれます。バインドを適切に設定する必要がありますが、そのトラフィックは最初からバインドに到達しないはずです。ネットワークで実行できる最初のネットワークデバイスでブロックします。私は同じ問題を抱えており、デフォルトの鼻咽喉科のルールで対処しました:
alert udp $ EXTERNAL_NET any-> $ HOME_NET 53(msg: "PROTOCOL-DNS過度のクエリタイプANY-潜在的な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;リビジョン:4;)
文字列isc.orgをブロックしたり、16進数文字列をブロックしたりしましたか?
これは私のために働きました:
iptables -A INPUT -p udp -m string --hex-string "| 03697363036f726700 |" --algo bm -j DROP
まず、これが古い質問であることは知っていますが...
私は何十年も自分の権威のある非再帰的なDNSサーバーを実行してきましたが、これまでDNSベースのDDoS攻撃の被害を受けたことはありませんでした。これまで、新しいISPに切り替えました。何千ものスプーフィングされたDNSクエリがログに殺到し、私は本当にサーバーに影響を与えたのではなく、ログが乱雑になり、悪用されたという不快な気持ちに苛立ったりしました。攻撃者は「 権威ネームサーバー攻撃 」で私のDNSを使用しようとするようです。
したがって、内部ネットワークへの再帰クエリを制限し(他のすべてを拒否)、たとえ偽装されたIPアドレスに否定応答を返すよりも、CPUサイクルをiptablesの文字列マッチングに費やしていると考えました(ログの乱雑さが少なく、ネットワークトラフィックと私自身のより高い満足度)。
私は 他の誰もがそうしているように見える として実行することから始め、どのドメイン名が照会され、ターゲットDROPを使用してそのドメインで文字列一致を作成したかを確認します。しかし、すぐに大量のルールが作成され、それぞれがCPUサイクルを消費することに気づきました。じゃあ何をすればいいの?私は再帰的なネームサーバーを実行していないので、信頼できる実際のゾーンでマッチングを実行し、それ以外のものはすべて削除する可能性があると考えました。
IptablesのデフォルトのポリシーはACCEPTです。ポリシーがDROPの場合、次のソリューションを使用する場合は、おそらくいくつかの調整を行う必要があります。
ゾーン構成を別のファイル(/etc/bind/named.conf.local)に保持しています。これを例として使用してみましょう。
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;
};
最初の2つのゾーンに関する「// Private」コメントに注意してください。これを次のスクリプトで使用して、有効なゾーンのリストから除外します。
#!/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";
引数としてゾーン構成ファイルを使用して上記のスクリプトを実行します。
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
出力をスクリプトに保存し、それをシェルにパイプするか、コピーしてターミナルに貼り付け、新しいチェーンを作成し、すべての無効なDNSクエリを除外します。
/ sbin/iptables -L DNSvalidate -nvxを実行して、新しいチェーンの各ルールのパケット(およびバイト)カウンターを確認します(より効率的にするために、ほとんどのパケットがリストの先頭に来るゾーン。
誰かがこれが役立つと思うことを願って:)