# 使用`Fail2Ban`防止sip攻击`FreeSWITCH` `FreeSWITCH`在公网运行容易遭受sip攻击,解决的办法有很多种,而`Fail2Ban`安装配置以及调试比较简单,不失为一种好的选择。 `Fail2Ban`版本很多,配置方式略有差别。 本次测试是基于`Fail2Ban 0.9.6`版本,其他相关信息如下: - Debian9 - FreeSWITCH 1.10.3,`base_dir`是`/usr/local/freeswitch` ## 安装`Fail2Ban` ```shell cd /usr/src; git clone https://github.com/fail2ban/fail2ban.git -b 0.9.6 cd /usr/src/fail2ban; python3 setup.py install #配置成服务 cp files/debian-initd /etc/init.d/fail2ban
#centos
cp files/redhat-initd /etc/init.d/fail2ban
https://github.com/fail2ban/fail2ban/blob/0.11/files/redhat-initd update-rc.d fail2ban defaults service fail2ban start ``` ## 配置`iptables` ```shell iptables -A INPUT -i lo -j ACCEPT iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT iptables -A INPUT -p tcp --dport 22 -j ACCEPT iptables -A INPUT -p tcp --dport 80 -j ACCEPT iptables -A INPUT -p tcp --dport 443 -j ACCEPT iptables -A INPUT -p tcp --dport 5066 -j ACCEPT iptables -A INPUT -p tcp --dport 7443 -j ACCEPT iptables -A INPUT -p tcp --dport 5060:5061 -j ACCEPT iptables -A INPUT -p udp --dport 5060 -j ACCEPT iptables -A INPUT -p tcp --dport 5080 -j ACCEPT iptables -A INPUT -p udp --dport 5080 -j ACCEPT iptables -A INPUT -p udp --dport 16384:32768 -j ACCEPT iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT iptables -P INPUT DROP iptables -P FORWARD DROP iptables -P OUTPUT ACCEPT ``` ## 配置 `FreeSWITCH` 1. sip_profiles/internal.xml ``` <param name="log-auth-failures" value="true"/> ``` 2. autoload_configs/switch.conf.xml 要修改一个配置项目 ``` <param name="threaded-system-exec" value="true"/> ``` ## 配置 fail2ban ### 配置 freeswitch jail 找到 `/etc/fail2ban/jail.conf` 的 freeswitch 段,修改成下面这样: ``` [freeswitch] enabled = true port = 5060,5061,5080 action = iptables-allports[name=freeswitch, protocol=all] logpath = /usr/local/freeswitch/log/freeswitch.log filter = freeswitch maxretry = 5 bantime = -1 findtime = 3600 ignoreip = 127.0.0.1/8 192.168.0.0/16 10.0.0.0/8 172.16.0.0/16 ``` 其中: * port = 5060,5061,5080 # sip profile 的端口 * action = iptables-allports[name=freeswitch, protocol=all] # 这里不用改动 * logpath = /usr/local/freeswitch/log/freeswitch.log # freeswitch.log的全路径 * filter = freeswitch #这里不用改动 * maxretry = 5 # 尝试次数 * bantime = -1 # -1 永久 ban(禁止) * findtime = 3600 # 发现的时间,这几个参数合起来的意思就是,如果 1 小时内检查到 哪个 IP 地址,做了 5 次尝试,那么永久禁止他 * ignoreip = 127.0.0.1/8 192.168.0.0/16 10.0.0.0/8 172.16.0.0/16 # ip 白名单 ### 配置 freeswitch filter 修改`/etc/fail2ban/filter.d/freeswitch.conf`,改成下面这样: ``` # Fail2Ban configuration file # # Enable "log-auth-failures" on each Sofia profile to monitor # <param name="log-auth-failures" value="true"/> # -- this requires a high enough loglevel on your logs to save these messages. # # In the fail2ban jail.local file for this filter set ignoreip to the internal # IP addresses on your LAN. # [Definition] #failregex = ^\.\d+ \[WARNING\] sofia_reg\.c:\d+ SIP auth (failure|challenge) \((REGISTER|INVITE)\) on sofia profile \'[^']+\' for \[.*\] from ip <HOST>$ # ^\.\d+ \[WARNING\] sofia_reg\.c:\d+ Can't find user \[\d+@\d+\.\d+\.\d+\.\d+\] from <HOST>$ failregex = ^\.\d+ \[WARNING\] sofia_reg\.c:\d+ SIP auth failure \((REGISTER|INVITE)\) on sofia profile \'[^']+\' for \[.*\] from ip <HOST>$ ^\.\d+ \[WARNING\] sofia_reg\.c:\d+ Can't find user \[\d+@\d+\.\d+\.\d+\.\d+\] from <HOST>$ ignoreregex = # Author: Rupa SChomaker, soapee01, Daniel Black # https://freeswitch.org/confluence/display/FREESWITCH/Fail2Ban # Thanks to Jim on mailing list of samples and guidance # # No need to match the following. Its a duplicate of the SIP auth regex. # ^\.\d+ \[DEBUG\] sofia\.c:\d+ IP <HOST> Rejected by acl "\S+"\. Falling back to Digest auth\.$ ``` 现在运行`systemctl restart fail2ban`重启服务 再运行 `fail2ban-client status`,输出如下: ``` Status |- Number of jail: 1 `- Jail list: freeswitch ``` 运行`fail2ban-client status freeswitch`,输出如下: ``` Status for the jail: freeswitch |- Filter | |- Currently failed: 0 | |- Total failed: 0 | `- File list: /usr/local/freeswitch/log/freeswitch.log `- Actions |- Currently banned: 0 |- Total banned: 0 `- Banned IP list: ``` 现在试着ban一个ip,执行这个命令: ``` fail2ban-client set freeswitch banip 113.113.113.113 ``` 然后用`fail2ban-client status freeswitch`查看 ``` Status for the jail: freeswitch |- Filter | |- Currently failed: 0 | |- Total failed: 0 | `- File list: /usr/local/freeswitch/log/freeswitch.log `- Actions |- Currently banned: 1 |- Total banned: 3 `- Banned IP list: 113.113.113.113 ``` 可以看到, `113.113.113.113` 这个地址已经被ban 执行这个命令`iptables -nvL --line-numbers` 输出如下: ``` Chain INPUT (policy DROP 9 packets, 2952 bytes) num pkts bytes target prot opt in out source destination 1 1057 132K f2b-freeswitch all -- * * 0.0.0.0/0 0.0.0.0/0 2 0 0 ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0 3 13 808 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED 4 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22 5 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 6 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:443 7 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:5066 8 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:7443 9 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpts:5060:5061 10 0 0 ACCEPT udp -- * * 0.0.0.0/0 0.0.0.0/0 udp dpt:5060 11 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:5080 12 0 0 ACCEPT udp -- * * 0.0.0.0/0 0.0.0.0/0 udp dpt:5080 13 0 0 ACCEPT udp -- * * 0.0.0.0/0 0.0.0.0/0 udp dpts:16384:32768 14 0 0 ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0 icmptype 8 Chain FORWARD (policy DROP 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination Chain OUTPUT (policy ACCEPT 6 packets, 496 bytes) num pkts bytes target prot opt in out source destination Chain f2b-freeswitch (1 references) num pkts bytes target prot opt in out source destination 1 0 0 REJECT all -- * * 113.113.113.113 0.0.0.0/0 reject-with icmp-port-unreachable 2 1057 132K RETURN all -- * * 0.0.0.0/0 0.0.0.0/0 ``` 用这个命令解除,`fail2ban-client set freeswitch unbanip 113.113.113.113` ## 把 FreeSWITCH 运行起来,运行`tail -f /var/log/fail2ban.log`进行观察,再结合`/usr/local/freeswitch/log/freeswitch.log`的日志内容,进行调试,不断优化。 ## fail2ban.lua 一般情况下`Fail2Ban`工作的很好,但还是有特殊的呼叫流程`Fail2Ban`抓不到。为此,笔者写了个`fail2ban.lua`,弥补`Fail2Ban`的不足 1. 修改`lua.conf.xml`,增加下面俩个配置项目: ``` <hook event="CUSTOM" subclass="sofia::wrong_call_state" script="fail2ban.lua"/> <hook event="CUSTOM" subclass="sofia::register_failure" script="fail2ban.lua"/> ``` 下面是`fail2ban.lua`的内容(代码比较简单,不再解释了): ``` function OnEvent(e) local subclass = e:getHeader("Event-Subclass") or "" if string.find(subclass, "sofia::") ~= 1 then return end local ip = e:getHeader("network_ip") or e:getHeader("network-ip") if not ip then return end local ua = e:getHeader("user-agent") or "" local to_user = e:getHeader("to-user") or "" local from_user = e:getHeader("from-user") or "" local auth_result = e:getHeader("auth-result") or "" local registration_type = e:getHeader("registration-type") or "" local s = string.format("*** %s, ip = %s, ua = %s, to = %s, from = %s, result = %s, type = %s\n", subclass, ip, ua, to_user, from_user, auth_result, registration_type) freeswitch.consoleLog("NOTICE", s) if subclass == "sofia::wrong_call_state" or subclass == "sofia::register_failure" then local cmd = "fail2ban-client set freeswitch banip " .. ip freeswitch.consoleLog("ERR", cmd .. "\n") os.execute(cmd) end end freeswitch.consoleLog("INFO", "fail2ban.lua, ===\n" .. event:serialize() .. "===\n") OnEvent(event) ``` ## 参考资料: <https://docs.fusionpbx.com/en/latest/firewall/fail2ban.html> <https://docs.fusionpbx.com/en/latest/firewall/iptables.html> <https://freeswitch.org/confluence/display/FREESWITCH/Fail2Ban>
https://blog.csdn.net/weixin_43103905/article/details/95060220
注意:
如果遇到报错“no directory /var/run/fail2ban to contain the socket file /var/run/fail2ban/fail2ban.sock”, 请手动创建相关文件夹:
mkdir /var/run/fail2ban
#开机启动
$ systemctl enable fail2ban
$ systemctl start fail2ban
redhat-initd