全部博文(297)
分类: LINUX
2007-07-23 12:25:25
一次DOS事件的解决办法
日期:2006-09-18 作者:小龙女 来自:et8.net
0.分析过程
首先,分析了DOS的类型、特征、攻击方法。
使用netstat -na|grep SYN_RECV|wc,发现当前存在大量SYN_RECV状态连接,源地址都是伪造的,netstat -na|grep SYN_RECV|wc显示数量为1024个,这个是当然,Linux默认的Syn_Backlog对列就是1024,超过的SYN都丢弃了。
针对的攻击端口是80:WWW服务,当然,Web服务器也已经无法访问了。
在打开SYN_Cookie防护之后,攻击得到了一些缓解,但随后攻击流量又增大了,情况也好不到哪儿去,而Linux的Iptables又不能做syn_proxy的,那么只好从其他方面下手,用tcpdump -w抓下了当时的数据流量,计数分析流量大约在1.8w pps左右,其中99%以上都是伪造源地址的syn包。
既然是伪造地址,那就比较难处理,不过经过仔细的统计和分析,还是分析出了这次攻击中主要数据的特征,主要有以下几条:
1. tcp标志位为 syn 2. ip数据总长为40Byte 3. ip头中的Identifier字端固定为256(0x0100) 4. TTL值平均分布为 74 - 95之间 5. tcp窗口值固定为16384 6. 目标端口为tcp:80 7. tcp初始化序列号为 17314131xx,按+1累计依次递增
这样,注意看其中的3、4、5几条,这是对我们来说最重要的线索。
3. ip identifier字端固定为0x0100,而在TCP/IP规范中,这个字段是为了防止一个连接中的分片包重复而作的包内序列号。虽然大多数操作系统没有严格准循着一条规范,但这个数值的来源却是确定的,即在正常的TCP/IP堆栈中,这个字段的值应该是发送此数据包是的TCB(TCP控制块,一个内核空间的TCP数据结构)的序列号。而即使系统也没有严格准循这一条,那么在网络中传输的数据,identifier字段的内容也应该是随机分布的,正常的操作系统网络堆栈不可能发送出大量0x0100这样固定的字段内容来。
4. TTL值平均分布在74 - 95之间。按照常识也知道,大多数操作系统默认的TTL应该为32、64、128这样的2的整数次方;而另一个方面,TTL在网络传输的过程中每过一个路由器就会自动减一,而现在的Internet路由设计已经是比较良好的,从任何一点到达Intetnet的另一端,一般来说TTL条数不会超过20-30,这个我也测试过,从国内网通和电信的网络看来,到达国内和国际的大多数网站,TTL跳数都在20以内,而从Windows的Tracert命令也可以看出--它假设的最大TTL超时条数也只是30。超过30条的正常Internet路由是很罕见的。那么我们来做一个简单的减法:
128 - 30 = 98 64 - 30 = 34 32 - 30 = 2
所以一个数据包,在正常的传输过程中,当到达端点时,它的TTL数分布范围应该是:代码:
2 - 32 (罕见)、 34 - 64 、 98 - 128
而在本次数据采样中,大多数伪造地址的SYN数据,TTL都在74 - 95之间。
其他附加特征,例如IP长度、TCP窗口、TCP SYN_Flag等,也可以作为附加判断标志。这样我们提取出这次攻击的主要特征码为:
a. tcp syn flag only, dst port 80 b. ip identifier = 0x0100 c. 74 < ttl < 95 d. tcp window = 16384
这样四条特征。
之后就是想办法过滤了。因为这次没办法假设其他的防火墙,只能用系统自身的iptables挡一下,所以效果么......够麻烦的。
1. 下载最新版的iptables-1.3.1和patch-o-matic snapshot 。(需要Linux内核
2.6.10以上版本支持,这一点...Redhat系的所有版本都得重编了。)
ftp://ftp.netfilter.org/pub/patch-o-matic-ng/snapshot/
解压iptables和pom;
运行pom patch脚本,过程中需要输入iptables和内核源代码完全路径;
# ./runme connlimit u32 TARPIT pkttype length
编译和安装iptables及pom内核模块。
# make -C /lib/modules/`uname -r`/build SUBDIRS=net/ipv4/netfilter/ modules # make -C /lib/modules/`uname -r`/build SUBDIRS=net/ipv4/netfilter/ modules_install
编译iptables。并手工安装;
# make KERNEL_DIR=内核源码目录 # cp iptables iptables-save iptables-restore /usr/sbin # cp extensions/*.so /usr/lib/iptables/
2. 配置内核参数
====================================================================== #--以下为sysctl 内核参数设置 #net.ipv4.conf.default.rp_filter = 1 #net.ipv4.conf.all.rp_filter = 1 #net.ipv4.conf.eth1.rp_filter = 1 # 开启IP源地址验证,防止IP地址欺骗,在任何情况下都应开启,默认关闭 for f in /proc/sys/net/ipv4/conf/*/rp_filter; do echo 1 > $f done sysctl -w net.ipv4.conf.default.accept_source_route=0 # 禁用icmp源路由选项 sysctl -w net.ipv4.icmp_echo_ignore_broadcasts=1 # 忽略icmp ping广播包,应开启 #sysctl -w net.ipv4.icmp_echo_ignore_all=1 # 忽略所有icmp ping数据,覆盖上一项 sysctl -w net.ipv4.icmp_ignore_bogus_error_responses=1 # 以下一段为抵抗syn flood攻击,平时建议关闭 sysctl -w net.ipv4.tcp_syncookies=1 # tcp syncookie,默认关闭 sysctl -w net.ipv4.tcp_max_syn_backlog=1280 # syn队列,默认1024,> 1280可能工作不稳定,需要修改内核源码参数 sysctl -w net.ipv4.tcp_synack_retries=2 # syn-ack握手状态重试次数,默认5,遭受syn-flood攻击时改为1或2 sysctl -w net.ipv4.tcp_syn_retries=2 # 外向syn握手重试次数,默认4 # 以下一段为应对tcp connect连接耗尽攻击,如果开启iptables connlimit模块可禁用 # 有严重连接性能影响和不稳定因素,慎用 sysctl -w tcp_tw_recycle=1 # 默认0,tw快速回收 sysctl -w tcp_tw_reuse=1 # 默认0,tw重用 sysctl -w tcp_keepalive_intvl=60 # 默认75,tcp keeplive探测轮询时间 sysctl -w tcp_keepalive_probes=3 # 默认9,tcp keeplive探测轮询次数 sysctl -w tcp_keepalive_time=1800 # 默认7200,tcp keeplive时间 sysctl -w tcp_fin_timeout=30 # 默认60,tcp fin状态超时时间 #sysctl -w net.ipv4.tcp_retries1=2 # tcp连接重传参数,慎用 #sysctl -w net.ipv4.tcp_retries2=8 sysctl -w net.ipv4.ip_conntrack_max=65535 # 增大iptables状态跟踪表
======================================================================
3. 配置iptables规则
======================================================================
#--以下为iptables规则设置-- modprobe ipt_TARPIT modprobe ipt_u32 modprobe ipt_connlimit modprobe ipt_length modprobe ipt_pkttype iptables -N input_ext iptables -F input_ext # 新建iptables队列 iptables -A INPUT -i lo -j ACCEPT iptables -A INPUT -m state --state INVALID -j DROP iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT # 激活状态检测 iptables -A INPUT -i eth0 -j input_ext # 扩展input规则 iptables -A INPUT -j DROP # 默认input规则,丢弃全部 iptables -A input_ext -p tcp -m tcp --dport 80 --tcp-flags SYN,RST,ACK SYN -m u32 --u32 "0x2&0xffff=0x100&&0x5&0xff=0x4a:0x5f" -j DROP # 本次syn-flood攻击指纹特征,丢弃 iptables -A input_ext -p tcp -m tcp --dport 80 --tcp-flags SYN,RST,ACK SYN -m connlimit --connlimit-above 5 --connlimit-mask 32 -j TARPIT # 防止连接耗尽攻击,每IP并发连接限制为4 iptables -A input_ext -p tcp -j TARPIT # 防止端口扫描攻击 iptables -A input_ext -m pkttype --pkt-type broadcast -j DROP # 丢弃广播数据包 iptables -A input_ext -p icmp -m limit --limit 6/s -m icmp --icmp-type 4 -j ACCEPT # 接受icmp traceroute/echo reply数据,限制流量 5个/秒 iptables -A input_ext -p icmp -m limit --limit 6/s -m icmp --icmp-type 8 -j ACCEPT iptables -A input_ext -p icmp -m length --length 48:256 -j ACCEPT # 限制icmp包大小为 0 - 256Byte,防止大包flood # 实际网络中如果不用icmp/udp协议,可以直接全部drop
======================================================================
1. 带宽占满的情况下,任何防护都是没用的。
2. 任何ip数据都是可以伪造的,如果攻击数据完全采用随机数发送的话,那么很可能无迹可寻。
3. 在进行过滤和dos防御的时候,不可避免的会损失一些正常的连接,这个时候,想想80/20规则,
不要力求完美。
4. 任何安全防护措施和内核参数的调整,都可能对系统和网络的稳定性造成一定的负面影响,所以要根据实际情况而定,切勿忙从。
5. 这个防火墙规则中主要生效的是TCP段和ICMP段,在带宽未被占满时可以一定程度防止syn-flood、icmp-flood、tcp-connect-flood类型的DOS。
但是syn-flood的u32规则是针对这次攻击的特征所写的,在应对其他攻击时不可能完全有效,必须单独重新分析。
tcp-connect连接限制,我目前定的是同一ip地址并发5个web连接,防止连接耗尽,在局域网NAT访问时可能会有些问题,可以根据网络拓扑情况添加信任规则。
6. 常见的网络层dos主要有:
syn-flood (协议缺陷型)
ack-flood(stream) (协议缺陷型)
icmp-flood(smarf) (流量型)
udp-flood(froogle) (流量型)
tcp-connect-flood (资源型)
对于icmp和udp,可以在规则链开始就直接丢弃掉;
对于tcp-flood,可以使用conn-limit限制,效果比较好,但是要注意调整内核参数ip_conntrack的数值,否则可能造成iptables状态跟踪表溢出,反而形成拒绝服务;另外,当syn+ack类型的攻击发生时,本省也会消耗大量的conntrack资源,所以防火墙规则的顺序很重要。
对于syn-flood,最好的方法还是使用bsd pf的syn-proxy,效果不错,不过这个下次再讲吧。
如果不行的话,可能就只能针对个案进行模式特征分析了。
再次提醒,防火墙规则配置有风险,一定要根据自己实际情况调整和测试完毕后再上线。可以在input链的-j input_ext规则之前加一条:
-i INPUT 1 -s 内网地址 -j ACCEPT return之类的语句完全优先信任管理地址。
原文链接: