前言
我在阿里云搭建的自用 dnsmasq 服务器,用来做免污染的 DNS,最近由于公开了IP,果然就遭到了攻击——其实是被用于 DNS 放大攻击。
由于 dnsmasq 本身就没有设计为对外提供 DNS 服务,所以它对于安全方面的配置文件不是很多(根本没有!),但它的解析策略又很方便配置(比如中国DNS解析白名单等),所以我在原本的基础上,再加了一个 Bind9 作为前端来做安全。
那么,今天我们就一起来看看到底如何给 Bind9 做安全配置。
Bind9 自身安全配置
Bind9 本身支持很多安全策略,我们把它做好,就已经能够让 DNS 十分健壮:
编辑
/etc/bind/named.conf.options
,我们添加自定义策略:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
options { directory "/var/cache/bind"; version "None of your business"; // If there is a firewall between you and nameservers you want // to talk to, you may need to fix the firewall to allow multiple // ports to talk. See http://www.kb.cert.org/vuls/id/800113 // If your ISP provided one or more IP addresses for stable // nameservers, you probably want to use them as forwarders. // Uncomment the following block, and insert the addresses replacing // the all-0's placeholder. forwarders { 127.0.0.1 port 5352; }; //======================================================================== // If BIND logs error messages about the root key being expired, // you will need to update your keys. See https://www.isc.org/bind-keys //======================================================================== // dnssec-validation auto; // recursion no; auth-nxdomain no; # conform to RFC1035 //listen-on-v6 { any; }; forward only; allow-query {any;}; allow-query-cache {any;}; dnssec-enable no; dnssec-validation no; rate-limit { ipv4-prefix-length 32; window 10; responses-per-second 25; errors-per-second 5; nxdomains-per-second 5; slip 2; }; }; |
详细解释:
1 |
version "None of your business"; |
隐藏掉 Bind9 的版本信息,避免黑客针对你的 Bind9 版本漏洞进行攻击。
1 2 3 |
forwarders { 127.0.0.1 port 5352; }; |
这句是开启 Bind9 解析转发,就像 dnsmasq 一样,让 Bind9 能够向上获取解析而不是自身去从根解析,就可以避免污染了(我这里解析到了本地的 dnsmasq 上)
1 2 3 |
forward only; allow-query {any;}; allow-query-cache {any;}; |
只允许转发,禁用根解析,同时开启外部解析和缓存。
1 2 |
dnssec-enable no; dnssec-validation no; |
关闭安全配置,因为我要向上转发到dnsmasq,而前者的应答是非权威应答,所以要让 Bind9 接受非权威应答,就要关闭它。你不这样用的话就不必关。
在查询一个域名时,可能会看到有“非权威应答”的提示,该提示表示你所查询的域名不使用你当前所用的DNS查询服务器上。
1 2 3 4 5 6 7 8 |
rate-limit { ipv4-prefix-length 32; window 10; responses-per-second 25; errors-per-second 5; nxdomains-per-second 5; slip 2; }; |
为每个 IP 进行限速,如果请求超过每秒 25 个,就不再响应直接丢包。
效果
这样一来,你应该就能在
/var/log/syslog
里看到大量的超限 drop 记录了,不过,即使如此,vps的流量依旧如流水一般远去,所以,我们还需要使用第三方的工具来处理这些 IP。
记得重启服务
service bind9 restart
使用 Fail2ban 自动屏蔽黑客 IP
没错, 如果你读过我的 购买了VPS之后你应该做足的安全措施 这篇文章,那你的 vps 上应该已经安装了这个工具,它默认就已经能够很好的运行了,但要给 Bind9 使用,我们还要继续定制一番。
定制 Bind9 以兼容 Fail2ban
Bind9 默认并不会单独生成日志的,我们需要把出错的日志输出以便 Fail2ban 能够记录,所以编辑
/etc/bind/named.conf
,在文件末尾另起一行插入如下语句:
1 2 3 4 5 6 7 8 9 10 |
logging { channel query_log { file "security.log" versions 3 size 30m; severity info; print-time yes; }; category default { query_log; }; }; |
这是重定向 Bind9 的默认日志到
/var/cache/bind/security.log
大小保持30M
这时候如果你用
tail -f /var/cache/bind/security.log
来查看,就会看到一大堆类似这样的记录了:
1 2 3 4 5 6 7 8 9 10 11 12 |
23-Apr-2016 18:44:08.560 client 94.254.209.48#80 (nhl.msk.su): rate limit drop response to 94.254.209.48/32 for nhl.msk.su IN ANY (0000640d) 23-Apr-2016 18:44:08.589 client 94.254.209.48#80 (nhl.msk.su): rate limit slip response to 94.254.209.48/32 for nhl.msk.su IN ANY (0000640d) 23-Apr-2016 18:44:08.607 client 94.254.209.48#80 (nhl.msk.su): rate limit drop response to 94.254.209.48/32 for nhl.msk.su IN ANY (0000640d) 23-Apr-2016 18:44:08.695 client 94.254.209.48#80 (nhl.msk.su): rate limit slip response to 94.254.209.48/32 for nhl.msk.su IN ANY (0000640d) 23-Apr-2016 18:44:08.696 client 94.254.209.48#80 (nhl.msk.su): rate limit drop response to 94.254.209.48/32 for nhl.msk.su IN ANY (0000640d) 23-Apr-2016 18:44:08.752 client 94.254.209.48#80 (nhl.msk.su): rate limit slip response to 94.254.209.48/32 for nhl.msk.su IN ANY (0000640d) 23-Apr-2016 18:44:08.844 client 94.254.209.48#80 (nhl.msk.su): rate limit drop response to 94.254.209.48/32 for nhl.msk.su IN ANY (0000640d) 23-Apr-2016 18:44:08.950 client 94.254.209.48#80 (nhl.msk.su): rate limit slip response to 94.254.209.48/32 for nhl.msk.su IN ANY (0000640d) 23-Apr-2016 18:44:09.009 client 94.254.209.48#80 (nhl.msk.su): rate limit drop response to 94.254.209.48/32 for nhl.msk.su IN ANY (0000640d) 23-Apr-2016 18:44:09.015 client 94.254.209.48#80 (nhl.msk.su): rate limit slip response to 94.254.209.48/32 for nhl.msk.su IN ANY (0000640d) 23-Apr-2016 18:44:09.112 client 94.254.209.48#80 (nhl.msk.su): rate limit drop response to 94.254.209.48/32 for nhl.msk.su IN ANY (0000640d) 23-Apr-2016 18:44:09.117 client 94.254.209.48#80 (nhl.msk.su): rate limit slip response to 94.254.209.48/32 for nhl.msk.su IN ANY (0000640d) |
显然,现在有人在利用我的 DNS 进行反射攻击,接下来我们配置 Fail2ban 来干掉这些 IP。
让 Fail2ban 对 Bind9 生效
其实 Fail2ban 原生支持 Bind9 的,甚至其列表里就已经内置——不过那个策略与我们的期望不甚相符,还得自己改改。
编辑过滤配置
编辑
/etc/fail2ban/jail.conf
文件,在里边找到关于 Bind9 的配置部分,默认如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
# These jails block attacks against named (bind9). By default, logging is off # with bind9 installation. You will need something like this: # # logging { # channel security_file { # file "/var/log/named/security.log" versions 3 size 30m; # severity dynamic; # print-time yes; # }; # category security { # security_file; # }; # }; # # in your named.conf to provide proper logging # !!! WARNING !!! # Since UDP is connection-less protocol, spoofing of IP and imitation # of illegal actions is way too simple. Thus enabling of this filter # might provide an easy way for implementing a DoS against a chosen # victim. See # http://nion.modprobe.de/blog/archives/690-fail2ban-+-dns-fail.html # Please DO NOT USE this jail unless you know what you are doing. #[named-refused-udp] …… [named-refused-tcp] …… |
我们给它改改,udp 和 tcp 都启用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
[named-refused-udp] enabled = true port = domain,953 protocol = udp filter = named-refused logpath = /var/cache/bind/security.log findtime = 1 maxretry = 5 action = iptables-multiport[name=Named, port=53, protocol=udp] [named-refused-tcp] enabled = true port = domain,953 protocol = tcp filter = named-refused logpath = /var/cache/bind/security.log findtime = 1 maxretry = 5 action = iptables-multiport[name=Named, port=53, protocol=tcp] |
这里的意思是一旦在1秒内发现5次记录,就会把对应的 IP 给加入黑名单,时间则是默认的3600秒。不过不要担心,这个记录是 drop 记录,不是正常的 query 记录。
修改过滤规则
接下来我们改一下默认规则,默认的规则是探测被攻击——而我们是要探测被用于攻击……编辑
/etc/fail2ban/filter.d/named-refused.conf
文件,找到如下几行:
1 2 3 |
failregex = ^%(__line_prefix)s(\.\d+)?( error:)?\s*client <HOST>#\S+( \([\S.]+\))?: (view (internal|external): )?query(?: \(cache\))? '.*' denied\s*$ ^%(__line_prefix)s(\.\d+)?( error:)?\s*client <HOST>#\S+( \([\S.]+\))?: zone transfer '\S+/AXFR/\w+' denied\s*$ ^%(__line_prefix)s(\.\d+)?( error:)?\s*client <HOST>#\S+( \([\S.]+\))?: bad zone transfer request: '\S+/IN': non-authoritative zone \(NOTAUTH\)\s*$ |
改为:
1 |
failregex = <HOST>#\S+( \([\S.]+\))?\: rate limit drop |
重启服务
使用命令
service fail2ban restart
来重启服务,这时候使用命令可查看其状态:
1 2 3 4 5 6 7 8 9 10 |
:~# fail2ban-client status named-refused-udp Status for the jail: named-refused-udp |- filter | |- File list: /var/cache/bind/security.log | |- Currently failed: 0 | - Total failed: 9 - action |- Currently banned: 1 | - IP list: 94.254.209.48 - Total banned: 1 |
你看,已经抓到一个了。
总结
总之,一番折腾下来,我们得到了如下收获:Bind9 能够对单个 IP 的每秒请求进行限制(随后你可以根据需求进行修改),一旦某IP再一秒内对服务器请求次数超过限制,则会被记录并丢弃请求,如果超过的次数超过五次,那么就会被拉入黑名单被防火墙拒绝(对方显示目标地址不可达)。
关于UDP的一点讨论
如你所见,在 Fail2ban 配置文件当中也写明了对 UDP 的策略很有危险,因为黑客可以很容易伪造不同的地址,这样可能会被用来利用你的规则恶意屏蔽某些 IP ,如果你的服务器出现这个情况,你就需要关掉针对 UDP 的策略了。
扩展阅读
Blocking a DNS DDOS using the fail2ban package
本文由 落格博客 原创撰写:落格博客 » 使用 fail2ban 防止 Bind9 被用于 DNS 放大攻击
转载请保留出处和原文链接:https://www.logcg.com/archives/1681.html
I need help ! I try to use fail2ban with bind9 but when i check fail2ban’s status i get errors ! some one can help me with how to do! Thanks
Hi, thank you for your publications. May i suggest to publish dnsmasq file configuration since this dns resolver is used into the logic developped by your article ?
Hope it helps.
Regards?
—–
forwarders {
127.0.0.1 port 5352;
};
The message is forwarded to resolve open Bind9,Like dnsmasq as,Let Bind9 able to get up and not resolve on their own to resolve the root,You can avoid polluted (I here to resolve the local dnsmasq)
Thank you for writing a helpful blog. I followed your configuration and configured my server.
But failregex = #\S+( \([\S.]+\))?\: rate limit drop does not matches for me. My log file generates logs. Does The # after commenting the line “^\s*\S+\s+named(?:\[\d+\])?: [^:]+: rate limit drop” ? Color also change after #.
My Fail2ban version is 1.0.2.
Output of
fail2ban-regex /var/cache/bind/security.log /etc/fail2ban/filter.d/named-refused.conf
Running tests
=============
Use failregex filter file : named-refused, basedir: /etc/fail2ban
Use log file : /var/cache/bind/security.log
Use encoding : UTF-8
Results
=======
Prefregex: 1 total
| ^\s*(?:\S+ (?:(?:\[\d+\])?:\s+\(?named(?:-\w+)?(?:\(\S+\))?\)?:?|\(?named(?:-\w+)?(?:\(\S+\))?\)?:?(?:\[\d+\])?:)\s+)?(?:(?!error|info)[\w-]+: )?(?:(?:error|info):\s*)?client(?: @\S*)? (?:\[?(?:(?:::f{4,6}:)?(?P(?:\d{1,3}\.){3}\d{1,3})|(?P(?:[0-9a-fA-F]{1,4}::?|::){1,7}(?:[0-9a-fA-F]{1,4}|(?<=:):)))\]?|(?P[\w\-.^_]*\w))#\S+(?: \([\S.]+\))?: (?P.+)\s(?:denied|\(NOTAUTH\))\s*$
-
Failregex: 0 total
Ignoreregex: 0 total
Date template hits:
|- [# of hits] date format
| [253912] {^LN-BEG}Day(?P[-/])MON(?P=_sep)ExYear[ :]?24hour:Minute:Second(?:\.Microseconds)?(?: Zone offset)?
–
Lines: 253912 lines, 0 ignored, 0 matched, 253912 missed
[processed in 9.25 sec]
Missed line(s): too many to print. Use –print-all-missed to print all 253912 lines
What I am missing ?
I would say… try restart the fail2ban first. It seems like ur changes not take effect, Failregex: 0 total, it should be 1, otherwise the regex was not loaded.
If a service restart not work, then I d suggest go over the path/filenames see if there any typo or something, or even poking around the prefregex to blah then see if the change take effect.
Just to make sure other don’t make this mistake.
Under the tcp jail:
[named-refused-tcp]
…
Change this to:
action = iptables-multiport[name=Named, port=53, protocol=udp]
This:
action = iptables-multiport[name=Named, port=53, protocol=tcp] << THIS
Tanks man, updated.
站长好,我的dns服务器收到的攻击日志如下:
202.9.120.7#13620 (aaa.com): view g-1: rate limit drop SERVFAIL error response to 202.9.120.7/32
可能是由于启用了view?在使用您教程里的正则表达式failregex = #\S+( \([\S.]+\))?\: rate limit drop时无法匹配,请问我这种日志,如何修改正则表达式,使其能匹配日志?盼求回复,谢谢!
如果是静态的,那就 failregex =#\S+( \([\S.]+\))?\: view g-1: rate limit drop #\S+( \([\S.]+\))?\: \w{4} \w-\d: rate limit drop
如果那个也是动态的,那就:failregex =
我使用您提到的两个正则式,都不行。是不是什么地方漏写了什么?
日志中一条为
120.9.20.2#52774 (chef.vpn.qianxin.com): view cnc-user: rate limit drop
我文中的例子是 “#80 (nhl.msk.su): rate limit drop“, 你的日志是 “#52774 (chef.vpn.qianxin.com): view cnc-user: rate limit drop“,比我的多了“ view cnc-user:“ 这么个字段,如果它是固定的,那就把正则改成“#\S+( \([\S.]+\))?\: view cnc-user\: rate limit drop“ 试试,如果是变化的,干脆变成 “#\S+( \([\S.]+\))?\:.+\: rate limit drop“ 得了。
简单来说就是你的日志格式和我的不一致~
This is very interesting, You’re a very skilled blogger. I have joined your feed and look forward sex seeking more of your fantastic post. Also, I have shared your site in my social networks!
阿里云太贵啦,学生版一个月要十块钱呢,你弄个腾讯云,一个月一块钱哦~~也是学生版呢!
听说了,他们推出的时候我早就已经买了,另外听说腾讯云挺坑的啊。
就看着便宜,反正我也是用来搭ss,因为学校访问外网有时太坑,顺便弄个UDP53的OpenVPN,你懂的!