商务合作加Q:411239339

一次DOS事件的解决办法

浏览:371次阅读
没有评论

共计 6005 个字符,预计需要花费 16 分钟才能阅读完成。

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 之类的语句完全优先信任管理地址。

正文完
扫码赞助
post-qrcode
 0
果子
版权声明:本站原创文章,由 果子 于2015-01-04发表,共计6005字。
转载说明:除特殊说明外本站文章皆由果较瘦原创发布,转载请注明出处。
评论(没有评论)