Follow @Openwall on Twitter for new release announcements and other news

An Analysis of TACACS+ Protocol Security

by Solar Designer
May 30, 2000
Last revised: July 7, 2024

This article presents an analysis of several vulnerabilities in Cisco's TACACS+ protocol. Unfortunately, only some of the vulnerabilities can be fixed without breaking the interoperability. Thus, the main purpose of this article 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." Copies of the RFC draft (from 1990s) and the final RFC (from 2020) can be obtained at:

Vulnerabilities

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. However, there are 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:

(In practice, it would take about 272 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.

Fixes

Cisco has fixed the tac_plus DoS/overflow in version F4.0.4.alpha of their unsupported Developer's Kit.

This vulnerability is also fixed in tac+ia (a tac_plus clone) version 0.96.

Alternatively, you can apply this simple patch to an older version of tac_plus:

--- 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 */

Recommendations

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.

References

Credits and contact information

The analysis has been performed by Solar Designer <solar at openwall.com>. I would like to thank Dug Song for reviewing the security advisory (which this article is based on) and Damir Rajnovic of Cisco Systems PSIRT for handling these vulnerabilities within Cisco.

Updated versions of this article will be made available at https://www.openwall.com/articles/TACACS%2B-Protocol-Security.

Revision history

Release: May 30, 2000 (Openwall security advisory OW-001-tac_plus)
Updated: July 10, 2000 (revision 2 of the above)
Updated: June 6, 2010 (converted into article, better HTML formatting)
Updated: June 19, 2014 (dropped ftpeng.cisco.com links, which no longer work)
Updated: July 7, 2024 (updated RFC links)

115329