我有一个可供公众访问的名称服务器,因为它是几个域的权威名称服务器。
当前,服务器充斥着ANY
对isc.org,trip.net等类似的伪造类型请求(这是一种已知的分布式DoS攻击)。
该服务器运行BIND,并已allow-recursion
设置为我的LAN,因此这些请求被拒绝。在这种情况下,服务器仅以authority
和additional
引用根服务器的部分作为响应。
是否可以配置BIND,使其完全忽略这些请求,而根本不发送响应?
我有一个可供公众访问的名称服务器,因为它是几个域的权威名称服务器。
当前,服务器充斥着ANY
对isc.org,trip.net等类似的伪造类型请求(这是一种已知的分布式DoS攻击)。
该服务器运行BIND,并已allow-recursion
设置为我的LAN,因此这些请求被拒绝。在这种情况下,服务器仅以authority
和additional
引用根服务器的部分作为响应。
是否可以配置BIND,使其完全忽略这些请求,而根本不发送响应?
Answers:
面对相同的问题,我选择忽略所有递归请求。当所有解析器都想将我的服务器用作权威服务器时,确实会发送非递归查询。就我自己而言,只有配置错误的客户端和攻击者才使用递归查询。
不幸的是,我还没有找到让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
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
选件,它才能正常工作。
-r
选项与众不同。我个人不喜欢简单的host
查询不再起作用,这可能会造成混乱。尽管如此,这可能是一个有效的(迄今为止最好的)答案,即使我将继续使用自己的方法来过滤输出,我也会给您赏金,因为它即将到期。
我会尝试:
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。
allow-query "none";
到zone "."
配置中?
通常,我建议:
打开绑定日志并记录被拒绝回答的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
希望这会有所帮助!
基本思想是让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响应的标志字段上设置以下位
当规则匹配以提供一些测试反馈时,在调试中发现已运行的绑定调试日志消息“错误发送响应:主机不可达”。
必须承认这是一个毫无意义的练习。如果没有放大,攻击者就可以轻松地反映TCP SYN。最终,除了使用TCP或部署Eastlake的DNS cookie外,根本没有可行的解决方案打破DNS。
您是否尝试阻止字符串isc.org或阻止它的十六进制字符串?
这为我工作:
iptables -A INPUT -p udp -m string --hex-string“ | 03697363036f726700 |” --algo bm -j DROP
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'
这种攻击称为放大拒绝服务。您应该正确配置绑定,但是流量一开始就不应该进入绑定。在可以在您的网络中执行此操作的第一个网络设备上将其阻止。我遇到了同样的问题,并用默认的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;)
首先,我知道这是一个老问题,但是...
我已经运行了自己的权威性,非递归型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 以查看新链中每个规则上的数据包(和字节)计数器(您可能希望将包含大多数数据包的区域移到列表的顶部,以使其效率更高)。
希望有人会觉得有用:)