bind:無効な再帰クエリのブラックホール?


13

いくつかのドメインの信頼できるネームサーバーであるため、パブリックにアクセス可能なネームサーバーがあります

現在、サーバーにはANYisc.org、ripe.netなどの偽のタイプのリクエストが殺到しています(これは既知の分散DoS攻撃です)。

サーバーはBINDを実行allow-recursionし、これらの要求が拒否されるように私のLANに設定しました。このような場合、サーバーは、ルートサーバーを参照するセクションauthorityadditionalセクションだけで応答します。

応答をまったく送信せずに、これらの要求を完全に無視するようにBINDを構成できますか?

回答:


5

同じ問題に直面して、私はすべての再帰要求を無視することにしました。すべてのリゾルバーは、権限のあるサーバーとしてサーバーを使用する場合、非再帰的なクエリを送信します。私自身の場合、誤って設定されたクライアントと攻撃者のみが再帰クエリを使用します。

残念ながら、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

いいえ、そのルールは信頼できるタイプのリクエストもブロックします(少なくとも私のマシンでは)。どうやらあらゆる種類のDNS要求をブロックしているようです。
ウドG

私は二重にチェックし、私はまさにそのルールを使用しています。以下は、ライブサーバーからのカットアンドペーストです。コマンド:iptables -t raw -S PREROUTING。出力:-P PREROUTING ACCEPT、その後に-A PREROUTING -i eth0 -p udp -m udp --dport 53 -m string --hex-string "|01000001000000000000|" --algo kmp --from 30 --to 65535 -j DROP。で正しく動作することをテストしましたhost -ar exampledomain.com dns-server.example.net。もちろん、-rオプションを追加するまで正しく動作しませんでした。
pino42

さて、-rオプションは違いを生みます。私は個人的には、単純なhostクエリがもう機能しないことを嫌い、これは非常に紛らわしいです。これはおそらく有効な(これまでのところ)答えですが、OUTPUTをフィルタリングして独自のアプローチを使用し続ける場合でも、期限切れが近づいているので、私はあなたに報奨金を与えます。
ウドG

ありがとう!より良い解決策に出くわした場合は、必ず投稿します。私はあなたに同意します:これはハックです。動作するものですが、それでもハックです。
-pino42

2

私が試してみます:

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";します。


私が持っているzone "." { type hint; file "/etc/bind/db.root"; };ルートサーバをリストdb.rootとの宣言を。その宣言を削除すると、外部ドメインの応答は停止しますが、それでもサーバーは「サーバー障害」で応答するため、DoSに引き続き使用できます。
Udo G

@UdoG:構成に追加しようとしallow-query "none";ましたzone "."か?
12

これはアップストリーム帯域幅のみを節約しているように見えますが、これは十分なはずです。修正により、攻撃者はすでにサーバーのダウンストリーム帯域幅と処理能力を
使い果たしました-TheLQ

@TheLQ:この質問は、これがDDoS攻撃であることを示しています。一般的なDNSベースのDDoS攻撃は、ターゲットの偽造IPでDNSクエリを送信することです。DNS応答パケットはクエリよりも大きいため、乗数を提供します。サーバーが非常に大きなパケットで応答しない場合は、攻撃でサーバーを使用している理由を排除しています。
フライハイト

@UdoG:サーバー障害パケットは31〜32のみですが、ルートサーバーへの参照はおそらく数百バイトでした。サーバーの応答がクエリと同じサイズ、またはほんの少し大きい場合、DNS DDoS攻撃ではサーバーは役に立ちません。攻撃者はターゲットに送信する帯域幅を消費するためです。よく構成されている可能性のある多数の信頼できるネームサーバー(Googleなど)に対してテストを行い、「再帰が要求されましたが利用できません」と応答しました。
フライハイト

1

一般的に、私はお勧めします:

バインドログをオンにし、拒否された回答を取得する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

これが役立つことを願っています!


TODO:バインドログファイルの例。
アンドレイ・ミハルツォフ

1

基本的な考え方は、バインドされた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応答のフラグフィールドにキーを設定します

  • DNS応答
  • 再帰クエリ
  • 返信コードが拒否されました

ルールが一致してテスト用のフィードバックがある場合、デバッグ「応答の送信エラー:ホストに到達できません」でバインドを実行しているログメッセージに注意してください。

これはやや無意味な演習であることを認めなければなりません。増幅がない場合、攻撃者はTCP SYNを簡単に反映できます。最終的にDNSは、TCPを使用するか、EastlakeのDNS Cookieを展開する以外に、実行可能なソリューションを破りません。


0

文字列isc.orgをブロックしようとしたか、16進文字列をブロックしようとしましたか?

これは私のために働いた:

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


サーバーが応答するすべてのドメインの16進文字列を特定し、それらを許可するために上記を実行し、他のすべてのudp / 53トラフィックを削除する方が良いでしょうか?
12

現在、ルートサーバーを参照しているUDP応答を既にブロックしています。iptables -A OUTPUT -p udp -m string -hex-string "|726f6f742d73657276657273|" –algo bm –to 65535 -j DROPしかし、可能な場合は、BIND構成に基づいたソリューションを本当に好むでしょう。
ウドG

これは弱いです。ドメインとして任意の文字列を生成できます。現在、この問題に直面していますが、静的な名前でブロックする方法ではありません'bnrexex.www.sf97.net/A/IN' 'whzpkacpxpiuycm.www.tpa.net.cn/A/IN'
3h4x

0

この攻撃はAmplified Denial of Serviceと呼ばれます。バインドを適切に構成する必要がありますが、そもそもそのトラフィックはバインドに到達しないはずです。ネットワークで実行できる最初のネットワークデバイスでブロックします。私は同じ問題を抱えていて、デフォールト・スノート規則で対処しました:

alert udp $ EXTERNAL_NET any-> $ HOME_NET 53(msg: "タイプANYのPROTOCOL-DNS過剰クエリ-潜在的なDoS"; byte_test:1、!&、0xF8,2; content: "| 00 00 FF 00 01 |"; detection_filter:track by_src、カウント30、30秒、metadata:service dns、reference:url、foxpa.ws / 2010/07/21 / thwarting-the-isc-org-dns-ddos /; classtype:attempted-dos; sid :21817; rev:4;)


0

まず、これは古い質問ですが、...

私は何十年もの間、独自の権威ある非再帰的なDNSサーバーを運用してきましたが、DNSベースのDDoS攻撃の被害者になったことはありませんでした。何千ものスプーフィングされた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 を実行して、新しいチェーンの各ルールのパケット(およびバイト)カウンターを表示します(より効率的にするために、ほとんどのパケットを持つゾーンをリストの一番上に移動することができます)。

誰かがこれが便利だと思うことを願って:)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.