bind: blackhole untuk kueri rekursif tidak valid?

13

Saya memiliki server nama yang dapat diakses publik karena itu adalah server nama resmi untuk beberapa domain .

Saat ini server dibanjiri dengan ANYpermintaan jenis palsu untuk isc.org, ripe.net dan sejenisnya (itu adalah serangan DoS terdistribusi yang dikenal ).

Server menjalankan BIND dan telah allow-recursiondiatur ke LAN saya sehingga permintaan ini ditolak. Dalam kasus seperti itu, server merespons hanya dengan authoritydan additionalbagian merujuk ke server root.

Dapatkah saya mengonfigurasi BIND sehingga benar-benar mengabaikan permintaan ini, tanpa mengirim jawaban sama sekali?

Udo G
sumber

Jawaban:

5

Menghadapi masalah yang sama, saya memilih untuk mengabaikan semua permintaan rekursif. Semua resolver memang mengirim permintaan non-rekursif ketika mereka ingin menggunakan server saya sebagai server otoritatif. Hanya klien dan penyerang yang tidak terkonfigurasi, dalam kasus saya sendiri, menggunakan kueri rekursif.

Sayangnya saya belum menemukan cara untuk membiarkan BIND melakukan itu, tetapi jika iptables cukup baik untuk Anda, saya menggunakan

iptables -t raw -I PREROUTING -i eth0 -p udp --destination-port 53 \
    -m string --algo kmp --from 30 \
    --hex-string "|01000001000000000000|" -j DROP
pino42
sumber
Tidak, aturan itu juga memblokir permintaan tipe otoritatif (setidaknya di mesin saya). Tampaknya ia memblokir semua jenis permintaan DNS.
Udo G
Saya mengecek ulang dan saya menggunakan aturan itu. Inilah cut-and-paste dari server langsung. Perintah: iptables -t raw -S PREROUTING. Output:, -P PREROUTING ACCEPTdiikuti oleh -A PREROUTING -i eth0 -p udp -m udp --dport 53 -m string --hex-string "|01000001000000000000|" --algo kmp --from 30 --to 65535 -j DROP. Saya menguji bahwa itu berfungsi dengan benar host -ar exampledomain.com dns-server.example.net. Tentu saja itu tidak berfungsi dengan benar sampai saya menambahkan -ropsi.
pino42
Oke, -ropsi membuat perbedaan. Saya pribadi tidak suka hostpertanyaan sederhana tidak berfungsi lagi dan ini bisa sangat membingungkan. Meskipun demikian, ini mungkin jawaban yang valid (terbaik sejauh ini) dan saya akan memberi Anda hadiah, karena ini akan kedaluwarsa, bahkan jika saya akan terus menggunakan pendekatan saya sendiri dengan memfilter OUTPUT.
Udo G
Terima kasih! Jika saya menemukan solusi yang lebih baik, saya akan memastikan untuk mempostingnya. Saya setuju dengan Anda: ini adalah retasan. Yang bekerja, tapi masih hack.
pino42
2

Aku akan mencoba:

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

Respons yang merujuk klien ke server root dikendalikan oleh zona "redirect". Ini seharusnya memberitahu itu untuk tidak membalas mereka.

Itu mengisyaratkan di dalam dokumen Bind9: http://ftp.isc.org/isc/bind9/cur/9.9/doc/arm/Bv9ARM.ch06.html#id2592674

Anda dapat mengganti "none"dengan subnet lokal Anda.

Jika Anda sudah memiliki zone "."deklarasi, cukup tambahkan allow-query "none";.

freiheit
sumber
Saya memiliki zone "." { type hint; file "/etc/bind/db.root"; };deklarasi dengan db.root yang mencantumkan server root. Menghapus deklarasi itu berhenti lagi untuk domain asing tetapi server tetap merespons dengan "kegagalan server" dan dengan demikian masih dapat digunakan untuk DoS.
Udo G
@ UdoG: Sudahkah Anda mencoba menambahkan allow-query "none";ke zone "."konfigurasi?
freiheit
Sepertinya ini hanya menghemat bandwidth upstream yang seharusnya berlimpah. Dengan perbaikan Anda, penyerang telah menggunakan server Anda downstream bandwidth dan kekuatan pemrosesan
TheLQ
@TheLQ: Pertanyaannya merujuk pada ini menjadi serangan DDoS. Serangan DDoS berbasis DNS yang umum adalah mengirim permintaan DNS dengan IP yang ditempa dari target. Karena paket balasan DNS lebih besar dari kueri, ia menyediakan pengganda. Jika server Anda tidak merespons dengan paket yang jauh lebih besar, Anda telah menghilangkan alasan mereka menggunakan server Anda dalam serangan itu.
freiheit
@ UdoG: Paket kegagalan server hanya 31 hingga 32, sedangkan rujukan ke server root mungkin beberapa ratus byte. Jika balasan server Anda memiliki ukuran yang sama dengan kueri, atau hanya sedikit lebih besar, server Anda tidak berguna dalam serangan DNS DDoS, karena penyerang akan mengkonsumsi bandwidth sebanyak yang Anda kirim ke target mereka. Saya menguji sejumlah server nama otoritatif yang terkonfigurasi dengan baik (seperti milik google), dan mereka menjawab dengan "rekursi yang diminta tetapi tidak tersedia".
freiheit
1

Secara umum, saya akan menyarankan:

Nyalakan bind log dan catat ips yang mendapat jawaban ditolak. Instal program fail2ban, tambahkan tindakan blackhole: http://pastebin.com/k4BxrAeG (masukkan aturan dalam file di /etc/fail2ban/actions.d)

Buat file filter bind di /etc/fail2ban/filter.d dengan sesuatu seperti ini (perlu debugging!)

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

Edit fail2ban.conf, tambahkan bagian:

[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

Semoga ini bisa membantu!

Andrei Mikhaltsov
sumber
TODO: ikat contoh file log.
Andrei Mikhaltsov
1

Ide dasarnya, izinkan bind mengklasifikasikan respons DNS sebagai Ditolak lalu gunakan iptables untuk mengonversi Tolak menjadi diabaikan secara diam-diam.

Menolak adalah bagian yang mudah di bagian names.conf options:

allow-recursion { none;};

Atau tentu saja ACL favorit Anda untuk pengecualian lokal ...

Selanjutnya sihir iptables gila, sesuaikan atau hapus "-o eth0" sesuai kebutuhan. Perintah ini mengasumsikan header lapisan IPv4 20 byte standar sebelum UDP.

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

Kunci ini pada bidang bendera respons DNS dengan bit-bit berikut ditetapkan

  • Tanggapan DNS
  • Permintaan rekursif
  • Kode balasan ditolak

Pesan log pemberitahuan berjalan mengikat di debug "respons pengiriman kesalahan: host tidak dapat dijangkau" ketika aturan cocok untuk mendapatkan umpan balik untuk pengujian.

Harus mengakui ini semua adalah latihan yang agak tidak berguna. Jika tidak ada amplifikasi, penyerang bisa dengan mudah mencerminkan TCP SYN. DNS pada akhirnya dipecah hanya tidak ada solusi yang layak selain menggunakan TCP atau penyebaran cookie DNS Eastlake.

pemakan disk
sumber
0

Sudahkah Anda mencoba memblokir string isc.org atau memblokir string hex untuknya?

Ini bekerja untuk saya:

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

Hex
sumber
Bukankah lebih baik mengidentifikasi string hex untuk semua domain yang harus ditanggapi oleh server, lakukan hal di atas untuk mengizinkannya, dan lepaskan semua lalu lintas udp / 53 lainnya?
freiheit
Saat ini saya sudah memblokir tanggapan UDP yang merujuk ke server root: iptables -A OUTPUT -p udp -m string -hex-string "|726f6f742d73657276657273|" –algo bm –to 65535 -j DROPtapi saya benar-benar lebih suka solusi yang hanya didasarkan pada konfigurasi BIND, jika itu mungkin sama sekali.
Udo G
ini lemah. Anda dapat menghasilkan sengatan apa pun yang Anda inginkan sebagai domain. kita sedang menghadapi masalah itu sekarang dan itu bukan cara untuk memblokirnya melalui nama statis'bnrexex.www.sf97.net/A/IN' 'whzpkacpxpiuycm.www.tpa.net.cn/A/IN'
3h4x
0

Serangan ini disebut Amplified Denial of Service. Anda harus mengonfigurasi bind dengan benar, tetapi lalu lintas itu tidak seharusnya mengikat Anda terlebih dahulu. Blokir di perangkat jaringan pertama yang mampu melakukannya di jaringan Anda. Saya memiliki masalah yang sama dan mengatasinya dengan aturan mendengus tuli:

peringatan udp $ EXTERNAL_NET any -> $ HOME_NET 53 (msg: "PROTOCOL-DNS permintaan tipe berlebihan ANY - DoS potensial"; byte_test: 1,! &, 0xF8,2; konten: "| 00 00 FF 00 01 |"; detection_filter: track by_src, hitung 30, detik 30; metadata: service dns; referensi: url, foxpa.ws / 2010/07/21 / menggagalkan-isc-org-dns-ddos /; classtype: percobaan-dos; sid : 21817; rev: 4;)

3h4x
sumber
0

Pertama, saya tahu ini adalah pertanyaan lama tapi ...

Saya telah menjalankan server DNS saya sendiri yang otoritatif, non rekursif, selama beberapa dekade, tetapi belum pernah menjadi korban dalam serangan DDoS berbasis DNS - sampai sekarang, ketika saya beralih ke ISP baru. Ribuan kueri DNS palsu membanjiri log saya dan saya benar-benar kesal - tidak begitu banyak tentang dampak pada server saya, melainkan fakta itu mengacaukan log saya dan perasaan tidak nyaman disalahgunakan. Tampaknya penyerang mencoba menggunakan DNS saya dalam " serangan Server Nama Resmi ".

Jadi saya pikir, meskipun saya membatasi permintaan rekursif ke jaringan internal saya (menyangkal semua lainnya), saya lebih suka menghabiskan siklus CPU saya pada pencocokan string di iptables daripada mengirim kembali tanggapan negatif ke alamat IP palsu (kurang berantakan di log saya, kurang lalu lintas jaringan dan tingkat kepuasan saya yang lebih tinggi).

Saya mulai dengan melakukan seperti yang dilakukan semua orang , mencari tahu nama domain yang ditanyakan dan membuat kecocokan string pada domain tersebut dengan DROP target. Tetapi saya segera menyadari bahwa saya akan berakhir dengan sejumlah besar aturan, masing-masing dari mereka mengkonsumsi siklus CPU. Jadi, apa yang harus dilakukan? Karena saya tidak menjalankan server nama rekursif, saya pikir saya dapat melakukan pencocokan pada zona yang sebenarnya. Saya berwenang untuk dan membuang semua yang lain.

Kebijakan default saya di iptables adalah MENERIMA, jika kebijakan Anda adalah DROP, Anda mungkin perlu melakukan beberapa penyesuaian jika Anda ingin menggunakan solusi berikut.

Saya menyimpan konfigurasi zona saya di file terpisah (/etc/bind/named.conf.local), mari kita gunakan ini sebagai contoh:

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

Perhatikan komentar "// Pribadi" di dua zona pertama saya, saya menggunakan ini dalam skrip berikut untuk mengecualikan mereka dari daftar zona yang valid.

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

Jalankan skrip di atas dengan file konfigurasi zona sebagai argumen.

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

Simpan output ke skrip, kirimkan ke shell atau salin dan tempel di terminal Anda untuk membuat rantai baru dan mulai filter semua permintaan DNS yang tidak valid.

jalankan / sbin / iptables -L DNSvalidate -nvx untuk melihat penghitung paket (dan byte) pada setiap aturan dalam rantai baru (Anda mungkin ingin memindahkan zona dengan sebagian besar paket ke bagian atas daftar untuk membuatnya lebih efisien).

Dengan harapan seseorang mungkin menemukan ini berguna :)

kaya
sumber