bind: черная дыра для неверных рекурсивных запросов?

13

У меня есть общедоступный сервер имен, поскольку он является официальным сервером имен для пары доменов .

В настоящее время сервер ANYзаполнен поддельными запросами типа isc.org, pale.net и аналогичными (это известная распределенная атака DoS ).

Сервер запускает BIND и allow-recursionнастроил мою локальную сеть, чтобы эти запросы были отклонены. В таких случаях сервер отвечает только с authorityи additionalсекции со ссылкой на корневые серверы.

Могу ли я настроить 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
pino42
источник
Нет, это правило блокирует также запросы авторитетного типа (по крайней мере, на моей машине). По-видимому, он блокирует все виды DNS-запросов.
Udo 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.
Udo 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";к нему.

Freiheit
источник
У меня есть zone "." { type hint; file "/etc/bind/db.root"; };объявление с db.root, перечисляющее корневые серверы. Удаление этого объявления останавливает ответы для сторонних доменов, но сервер, тем не менее, отвечает «сбой сервера» и, таким образом, все еще может использоваться для DoS.
Удо Г
@UdoG: вы пытались добавить allow-query "none";в конфиг zone "."?
Freiheit
Кажется, что это только экономит пропускную способность восходящего канала, хотя этого должно быть много. С вашим исправлением злоумышленник уже израсходовал пропускную способность и вычислительную мощность ваших серверов
TheLQ
@TheLQ: Вопрос касается того, что это DDoS-атака. Распространенная атака DDoS на основе DNS заключается в отправке DNS-запросов с поддельным IP-адресом цели. Поскольку ответный пакет DNS больше, чем запрос, он обеспечивает множитель. Если ваш сервер не отвечает значительно большим пакетом, вы устранили причину, по которой он использует ваш сервер для атаки.
Freiheit
@UdoG: Пакет сбоя сервера составляет от 31 до 32, тогда как обращение к корневым серверам, вероятно, составляло несколько сотен байтов. Если ответ вашего сервера имеет такой же размер, как и запрос, или только чуть-чуть больше, ваш сервер бесполезен в DDoS-атаке DNS, так как злоумышленники будут использовать столько же пропускной способности, сколько они заставят вас отправить их цели. Я проверил на нескольких, вероятно, хорошо настроенных авторитетных серверах имен (таких как Google), и они ответили: «Запрошена рекурсия, но она недоступна».
Freiheit
1

Как правило, я бы предложил:

Включите журналы привязки и запишите ips, который получает отклоненный ответ. Установите программу fail2ban, добавьте действие blackhole: 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

Основная идея: пусть bind классифицирует ответ DNS как Отказанный, а затем использует iptables для преобразования Отказанного в игнорируемое.

Отказаться - это простая часть в разделе параметров named.conf:

allow-recursion { none;};

Или, конечно, ваши любимые ACL для локальных исключений ...

Далее сумасшедшая магия iptables, настройте или удалите "-o eth0" по мере необходимости. Эта команда предполагает стандартный 20-байтовый заголовок уровня IPv4 до UDP.

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 или развертывания файлов cookie Eastlake DNS.

Пожиратель дисков
источник
0

Вы пытались заблокировать строку isc.org или заблокировать шестнадцатеричную строку для нее?

Это сработало для меня:

iptables -A INPUT -p udp -m строка --hex-string "| 03697363036f726700 |" --algo bm -j DROP

наговор
источник
Разве не лучше было бы определить шестнадцатеричные строки для всех доменов, на которые должен отвечать сервер, сделать это выше, чтобы разрешить их, и отбросить все другие трафики udp / 53?
Freiheit
В настоящее время я уже блокирую ответы UDP, относящиеся к корневым серверам, iptables -A OUTPUT -p udp -m string -hex-string "|726f6f742d73657276657273|" –algo bm –to 65535 -j DROPно я бы действительно предпочел решение, основанное только на конфигурации BIND, если это вообще возможно.
Удо Г
это слабо Вы можете генерировать любое жало как домен. мы сталкиваемся с этой проблемой прямо сейчас, и это не способ блокировать ее статическим именем'bnrexex.www.sf97.net/A/IN' 'whzpkacpxpiuycm.www.tpa.net.cn/A/IN'
3h4x
0

Эта атака называется усиленным отказом в обслуживании. Вы должны правильно настроить привязку, но этот трафик не должен в первую очередь попасть на вашу привязку. Заблокируйте его на первом сетевом устройстве, которое способно сделать это в вашей сети. У меня была такая же проблема, и я справился с ней по правилу глухого фырканья:

предупреждение udp $ EXTERNAL_NET any -> $ HOME_NET 53 (сообщение: «Чрезмерные запросы PROTOCOL-DNS типа ANY - потенциальная DoS»; byte_test: 1,! &, 0xF8,2; содержимое: «| 00 00 FF 00 01 |»; обнаружение_фильтр: отслеживание by_src, счет 30, секунды 30; метаданные: служба DNS; ссылка: URL-адрес, foxpa.ws / 2010/07/21 / thwarting-the-isc-org-dns-ddos /; класс классификации: предпринятые-действия; sid : 21817; рев: 4;)

3h4x
источник
0

Во-первых, я знаю, что это старый вопрос, но ...

Я десятилетиями управлял своим собственным авторитетным, не рекурсивным DNS-сервером, но никогда не был жертвой каких-либо DNS-атак DDoS - до тех пор, пока я не переключился на нового интернет-провайдера. Тысячи поддельных DNS-запросов наводнили мои журналы, и я был действительно раздражен - не столько о влиянии на мой сервер, сколько о том, что он загромождает мои журналы и неприятном ощущении злоупотребления. Похоже, что злоумышленник пытается использовать мой DNS в « Атаке авторитетного сервера имен ».

Поэтому я решил, что, хотя я ограничиваю рекурсивные запросы своей внутренней сетью (отказывая во всех остальных), я скорее трачу свои циклы ЦП на сопоставление строк в iptables, чем на отправку отрицательных ответов на поддельные IP-адреса (меньше беспорядка в моих журналах, меньше сетевой трафик и мой более высокий уровень удовлетворенности).

Я начал с того, что поступил так же , как и все остальные , выяснил, какие доменные имена запрашиваются, и создал совпадение строк в этом домене с целевым DROP. Но вскоре я понял, что получу огромное количество правил, каждое из которых потребляет циклы процессора. Так что делать? Поскольку я не запускаю рекурсивный сервер имен, я подумал, что мог бы сопоставить действительные зоны, для которых я уполномочен, и отбросить все остальное.

Моя политика по умолчанию в iptables - ПРИНЯТЬ, если ваша политика 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;
};

Обратите внимание на комментарий «// 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 видеть пакетов (и байтов) счетчики по каждому правилу в новой цепи (вы можете захотеть , чтобы переместить зону с большинством пакетов в верхней части списка , чтобы сделать его более эффективным).

В надежде, что кто-то найдет это полезным :)

богатый
источник