
1. 这不是“又一个AAA协议”——TACACS在Wireshark里到底长什么样很多人看到标题里的“TACACS”第一反应是“哦Cisco的认证协议不就是登录设备时输账号密码那个”然后顺手点开Wireshark过滤tcp.port 49抓几包看到一堆十六进制数据扫一眼Source、Destination、Length就关掉了。我当年也是这么干的——直到某次深夜排查一台核心交换机反复掉线的问题发现所有管理员登录日志都显示“Authentication Success”但设备却在认证通过后3秒内主动断开TCP连接。Wireshark里那几行TACACS包像一串沉默的密码既不像HTTP那样有明文路径也不像DNS那样带可读域名更不像TLS握手那样有清晰的ClientHello/ServerHello。它就躺在那里干净、紧凑、几乎不废话。这就是TACACS的真实面貌一个为网络设备管理而生的、极度克制的二进制协议。它不追求通用性不兼容其他厂商甚至不打算让你轻易读懂。它的设计哲学就写在RFC 89072021年更新版第1节里“TACACS is designed to be simple, efficient, and secure for the specific purpose of authenticating, authorizing, and accounting network device administrative access.” 注意关键词——administrative access不是用户上网不是API调用而是“谁被允许登上这台路由器改配置”。所以它天然带着一种“内部人协议”的封闭感。Wireshark能解码它不是因为它是开源标准而是因为Wireshark开发者硬生生逆向了Cisco多年来的实现细节并持续维护着这个解码器。你看到的“TACACS Authentication Start”、“TACACS Authorization Request”这些中文标签背后是成千上万行针对字段偏移、长度编码、密钥派生逻辑的C代码。这也是为什么单纯知道“TACACS用TCP 49端口”远远不够。当你在Wireshark里看到一个TACACS Authentication Start包它里面没有用户名明文除非你开了debug没有密码永远加密甚至没有明确的“我要登录哪个设备”的字段——所有上下文都藏在Session ID、Sequence Number和Header Flags这些看似枯燥的元数据里。真正的信息密度全在那个被加密的data字段里。而Wireshark的解码能力恰恰取决于你是否正确设置了共享密钥Shared Secret。没有密钥Wireshark只能告诉你“这是一个TACACS包”就像给你一张锁着的保险箱照片有了密钥它才能一层层剥开把username、port、rem_addr、priv_lvl这些关键字段还原成可读文本。这不是功能开关而是解密钥匙——它决定了你在Wireshark里看到的是“协议骨架”还是“活的管理会话”。所以这篇续集不讲“TACACS是什么”不列RFC定义也不画三层AAA模型图。我们直接钻进Wireshark的Packet Details面板从一个真实抓包文件开始一帧一帧地拆解当管理员在Cisco IOS设备上敲下enable命令时背后发生了什么Wireshark如何识别出这是TACACS而非RADIUS那个被标记为Encrypted data的字段到底藏着哪些决定权限的关键字为什么有时候Wireshark显示“Decryption failed”而有时候又能完美展开Authorization Response里的cmdshow run这些问题的答案不在文档里而在你鼠标双击那一帧数据包之后展开的每一层树状结构之中。2. 抓包前必须搞清的三件事端口、密钥、会话生命周期在Wireshark里看清TACACS第一步不是点Start Capture而是先回答三个问题我在抓谁和谁之间的通信用的什么密钥这个会话会持续多久忽略其中任何一个后续分析都会变成无源之水。2.1 端口选择49只是默认不是铁律绝大多数资料会告诉你“TACACS走TCP 49端口。” 这没错但仅限于Cisco设备的默认配置。实际生产环境中这个端口可能被修改。比如某金融客户为了规避安全扫描规则将所有AAA服务器监听端口统一改为18120又比如某运营商在多租户环境下为不同业务线分配了49、49001、49002三个端口分别处理接入网、核心网、网管系统的认证请求。如果你只过滤tcp.port 49就会漏掉90%的流量。更隐蔽的陷阱是双向通信方向。TACACS是典型的Client-Server模型网络设备NAS如交换机、路由器是ClientTACACS服务器如Cisco Secure ACS、FreeRADIUS with tacacs_plus module是Server。但Wireshark抓包位置决定了你能看到什么。如果你在NAS设备本机抓包tcpdump -i lo或monitor capture你会看到NAS作为Client发起的SYN到Server以及Server返回的SYN-ACK但如果你在Server侧抓包看到的就是反向的连接。而Wireshark的tcp.port 49过滤会同时匹配源端口和目的端口。这意味着在NAS侧抓包时tcp.port 49会捕获到src_port ! 49 dst_port 49的请求包以及src_port 49 dst_port ! 49的响应包因为Server回包时源端口是49在Server侧抓包时情况正好相反。实操中我习惯用更精准的过滤tcp.dstport 49 || tcp.srcport 49。但这还不够。真正可靠的方式是结合IP地址ip.addr 10.1.1.100 (tcp.dstport 49 || tcp.srcport 49)其中10.1.1.100是你的TACACS服务器IP。这样无论在哪台设备上抓包都能准确定位到目标会话。提示Cisco设备上查看当前TACACS配置的命令是show running-config | include tacacs。输出中tacacs-server host 10.1.1.100 port 49这一行port后面的数字就是你要过滤的实际端口号。别信“默认”一定要查配置。2.2 密钥Wireshark解码的唯一钥匙且必须完全一致这是最常被忽略、也最致命的一环。TACACS的data字段加密使用的是MD5-HMAC密钥Shared Secret参与了整个加密/解密流程。Wireshark的TACACS解码器要求你手动输入这个密钥且必须与NAS设备配置中的密钥逐字节完全相同——包括大小写、空格、特殊字符甚至不可见字符如Windows记事本可能插入的BOM头。我踩过一个典型坑客户提供的密钥是My$ecr3t!2023我复制粘贴进Wireshark的Protocol Preferences时末尾不小心多了一个空格。结果Wireshark显示所有包都是Encrypted data无法展开任何字段。排查了半小时最后用echo -n My\$ecr3t!2023 | md5sum和echo -n My\$ecr3t!2023 | md5sum对比才发现哈希值完全不同。TACACS协议本身不传输密钥Wireshark也无法自动推导它只做一件事用你给的密钥按RFC规定的算法HMAC-MD5 XOR obfuscation尝试解密。失败就原样显示加密数据。设置路径很隐蔽Edit → Preferences → Protocols → TACACS → Shared Secret。注意这里填的是NAS设备上配置的密钥不是TACACS服务器上的密钥虽然两者通常相同但逻辑上NAS是Client它用密钥加密发给Server的请求Server用同一密钥解密并生成响应。另外Wireshark支持多个密钥用分号;分隔适用于多服务器环境。但切记密钥字符串里如果本身包含分号必须用反斜杠\;转义否则Wireshark会错误分割。2.3 会话生命周期一次登录多次交互一个Session ID贯穿始终TACACS会话不是“一次请求-一次响应”那么简单。它是一个有状态的、基于Session ID的长连接。当你在Cisco设备上执行enable命令时触发的不是一个包而是一组紧密关联的交互Authentication StartNAS向Server发送初始认证请求包含用户名明文、端口类型vt100、源IP等但不包含密码Authentication ContinueServer回复指示NAS向用户索取密码GETDATA或直接拒绝Authentication ReplyNAS收到用户输入的密码后再次发包这次携带加密后的密码凭证Authorization Request认证成功后NAS立即发送授权请求询问“这个用户对enable命令是否有权限”Authorization ResponseServer返回statusPASS或statusFAIL并可能附带serviceshell、cmdenable等属性Accounting Request/Response用户登出时NAS发送计费开始/结束记录。所有这些包共享同一个Session ID4字节无符号整数在TACACS Header中。Wireshark会自动将它们归为一组显示在Packet List面板的Info列里如TACACS Authentication Start (Session: 0x1a2b3c4d)。你可以右键任一包 →Follow → TACACS StreamWireshark会自动筛选出该Session ID下的所有相关包按时间顺序排列。这是分析完整管理会话的黄金操作。没有这个意识你看到的只是一堆孤立的“Start”、“Reply”、“Request”根本拼不出完整的登录-提权-执行-退出链条。注意Session ID是NAS生成的每次新会话都会递增。但Wireshark不会帮你关联不同Session ID之间的逻辑比如同一个用户连续两次登录你需要靠username字段和时间戳手动串联。3. 拆解真实包从Authentication Start到Authorization Response的逐帧解读现在我们打开一个真实的抓包文件假设已正确配置密钥和过滤。聚焦一个典型场景管理员从SSH会话登录交换机后执行enable命令提升权限。Wireshark Packet List里你会看到连续几帧标着TACACS的包。我们按顺序逐帧深挖看Wireshark如何把二进制流翻译成运维语言。3.1 Frame 127Authentication Start —— “我要以user1身份登录”双击第一帧展开Packet Details。最顶层是TACACS协议树展开后看到Header和Body。Header里关键字段Version:0x12表示TACACS协议版本1.2十六进制对应十进制18Type:0x01即Authentication认证Flags:0x04Unencrypted位未置位说明body是加密的Single-connection位置位表示此会话只用于单个连接Session ID:0x1a2b3c4d这个ID将贯穿后续所有交互Sequence Number:0x01这是该Session内的第一个包Encryption Type:0x01表示使用DES加密老设备或0x05表示AES新设备但Wireshark解码逻辑相同。展开BodyWireshark已用密钥解密显示为Authentication Start。里面是明文字段username:user1—— 用户名明文传输port:vt100—— 终端类型告诉Server这是VT100终端常见于SSHrem_addr:192.168.5.10—— 用户连接NAS的源IPServer据此判断访问位置priv_lvl:1—— 当前用户权限等级1普通用户15enable级别这里还是低权限。这里有个重要细节password字段完全不存在。TACACS的设计哲学是“密码永不离开用户终端”。NAS只负责收集用户名和终端信息发给ServerServer再指令NAS去向用户索要密码。这和RADIUS的“NAS收集密码并转发”有本质区别安全性更高但也意味着第一次交互里你看不到密码相关字段。3.2 Frame 128Authentication Continue —— “请让用户输入密码”下一帧Type仍是0x01Authentication但Sequence Number变为0x02Flags里的Continue位被置位0x08。Wireshark解码为Authentication ContinueBody里最关键的字段是status:GETDATA—— Server指令NAS请向用户索取数据即密码data:Password:—— 提示字符串NAS会把它显示在终端上flags:NOECHO—— 告诉NAS用户输入时不要回显星号遮挡。此时Wireshark的Info列会显示TACACS Authentication Continue (GETDATA) (Session: 0x1a2b3c4d)。你甚至能在Packet Bytes面板里看到ASCII编码的Password:字符串。这证明了TACACS的“指令驱动”特性Server不被动等待而是主动指挥NAS下一步动作。3.3 Frame 129Authentication Reply —— “密码已收到验证通过”用户输入密码后NAS封装新包。Sequence Number变为0x03Type不变Flags恢复为0x04非Continue。Wireshark解码为Authentication ReplyBody里status:PASS—— 认证成功server_msg:Authentication successful—— Server返回的成功消息可配置data: 空—— 无额外数据。至此用户名密码校验完成。但注意priv_lvl在这里并未提升。enable命令的权限提升是下一个独立的授权过程。3.4 Frame 130Authorization Request —— “用户user1想执行enable命令批准吗”这才是权限提升的核心。Type变为0x02AuthorizationSequence Number0x01新子会话开始Session ID不变。Wireshark解码为Authorization RequestBody里字段丰富user:user1—— 再次确认用户名port:vt100—— 同上rem_addr:192.168.5.10—— 同上priv_lvl:15—— 关键NAS在此声明“用户要提升到level 15”authen_method:ENABLE—— 明确这是enable命令触发的授权service:shell—— 服务类型是shell命令行cmd:enable—— 具体命令args: 空—— enable命令无参数。这个包清晰地展示了TACACS的精细化控制能力。Server可以根据usercmdpriv_lvl的组合决定是否放行。比如策略可以设定“user1可以执行show类命令但enable必须由admin-group成员执行”。3.5 Frame 131Authorization Response —— “批准赋予level 15权限”最后一帧Type0x02Sequence Number0x02StatusPASS。Wireshark解码为Authorization ResponseBody里status:PASSmsg:Authorizeddata:serviceshell cmdenable priv-lvl15—— Server返回的授权详情NAS据此设置用户session的privilege level。此时Wireshark的Packet List里Info列会显示TACACS Authorization Response (PASS) (Session: 0x1a2b3c4d)。你甚至可以在data字段里直接看到priv-lvl15这个字符串。这就是为什么管理员敲完enable后提示符从Switch变成了Switch#——NAS收到了Server的明确指令。实操心得如果Authorization Response里status是FAILWireshark的data字段往往会包含拒绝原因如denied by policy或insufficient privileges。这比设备CLI上模糊的% Authorization denied错误要具体得多是排错的第一手证据。4. 那些Wireshark不会告诉你的“灰色地带”加密失效、字段歧义与调试陷阱Wireshark的TACACS解码器非常强大但它不是万能的。有些问题它要么不显示要么显示得模棱两可需要你结合协议原理和设备行为来交叉验证。这些“灰色地带”恰恰是资深网络工程师价值所在。4.1 “Decryption failed”密钥正确但依然解密失败的三种可能即使你100%确认密钥正确Wireshark仍可能显示Encrypted data或Decryption failed。这时别急着重输密钥先检查这三个点加密类型不匹配TACACS Header里的Encryption Type字段0x01到0x05告诉Wireshark用哪种算法。但某些老旧NAS固件如IOS 12.2可能错误地将AES加密的数据标记为0x01DES导致Wireshark用DES密钥去解AES密文必然失败。解决方案在Wireshark Preferences里取消勾选Use encryption type from packet header强制Wireshark使用你指定的密钥和默认算法通常是MD5-HMAC尝试解密。时间漂移过大TACACS的HMAC计算中会加入一个时间戳session_id的一部分或独立字段。如果NAS和Server的系统时间相差超过5分钟Server生成的HMAC会失效NAS发给Server的包会被拒绝而Server返回的响应包其HMAC也可能因时间不一致而无法被Wireshark正确验证。现象是所有Reply和Response包都显示Decryption failed但Start和Continue包能解密。检查show ntp status和show clock同步时间。NAS配置了single-connection但Server不支持Flags里的Single-connection位0x04表示NAS希望复用TCP连接。但如果TACACS Server如旧版FreeRADIUS配置为per-request模式它会在每次响应后关闭连接。NAS重连时新连接的Session ID变了但Wireshark仍试图用旧Session ID关联包导致解密上下文错乱。此时Wireshark的Follow TACACS Stream会失效。解决方法在NAS上关闭single-connectiontacacs-server directed-request或升级Server软件。4.2 字段歧义priv_lvl在Authentication和Authorization中的不同含义Wireshark会把priv_lvl字段原样显示出来但它在不同包里的语义完全不同极易误解在Authentication Start包里priv_lvl: 1表示用户当前登录的权限等级即普通用户模式这是NAS上报的现状在Authorization Request包里priv_lvl: 15表示用户本次请求的目标权限等级即想升到enable模式这是NAS发起的申请在Authorization Response包里data字段里的priv-lvl15表示Server批准授予的最终权限等级这是决策结果。初学者常犯的错误是看到Authentication Start里的priv_lvl: 1就以为用户只能是level 1看到Authorization Request里的priv_lvl: 15就以为NAS已经给了level 15。实际上priv_lvl在Start包里是“状态”在Request包里是“诉求”在Response包里是“裁定”。Wireshark不会帮你标注这些语义差异它只忠实呈现字段值。你需要自己根据Type和Body上下文来解读。一个快速判断法Authentication包里的priv_lvl永远是当前值Authorization包里的priv_lvl永远是目标值Accounting包里的priv_lvl则是最终生效值。4.3 调试陷阱show aaa authorization命令的误导性输出Cisco设备上show aaa authorization命令会显示“Method list for enable”及其状态SUCCESS/FAIL。但这个输出有严重滞后性。它反映的是上一次授权的结果缓存而不是当前正在发生的实时交互。例如你修改了TACACS Server策略禁止user1执行enable但设备CLI里show aaa authorization仍显示SUCCESS因为缓存没刷新。此时抓包Wireshark里Authorization Response的status已经是FAIL但设备CLI还没更新显示。更隐蔽的陷阱是aaa authorization exec default local这类本地回退配置。当TACACS Server不可达时NAS会自动切换到本地数据库验证。Wireshark里你只会看到TACACS超时TCP Retransmission看不到本地认证过程因为本地认证不走网络。show aaa authorization却可能显示SUCCESS来自本地让你误以为Server工作正常。真相藏在debug aaa authentication和debug aaa authorization日志里而Wireshark抓包是验证这些日志是否真实的唯一手段。最后一个小技巧Wireshark里右键任意TACACS包 →Protocol Preferences → TACACS勾选Show decrypted data in packet bytes pane。这样Packet Bytes面板里被解密的明文字段会以高亮绿色显示比在Packet Details里翻找更快捷。尤其适合快速扫描大量包里的username或cmd字段。