skip to content

Reading a TACACS+ capture without the shared secret, what can the 12-byte header still tell you?

level: middleimportance: must knowfreq 55%

answer

  1. twelve octets before anything protected
  2. parity gives you the direction
  3. one field groups packets into a session
  4. type names the exchange family
  5. length counts the body only

basics

~20 s

The 12-byte header is unprotected, so a capture always yields the protocol version, which of the three exchange families the packet belongs to, its sequence number and direction, the session_id grouping packets, and the body length.

solid answer

~40 s

Every TACACS+ packet starts with a 12-octet header that is never obfuscated, so an operator with a capture and no shared secret can still read a great deal. One octet holds the version, split into `major_version` (`TAC_PLUS_MAJOR_VER := 0xc`) and `minor_version`. The `type` octet says which family the packet belongs to: `TAC_PLUS_AUTHEN := 0x01`, `TAC_PLUS_AUTHOR := 0x02` or `TAC_PLUS_ACCT := 0x03`. `seq_no` gives both position and direction, because the first packet of a session is 1 and the client sends only odd numbers while the server sends only even ones. The 4-octet `session_id` groups packets into sessions, and the 4-octet `length` counts the body alone. What you cannot read is the body itself.

code

pseudocode · 15 lines
pseudocode
TACACS+ packet := 12-octet header, then body

offset 0  version     high nibble  major_version := 0xc
                      low  nibble  minor_version := 0x0 or 0x1
offset 1  type        TAC_PLUS_AUTHEN := 0x01
                      TAC_PLUS_AUTHOR := 0x02
                      TAC_PLUS_ACCT   := 0x03
offset 2  seq_no      first packet of a session = 1
                      client sends odd, server sends even
offset 3  flags       TAC_PLUS_UNENCRYPTED_FLAG   := 0x01
                      TAC_PLUS_SINGLE_CONNECT_FLAG := 0x04
offset 4  session_id  4 octets, constant for the session's life
offset 8  length      4 octets, length of the BODY only

offset 12 body        protected; not readable from a capture alone

go deeper

for a junior

Know that a TACACS+ packet is a 12-octet header followed by a body, and that only the header is readable in a plain capture.

for a middle

Name each header field and what it buys an operator: family from type, direction from sequence parity, grouping from session_id, body size from length.

for a senior

Demonstrate the diagnosis: reconstruct exchanges from a capture by session_id, spot an authorization session that has gone past two packets, and state plainly which questions the body would be needed for.

for a principal

Consider what it means operationally that traffic shape is universally visible while content is not — it makes capture a safe tool to hand to network operations without widening access to credentials or commands.

## Why the header is the diagnostic surface TACACS+ protects the body of every packet and leaves the 12-octet header in front of it alone. That single design fact is what makes the header the thing an operator actually works with: on a fabric where a device-administration server is misbehaving, a capture taken without the shared secret still answers most of the questions worth asking, and the body answers none of them. ## The twelve octets, field by field - **version** (1 octet) — split into two nibbles: `major_version`, which is `TAC_PLUS_MAJOR_VER := 0xc`, and `minor_version`, either `TAC_PLUS_MINOR_VER_DEFAULT := 0x0` or `TAC_PLUS_MINOR_VER_ONE := 0x1`. - **type** (1 octet) — `TAC_PLUS_AUTHEN := 0x01`, `TAC_PLUS_AUTHOR := 0x02` or `TAC_PLUS_ACCT := 0x03`. This is the field that tells you whether you are watching a login, a permission check or a record being written, without reading a single byte of the body. - **seq_no** (1 octet) — the packet's position in its session. The first packet of a session is 1; the client sends only odd numbers and the server only even ones, so parity alone tells you the direction. - **flags** (1 octet) — carries `TAC_PLUS_SINGLE_CONNECT_FLAG := 0x04`, the offer and confirmation of single connection mode, and `TAC_PLUS_UNENCRYPTED_FLAG := 0x01`, which is set when the body is sent without the protocol's body protection. - **session_id** (4 octets) — the session's name, fixed for its whole life. Sorting a capture by this field is how you reassemble one exchange out of a busy connection. - **length** (4 octets) — the length of the **body only**, not of the whole packet. The 12 header octets are not counted. 1 + 1 + 1 + 1 + 4 + 4 = 12. If your recollection of the header does not add to twelve, one of the fields is wrong. ## What the header answers, and what it refuses to | Question an operator asks | Answerable from the header? | |---|---| | Which exchange family is this — login, permission check or record? | Yes, from `type` | | Which end sent this packet? | Yes, from the parity of `seq_no` | | Which packets belong together? | Yes, from `session_id` | | How far into the exchange are we? | Yes, from the value of `seq_no` | | Did the two ends agree to reuse this connection? | Yes, from `flags` on the first two packets | | Which user, which command, which result? | No — that is in the body | That last row is the whole point of the split. You can characterise the traffic completely and learn nothing about the people in it, which is exactly what you want when handing a capture to someone debugging churn rather than investigating an account. ## Reading a real trace A typical healthy pattern on one connection looks like this: 1. A packet with `seq_no` 1, `type` `TAC_PLUS_AUTHOR := 0x02`, a fresh `session_id`, from the device. 2. A packet with `seq_no` 2, the same `session_id`, from the server. 3. The connection closing — or, if single connection mode was established, a new `session_id` at `seq_no` 1. An authorization or accounting session that shows more than two packets is anomalous, because those exchanges are defined as a single request and a single reply. An authentication session, by contrast, can legitimately run to many packets as the server asks for more input. ## The size field is a defensive control too Because `length` is 4 octets, a body could in principle claim to be enormous. RFC 8907 recommends a maximum packet size of 2^16 and requires that an implementation allow the server's maximum accepted size to be controlled, so that a server is not obliged to buffer whatever a client asserts. When you read the field in a capture, read it as a claim the receiver is entitled to reject rather than as a fact. ## Interview register Do not recite the six fields as a list — that is a flashcard. Say what each one buys you when the body is opaque: family from `type`, direction from parity, grouping from `session_id`, progress from the value of `seq_no`, connection reuse from `flags`. Then state the limit: everything about the user, the command and the answer is in the body, and the header will never give it to you.

  • A capture shows one session_id whose packets run 1, 2, 3, 4, 5 — what does that tell you about the exchange?
    That it is an authentication sequence. Authorization and accounting sessions are defined as exactly one request and one reply, so they never go past `seq_no` 2. A five-packet session means the server kept asking the device for more input, and the odd numbers are the device's packets while the even ones are the server's.
  • Why does the length field count only the body?
    Because the header is fixed at 12 octets and the receiver has already read it before the field means anything. Counting the body alone lets the receiver read 12 octets, learn how many more to expect, and read exactly that many. It also means the value can be compared directly against the server's configured maximum accepted body size.
  • What can you not learn from a TACACS+ capture without the shared secret?
    Everything in the body: the user name, the terminal line the login arrived on, the command and its arguments, the privilege level, the server's verdict and any message shown to the operator. Only the 12-octet header and the connection-level behaviour are available, which is why capture-based diagnosis is limited to traffic shape.

saying these in an interview costs you the question

  • Saying the length field counts the whole packet including the header
  • Thinking sequence numbers restart per connection rather than per session
  • Treating even sequence numbers as coming from the network device
  • Claiming a capture shows the user name when the body is protected
  • Believing the header is protected along with the body
  • Confusing the header's flags octet with an accounting record's flags