绑定:黑洞无效的递归查询?


13

我有一个可供公众访问的名称服务器,因为它是几个域的权威名称服务器

当前,服务器充斥着ANY对isc.org,trip.net等类似的伪造类型请求(这是一种已知的分布式DoS攻击)。

该服务器运行BIND,并已allow-recursion设置为我的LAN,因此这些请求被拒绝。在这种情况下,服务器仅以authorityadditional引用根服务器的部分作为响应。

是否可以配置BIND,使其完全忽略这些请求,而根本不发送响应?

Answers:


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请求。
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查询不再起作用,这可能会造成混乱。尽管如此,这可能是一个有效的(迄今为止最好的)答案,即使我将继续使用自己的方法来过滤输出,我也会给您赏金,因为它即将到期。
Udo G

谢谢!如果遇到更好的解决方案,请确保将其发布。我同意你的看法:这是骇客。工作正常,但仍然是hack。
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 "."配置中?
2012年

似乎这只是节省了上游带宽,尽管应该足够。通过修复,攻击者已经用尽了服务器的下游带宽和处理能力
TheLQ 2012年

@TheLQ:问题是这是DDoS攻击。基于DNS的常见DDoS攻击是发送带有目标IP伪造的DNS查询。由于DNS答复数据包大于查询,因此它提供了一个乘数。如果您的服务器没有对更大的数据包做出响应,则可以消除它们在攻击中使用服务器的原因。
2012年

@UdoG:服务器故障数据包只有31到32,而对根服务器的引用可能是几百个字节。如果服务器的回复大小与查询的大小相同,或者只是稍大一点,则服务器在DNS DDoS攻击中毫无用处,因为攻击者将消耗尽可能多的带宽,将其发送给目标。我针对许多可能配置良好的权威名称服务器(例如Google的服务器)进行了测试,并回答“请求递归但不可用”。
2012年

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:绑定日志文件示例。
Andrei Mikhaltsov

1

基本思想是让bind将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。最终,除了使用TCP或部署Eastlake的DNS cookie外,根本没有可行的解决方案打破DNS。


0

您是否尝试阻止字符串isc.org或阻止它的十六进制字符串?

这为我工作:

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


确定服务器应响应的所有域的十六进制字符串是否更好,上面是否允许这些十六进制字符串,并丢弃所有其他udp / 53流量?
2012年

我目前已经在阻止引用根服务器的UDP响应:iptables -A OUTPUT -p udp -m string -hex-string "|726f6f742d73657276657273|" –algo bm –to 65535 -j DROP但是,如果可能的话,我真的更喜欢仅基于BIND配置的解决方案。
Udo G

这很弱。您可以生成任何希望作为域的字符串。我们现在正面临该问题,并且不是通过静态名称阻止它的方法'bnrexex.www.sf97.net/A/IN' 'whzpkacpxpiuycm.www.tpa.net.cn/A/IN'
3h4x 2014年

0

这种攻击称为放大拒绝服务。您应该正确配置绑定,但是流量一开始就不应该进入绑定。在可以在您的网络中执行此操作的第一个网络设备上将其阻止。我遇到了同样的问题,并用默认的snort规则处理了它:

警报udp $ EXTERNAL_NET任意-> $ HOME_NET 53(msg:“ PROTOCOL-DNS ANY类型的过多查询-潜在的DoS”; byte_test:1,!&,0xF8,2;内容:“ | 00 00 FF 00 01 |”; detection_filter:跟踪by_src,计数30,秒30;元数据:服务dns;参考:url,foxpa.ws / 2010/07/21 / thwarting-the-isc-org-dns-ddos /; classtype:attempted-dos; sid :21817; rev:4;)


0

首先,我知道这是一个老问题,但是...

我已经运行了自己的权威性,非递归型DNS服务器已有数十年了,但从未成为任何基于DNS的DDoS攻击的受害者–直到现在,我切换到新的ISP。成千上万的欺骗性DNS查询淹没了我的日志,我感到非常恼火–与其说对服务器的影响,不如说是它使我的日志混乱不堪和被滥用的感觉。攻击者似乎在“ 权威名称服务器攻击 ”中尝试使用我的DNS 。

因此,我认为,即使我将递归查询限制在我的内部网络上(拒绝所有其他请求),我宁愿将我的CPU周期花费在iptables中的字符串匹配上,而不是将否定响应发送回欺骗的IP地址(日志中的混乱程度更少,更少网络流量和更高的满意度)。

我从其他人似乎都开始做起,找出要查询的域名,并使用目标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;
};

请注意我前两个区域的“ // 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 以查看新链中每个规则上的数据包(和字节)计数器(您可能希望将包含大多数数据包的区域移到列表的顶部,以使其效率更高)。

希望有人会觉得有用:)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.