COMMAND

    TACACS+

SYSTEMS AFFECTED

    See advisory

PROBLEM

    Solar Designer found following.  It's his analysis of the  TACACS+
    protocol  and  its  implementations.   This  advisory  presents an
    analysis  of  several  vulnerabilities  in  the  TACACS+ protocol.
    Unfortunately,  only  some  of  the  vulnerabilities  can be fixed
    without breaking the interoperability.  Thus, the main purpose  of
    this  advisory  is  to  identify  the  weaknesses,  to allow for a
    conscious decision to be made on how much trust to place into  the
    encryption offered by TACACS+ -- on a case by case basis.

    Quoting  the  RFC  draft,  "TACACS+  provides  access  control for
    routers,  network  access  servers  and  other networked computing
    devices via  one or  more centralized  servers... TACACS+ improves
    on   TACACS   and   XTACACS   by   separating   the  functions  of
    Authentication,  Authorization  and  Accounting  and by encrypting
    all traffic  between the  NAS and  the daemon...  TACACS+ uses TCP
    for its transport."   A copy of the  RFC draft can be  obtained at
    one of the following locations:

        ftp://ftpeng.cisco.com/pub/tacacs/tac-rfc.1.78.txt
        http://www.cisco.com/warp/customer/459/tac-rfc.1.76.txt

    The attacks described here assume  an attacker with access to  the
    wire  but  no  knowledge  of  the  encryption  key,  unless stated
    otherwise.  The  first two vulnerabilities  might seem obvious  to
    those familiar with the protocol.   They are listed first to  help
    simplify understanding of the rest of the analysis, despite  their
    relatively minor impact.

    1. Lack of integrity checking
    =============================
    Impact: accounting records can  be altered while in  transmission.
    Almost no integrity  checking exists in  TACACS+.  The  only check
    defined in  the RFC  draft is  to make  sure the  sum of component
    lengths matches the total size of the packet.

    Combined with the MD5-based stream cipher used to encrypt  TACACS+
    packets, this lets an attacker  with access to the wire  flip most
    of the  bits in  the packet  (which affects  the plaintext  in the
    same way) without the change getting detected.  In particular,  it
    is  possible  to  make  meaningful  changes to accounting packets,
    such as modifying an elapsed_time from 9000 to 1000 with the  flip
    of one bit.

    2. Vulnerability to replay attacks
    ==================================
    Impact:  duplicate  accounting  records  can be produced, possibly
    with  forged  task_id  fields  to  avoid detection.  TACACS+ lacks
    virtually  any  protection  against  replay  attacks.   The   only
    requirement is that packets have a correct sequence number.  Since
    all TACACS+  sessions start  with a  sequence number  of 1  (not a
    vulnerability in and  of itself), the  TACACS+ server will  always
    process a packet with  seq_no set to 1.   Packets from the  middle
    of a  TACACS+ session  can't always  be replayed,  as an  attacker
    would need to successfully get the session to the required  seq_no
    first.

    Especially easy to replay  are accounting sessions, which  consist
    of  only  one  packet  sent  to  the  server (with a seq_no of 1).
    Obviously, it is also possible to replay the packets with  certain
    bits  flipped,  such  as  to  get  different  task_id's  in case a
    billing system is smart enough to check for duplicate records.

    The  fact  that  TACACS+  uses  TCP  provides  no security against
    replay, as new  TCP connections may  be opened by  an attacker for
    replaying recorded TACACS+ sessions.

    3. Forced session_id collisions
    ===============================
    Impact: the encryption of reply  packets can be compromised.   Due
    to its use of a stream cipher, the strength of TACACS+  encryption
    depends heavily on unique session_id's  for each session.  If  two
    different packets happen to get  the same session_id and the  same
    seq_no, they both become  vulnerable to simple frequency  analysis
    attacks.  Additionally, if there's  known plaintext in one of  the
    packets, the  corresponding parts  of the  other can  trivially be
    decrypted.

    Unfortunately, it is possible to get the TACACS+ server to encrypt
    a reply packet  using a session_id  of our choice.   Combined with
    our ability to replay packets sent to a TACACS+ server, this  lets
    us compromise  the encryption  of most  of the  packets on the way
    back.  This holds true for  almost all packets with a seq_no  of 2
    (the first reply  packets in a  session), as we're  always able to
    make the server at least have  a look at and reply to  our initial
    replayed packets (seq_no of 1).  In order to make sure the  second
    reply is different from the original  one, we can flip a few  bits
    in the request packet, or indeed change anything in its  cleartext
    header, before replay.

    Luckily,  passwords  are  typically  only  contained  in   packets
    travelling  to  the  server  (which  are  not  affected  by   this
    vulnerability)  --  not  on  the  way  back.   There're,  however,
    exceptions to this: passwords for outbound PAP have to be sent  to
    the remote  end of  a PPP  link; likewise,  passwords for  inbound
    CHAP  used  to  be  given  to  the  NAS (in minor_version 0 of the
    protocol, now deprecated).  Information other than user  passwords
    may  be  of  some  use  for  an  attacker  as  well; this includes
    usernames and AV pairs.

    4. The birthday paradox and session_id's
    ========================================
    Impact:  given  enough  sessions,   encryption  of  many  may   be
    compromised.   Another problem  with session_id's  is that they're
    too small to be unique if randomly chosen (as required by the  RFC
    draft),  and  there's  no  other  way  to  keep them unique across
    multiple NAS'es and reloads.

    Due to the  birthday paradox, we  can expect to  see two different
    sessions  with  the  same  session_id  if  we  watch about 100,000
    TACACS+   sessions.    As   separate   sessions   are   used   for
    authentication,  authorization,  and  accounting,  and as multiple
    accounting records are sent via  TACACS+ at different stages of  a
    user's  session  to  the  NAS,  this  may correspond to only about
    20,000 dialup sessions.  Even  for a relatively small ISP,  we can
    expect to see a  match within one day.   If we watch for  a month,
    we can get about 1000 matches,  which might give us a few  hundred
    user passwords  given the  amount of  luck (that  is, which packet
    types  get  the  same  session_id)  and  known  plaintext (such as
    attribute names) we can reasonably expect.

    5. Lack of padding
    ==================
    Impact: the lengths of user passwords can be determined.  The  RFC
    draft states that "there should be no padding in any of the fields
    or at the  end of a  packet".  Indeed,  the implementations follow
    this requirement.

    The security implication, however, is that the lengths of variable
    size data fields can often be determined from the packet sizes  --
    an attacker only needs a way to find out which packets contain the
    information they are looking for.  This task is simplified by  the
    fact that sequence numbers and packet types are transmitted in the
    clear.   In  the  case   of  determining  password  lengths,   the
    corresponding usernames can be obtained  via finger to the NAS  or
    similar approaches.

    6. MD5 context leak
    ===================
    Impact:  none  practical;  in  pathological  cases,  a part of the
    packet  can  be   decrypted.   This   vulnerability  is  only   of
    theoretical value when  applied to TACACS+,  and is included  here
    for completeness'  sake, as  well as  to remind  developers of the
    way MD5-like hashes  should not be  used.  You  should be familiar
    with MD5 (RFC 1321) in order to understand this short description.

    The body  of TACACS+  packets is  encrypted by  XOR'ing it  with a
    series of MD5 hashes (each 16  bytes long).  The first two  hashes
    (used  to  encrypt  first  32  bytes  of  the  packet body) are as
    specified in the RFC draft:

        MD5_1 = MD5{session_id, key, version, seq_no}
        MD5_2 = MD5{session_id, key, version, seq_no, MD5_1}

    Now, let's assume this pathological scenario:

        - the key is 49 bytes long;
        - we know or can guess first 16 bytes of the packet body;
        - first 9 bytes of MD5_1 are: 80 B8 01 00 00 00 00 00 00.

    (In practice, it would take  about 2**72 packets until we  see one
    with the required bytes in MD5_1.  This is clearly far too many.)

    As we have the 16 bytes  of known plaintext, we can determine  the
    entire  MD5_1  (not  just  the  9  bytes  we  check  for) from the
    encrypted packet.  This MD5_1 will match the normally unknown  MD5
    context from within the calculation of MD5_2 (after processing  of
    the first 64-byte block).

    Now, MD5_2 becomes a function of MD5_1 only; we no longer need  to
    know the key in order to calculate MD5_2.  Once we get MD5_2,  the
    decryption of the second 16 bytes of the packet body is trivial.

    A way  to make  this attack  impossible (and  not just infeasible)
    would be to define MD5_1 like this:

        MD5_0 = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
        MD5_1 = MD5{session_id, key, version, seq_no, MD5_0}

    7. Packet body length DoS and/or overflow
    =========================================
    Impact:  TACACS+  server  DoS,   TACACS+  client  DoS,   potential
    break-in.   Unlike  other  issues  discussed  here,  this  is   an
    implementation  defect.   However,  the  mistake  is   "essential"
    enough  that   both  implementations   checked  (the   unsupported
    TAC_PLUS  Developer's  Kit  vF4.0.3.alpha  and Cisco IOS 11.3(9)T)
    turned out to be vulnerable.

    One of the  fields in the  12-byte cleartext packet  header is the
    body length.  The obvious way  to read a packet off the  socket is
    to read the header first,  allocate memory for the body,  and then
    read the body with another call.  The "essential" mistake here  is
    to not sanity check the length field before allocating the memory.

    Thus, a trivial DoS attack on  a TACACS+ server is to make  it run
    out of  memory by  sending it  a packet  with a  huge value in the
    length field.  Depending  on the malloc(3) implementation,  it may
    also be required to actually fill the memory with data (which will
    require  some  time  for  transmitting  the  data,  but  is  still
    trivial).

    It is also  essential for implementations  to allocate memory  for
    both the packet header and the body, and copy the header into that
    memory before reading  the body off  the socket.   The "essential"
    mistake  here  is  to  not  check  for  an  integer  overflow   in
    calculating the total memory size to allocate.

    In tac_plus, this  results in the  ability to overflow  the buffer
    with our packet header  data by up to  11 bytes.  This  is usually
    harmless, but there might exist platforms where it's not.

    Obviously, these two attacks  require neither access to  the wire,
    nor knowledge of the key.  The only requirement is the ability  to
    connect to a TACACS+ server.

    Additionally,  it  is  possible  to  cause  tac_plus  to  at least
    misbehave by  exploiting the  first two  vulnerabilities mentioned
    here,  together  with  the  lack  of  integer overflow checking in
    calculating  the  sum   of  packet  component   lengths  for   the
    comparison.  It is likely  that other attacks on tac_plus  and the
    underlying OS are possible when  the encryption key is known,  but
    these are outside the scope of this analysis.

    Similar attacks  are possible  against the  clients; however, they
    require either access to the wire, or the ability to do blind  TCP
    sequence number and timing prediction.  In the case of Cisco  IOS,
    it is  possible to  allocate all  of the  available I/O memory for
    the duration of the TCP connection.

    Dylan  added  following.   Note  what  happens  when you change an
    enable (or any other, for that matter) password:

        Sat Apr 22 09:01:03 2000        x.x.x.x   xxxxxxx        tty1
        x.x.x.x    stop    task_id=131     start_time=956171839
        timezone=UTC    service=shell   priv-lvl=0      cmd=password <cleartext>
        <cr>

    The log entry is sent & stored in cleartext.  The best  suggestion
    is to disable aaa before changing passwords and then turn it  back
    on when you're done.

SOLUTION

    The  tac_plus  DoS  can  be  fixed  by  applying this simple patch
    (besides packet filtering, which you should have anyway):

    --- tac_plus.F4.0.3.alpha.orig/packet.c	Sat Apr  3 10:03:46 1999
    +++ tac_plus.F4.0.3.alpha/packet.c	Sun Nov 28 08:28:27 1999
        @@ -446,6 +446,13 @@

         /* get memory for the packet */
         len = TAC_PLUS_HDR_SIZE + ntohl(hdr.datalength);
    +    if ((ntohl(hdr.datalength) & ~0xffffUL) ||
    +	len < TAC_PLUS_HDR_SIZE || len > 0x10000) {
    +	report(LOG_ERR,
    +	       "%s: Illegal data size: %lu\n",
    +	       session.peer, ntohl(hdr.datalength));
    +	return(NULL);
    +    }
         pkt = (u_char *) tac_malloc(len);

         /* initialise the packet */

    This vulnerability will also be fixed in tac+ia (a tac_plus clone)
    version 0.96 and later.

    Note: these  are general  security recommendations  on setting  up
    TACACS+ - they  cannot fix some  of the inherent  protocol defects
    discussed above.

    1. Apply packet filtering where possible
    ========================================
    In the  simple case,  you will  have all  the TACACS+  clients and
    servers  within  your  network.   Make  sure  the servers are only
    accessible from within  your network, and  preferably only by  the
    IP addresses  of the  clients (this  may require  a combination of
    filters on the server systems themselves and anti-spoofing filters
    on  your  border  routers).   The  default  TACACS+ server port is
    49/tcp.

    2. Choose strong encryption keys
    ================================
    Offline attacks against the encryption key are possible with  only
    one  packet  collected  off  the  wire,  and  run much faster than
    similar  attacks  against  UNIX  passwords  do.   Thus,  a  strong
    encryption  key  should  be  larger  than a typical user password.
    Keep in  mind that  if the  key becomes  known, additional attacks
    against both TACACS+ server and client systems become possible.

    3. Avoid running tac_plus as root
    =================================
    Unfortunately,  version  F4.0.3.alpha  has  a  few  problems  when
    running as non-root, but  it does support the  TAC_PLUS_USERID and
    TAC_PLUS_GROUPID defines  at compile  time.   Be sure  not to have
    any extra supplementary  groups when you  start tac_plus, as  it's
    not smart enough to drop  those.  tac+ia-0.96 and later  will have
    --enable-tacplus-username 'configure' option.

    Cisco's commercial offerings CiscoSecure  for Unix and NT  are not
    vulnerable  to  the  described  overflow.   If an oversize TACACS+
    packet is  sent to  an IOS  client, IOS  will report  an error  as
    mentioned in the analysis and reject that packet.  The device will
    continue  to  function  normally  and  no  service disruption will
    occur.

    In  order  to  utilize  other  TACACS+  protocol  shortcomings  as
    described in the brilliant  analysis by Solar Designer,  a culprit
    must have  access to  the path  between the  TACAS+ client and the
    server.

    As  of  July  2000,  Cisco  updated  their  unsupported version of
    TACACS+  server  so  it  is  no  longer vulnerable to oversized T+
    packets.  You can download  the new version, F4.0.4 alpha,  if you
    follow this URL:

        ftp://ftp-eng.cisco.com/pub/tacacs