简介:本资源为信息安全技术应用专业《通过WireShark进行SSH协议分析3》配套教学文档,面向网络安全初学者、职业院校学生及参加分组对抗赛的选手,帮助其理解SSH协议从密钥交换、用户认证到加密数据传输的完整工作流程,并掌握使用WireShark抓包分析协议交互的实践方法。资源包内含1个docx文档,压缩包约37KB,文档以实训任务为主线,涵盖算法协商过程、密钥交换与用户认证机制、服务请求与连接关闭等预备知识,并给出配置IP地址、设置过滤条件、从Ubuntu登录CentOS SSH服务、逐项分析TCP连接建立、SSH服务版本信息、密钥交换初始化消息、加密数据及TCP断开连接等实训步骤,便于读者对照操作、复盘协议细节并排查网络问题。目前已有111人学习,适合作为协议分析入门与赛题演练的参考材料。
1. 从一次 SSH 登录抓包说起:WireShark 里到底能看到什么
很多人第一次用 WireShark 抓 SSH,看到满屏Encrypted packet就以为没东西可分析,直接关掉。其实恰恰相反——SSH 的握手阶段、算法协商、密钥交换、认证方式选择,全都是明文可读的,真正被加密的只有会话数据。这也是「通过 WireShark 进行 SSH 协议分析」这个实验的核心价值:它逼着你去理解一个加密协议在链路上到底暴露了多少元信息。
这篇笔记面向三类人:正在做信息安全技术应用专业实训的学生、需要给 SSH 连接做故障定位的运维、以及想搞懂「加密协议抓包到底能抓到什么」的安全初学者。我会按「先看清 SSH 在 WireShark 里的分层结构 → 再动手抓一次完整登录 → 然后逐字段拆解握手与认证 → 最后讲清楚哪些坑会让你抓不到包」的顺序推进。WireShark 抓包及分析这件事,SSH 是最好的练手对象,因为它既有明文协商又有加密载荷,边界清晰。
2. SSH 在 WireShark 里的协议分层与过滤表达式
2.1 为什么 SSH 能被解析成多个子协议
WireShark 对 SSH 的解析不是把它当成一个黑盒 TCP 流,而是按 RFC 4253 的二进制包结构逐层拆开。你在包列表里点开一个 SSH 包,会看到SSH Protocol下面挂着SSH Version 2、Key Exchange、Algorithm Negotiation等子树。这不是 WireShark 猜的,而是 SSH 传输层协议本身就有明确的报文类型字段(msg code),1~49 是传输层通用消息,50~79 是用户认证消息,80 以上是连接协议消息。
理解这一点很关键:SSH 的加密是从密钥交换完成之后才生效的,在此之前的所有报文——包括协议版本交换、算法列表、DH 公钥——都是明文。WireShark 能解析它们,是因为它知道这些报文的固定格式。一旦进入Encrypted packet,WireShark 就只能显示密文长度和方向,除非你配置了解密密钥。
2.2 常用显示过滤表达式速查
抓 SSH 最怕的是混在一堆无关流量里找不到目标。下面这几个过滤器是我实际做实验时反复用的,直接抄:
# 只看 SSH 流量(基于端口,最常用) tcp.port == 22 # 只看 SSH 协议解析出来的包(比端口更准,能排除非 SSH 的 22 端口流量) ssh # 只看密钥交换阶段的包 ssh.message_code == 20 || ssh.message_code == 30 || ssh.message_code == 31 # 只看认证阶段的包 ssh.message_code >= 50 && ssh.message_code <= 79 # 排除加密数据包,只看握手和认证 ssh && !ssh.encrypted_packet # 按 TCP 流跟踪某一次完整会话 tcp.stream eq 0这里要说明几个参数。ssh.message_code是 WireShark 解析出的 SSH 消息类型编号,20 是SSH_MSG_KEXINIT,30 是SSH_MSG_KEXDH_INIT,31 是SSH_MSG_KEXDH_REPLY。ssh.encrypted_packet是一个布尔字段,标记该包是否为加密载荷。tcp.stream eq 0里的 0 是流索引,你右键任意包选「Follow → TCP Stream」时 WireShark 会自动帮你填这个值。
提示:如果你的 WireShark 版本较老,
ssh.message_code可能不存在,改用ssh.protocol或直接tcp.port == 22也能定位,只是精度差一些。
2.3 抓包前的网卡与位置选择
这一步是很多新手翻车的地方。SSH 分析要求你抓到「完整的双向流量」,如果抓包点选错,你只能看到半个握手。常见做法有三种:
第一种,在客户端本机抓。适合分析「我连服务器时到底发了什么」,但看不到服务器侧的响应时序。第二种,在服务器侧抓。适合排查「为什么客户端连不上」,能看到 SYN 是否到达。第三种,在中间交换机做端口镜像。这是最完整的,但需要网络设备权限。
我一般做实验时选第一种,因为最省事。打开 WireShark,在网卡列表里选你实际走流量的那块(有线还是无线要看清),双击开始捕获,然后在终端执行ssh user@target。抓完后立刻停止,用tcp.port == 22过滤,再Follow TCP Stream看全貌。
3. 抓一次完整 SSH 登录:从 TCP 三次握手到认证结束
3.1 实验环境准备与最小复现步骤
要复现这个分析,你需要一台能 SSH 登录的目标机(虚拟机里的 Linux 就行),以及本机装好的 WireShark。步骤不复杂,但顺序要对:
第一步,确认目标机 SSH 服务在跑。在目标机执行systemctl status sshd,看到 active 即可。第二步,在本机打开 WireShark,选中正确的网卡,点开始捕获。第三步,新开一个终端,执行ssh 用户名@目标IP,正常输入密码完成一次登录。第四步,回到 WireShark 停止捕获,在过滤栏输入tcp.port == 22。
这时候你应该能看到类似这样的包序列:TCP 三次握手(SYN、SYN-ACK、ACK)→ SSH 协议版本交换(SSH-2.0-OpenSSH_x.x)→ 算法协商(KEXINIT 双向)→ 密钥交换(DH 或 ECDH)→ NEWKEYS → 认证请求与响应 → 加密会话数据。
3.2 逐包解读:版本交换与算法协商
先看版本交换。客户端和服务器各自发一个明文行,格式是SSH-2.0-软件版本。在 WireShark 里展开SSH Protocol → Protocol Version Exchange,你能看到Protocol Version: SSH-2.0-OpenSSH_8.9p1这样的字段。这个字段泄露了服务端软件版本,是安全评估里常被拿来说事的点——版本太老意味着可能有已知漏洞。
接着是 KEXINIT 包。这是双方各自发送的算法偏好列表,包含密钥交换算法、主机密钥算法、加密算法、MAC 算法、压缩算法五类。WireShark 会把它们解析成Key Exchange Algorithms、Host Key Algorithms等子树。你要重点看的是:双方最终协商出的是哪一套。协商规则是「客户端列表里排在前面的、且服务器也支持的」胜出。
# 在 WireShark 里定位协商结果的快捷方式 # 展开任意一个 KEXINIT 包,看 Algorithm Negotiation 子树 # 或者用过滤器直接跳到 NEWKEYS 包,它标志着协商完成 ssh.message_code == 21ssh.message_code == 21对应SSH_MSG_NEWKEYS,这个包一出现,说明密钥已经生成,后续所有报文都会加密。所以 NEWKEYS 是你分析的分水岭:它之前的包可以逐字段读,之后的包只能看长度和方向。
3.3 密钥交换与认证阶段的字段含义
密钥交换阶段,以最常见的diffie-hellman-group14-sha256为例,客户端发SSH_MSG_KEXDH_INIT,里面有一个大整数 e;服务器回SSH_MSG_KEXDH_REPLY,里面有服务器公钥、大整数 f、以及签名。WireShark 会把这些字段解析成DH Public Key、Host Key、Signature。你不需要手算 DH,但要能指出:e 和 f 是明文传输的,安全性依赖于离散对数难题,而不是「传了密钥」。
认证阶段,客户端发SSH_MSG_USERAUTH_REQUEST,里面包含用户名、认证方法(password 或 publickey)、以及对应的凭据。如果是 password 方法,密码是加密的,但用户名和方法名是明文。这就是为什么抓包能看出「谁在什么时候尝试登录」——元信息全暴露。
# 只看认证请求,快速统计登录尝试 ssh.message_code == 50 # 结合用户名过滤(如果你知道目标用户名) ssh.message_code == 50 && ssh.username == "root"ssh.username这个字段在 password 认证的请求包里是可读的。如果你在做安全审计,用这个过滤器能快速筛出针对特定账户的暴力尝试。注意,publickey 认证的请求包里用户名同样可读,但签名部分是加密的。
4. 避坑与排查:抓不到、解不开、看不懂的常见问题
4.1 抓到的包全是 Encrypted packet,看不到握手
现象:过滤tcp.port == 22后,所有包都显示Encrypted packet,没有任何SSH Protocol子树。
原因:你开始捕获的时机太晚,SSH 会话的握手阶段已经过去了。WireShark 只有在捕获到完整的密钥交换过程后,才能正确标记后续包为加密;如果中途开始抓,它连加密前的上下文都没有。
解决:先启动 WireShark 捕获,再发起 SSH 连接。顺序反了就得重来。另外确认你没有用-i指定错网卡,抓到了回环或无关接口。
4.2 过滤器写了 ssh 但一个包都不显示
现象:输入ssh过滤器后包列表空白,但tcp.port == 22有包。
原因:目标 SSH 服务可能跑在非 22 端口,或者 WireShark 的 SSH 解析器被禁用。非标准端口时,WireShark 不会自动把该 TCP 流识别为 SSH。
解决:先确认端口。如果是非 22 端口,用tcp.port == 你的端口过滤,然后右键任意包选Decode As → SSH,强制让 WireShark 按 SSH 解析。之后ssh过滤器就能用了。
4.3 看不到用户名或认证方法
现象:认证阶段的包展开后,SSH Protocol子树里没有User Name字段。
原因:你抓的是 publickey 认证,且 WireShark 版本对 publickey 请求的解析不完整;或者该会话使用了 keyboard-interactive 等不常见方法。
解决:换用 password 认证方式复现一次,ssh -o PreferredAuthentications=password user@host。password 请求包里的用户名字段解析最稳定。如果还是不行,检查 WireShark 版本,老版本对 SSH 扩展消息支持有限。
4.4 时间戳错乱导致包顺序看起来不对
现象:包列表里 NEWKEYS 出现在 KEXINIT 之前,或者 ACK 跑到 SYN 前面。
原因:多网卡抓包时,WireShark 用了不同网卡的时钟源,或者开启了「Update list of packets in real time」但系统负载高导致缓冲乱序。
解决:只选一块网卡抓。如果必须多网卡,抓完后用Edit → Preferences → Protocols → TCP → Relative sequence numbers关掉相对序号,并检查View → Time Display Format是否统一。实在乱序,用tcp.stream分组后按流单独看。
4.5 抓包文件太大,打开就卡死
现象:抓了十分钟,pcapng 文件几百 MB,WireShark 打开后无响应。
原因:没有设置捕获过滤器,把整块网卡的所有流量都录进去了。
解决:在捕获前设置 BPF 过滤器,只抓 SSH。在 WireShark 捕获界面的「Capture Filter」栏填tcp port 22,这样从源头就只录 SSH 流量。已经抓好的大文件,用tshark -r big.pcap -Y "tcp.port==22" -w ssh_only.pcap先裁剪再分析。
5. 进阶技巧:用 tshark 批量提取 SSH 会话元信息
图形界面适合单次分析,但如果你要处理几十个抓包文件、统计登录行为,tshark 才是效率工具。下面这条命令我从实验报告一直用到实际审计:
# 从 pcap 中提取所有 SSH 认证请求的用户名、方法、时间戳 tshark -r ssh_capture.pcap \ -Y "ssh.message_code == 50" \ -T fields \ -e frame.time \ -e ip.src \ -e ip.dst \ -e ssh.username \ -e ssh.auth_method \ -E separator=, \ -E header=y参数逐个说清楚。-r指定读取的抓包文件。-Y是显示过滤器,语法和 WireShark 图形界面完全一致。-T fields表示输出为字段模式,而不是默认的包摘要。-e每出现一次就指定一个要输出的字段,这里我选了时间、源 IP、目的 IP、用户名、认证方法。-E separator=,把字段分隔符设成逗号,方便导入表格。-E header=y让第一行输出字段名。
跑出来的结果可以直接贴进 Excel 或喂给脚本做进一步统计。比如你想知道哪个 IP 尝试登录最频繁,加一个sort | uniq -c | sort -rn就行。这个思路的价值在于:SSH 抓包分析不只是「看懂一个包」,而是能从流量里批量还原出「谁、什么时候、用什么方式、尝试登录了哪台机器」——这些元信息在安全事件排查里非常有用。
再补一个验证技巧。如果你想确认某次会话协商出的加密算法,不用逐包翻,直接用:
tshark -r ssh_capture.pcap \ -Y "ssh.message_code == 21" \ -T fields \ -e ip.src \ -e ssh.kex_algorithms \ -e ssh.encryption_algorithmsssh.message_code == 21是 NEWKEYS,但算法列表其实在 KEXINIT 里。更准确的做法是过滤ssh.message_code == 20,然后提取ssh.kex_algorithms和ssh.encryption_algorithms字段。这两个字段会输出协商后的算法名,比如curve25519-sha256和chacha20-poly1305@openssh.com。拿到这个结果,你就能判断这次连接用的是不是强算法。
我自己踩过的一个坑是:早期版本的 tshark 对ssh.auth_method字段支持不稳定,输出可能是空。遇到这种情况,退回到-e ssh.message_code先确认包被正确解析,再检查 tshark 版本。如果字段确实不支持,用-V输出完整解析树,再用 grep 捞关键字,虽然笨但一定能拿到数据。
做 SSH 协议分析这几年,我最大的习惯是:每次抓完包先不急着看内容,先用tshark -r xxx.pcap -Y "ssh" -T fields -e frame.number -e ssh.message_code把消息序列打出来,确认握手完整、认证可见,再决定要不要深入某个包。这个习惯帮我省掉了大量「打开图形界面翻半天发现抓错了」的时间。希望帮到你。
本文还有配套的精品资源,点击获取