
做抓包分析和漏洞排查这些年我越来越觉得TCP三次握手、四次挥手以及UDP的无连接特性不是面试题而是读包的基本功。很多人拿着Wireshark面对一堆报文不知道哪些是正常的、哪些是异常的就是因为脑子里没有一张“协议该长什么样”的底图。这篇文章就围绕TCP三次握手、四次挥手、UDP的区别结合我自己在漏洞抓包分析里遇到的实际场景把底层逻辑串一遍适合刚开始接触协议分析、或者被面试题背过但没真正理解状态流转的读者。1. 为什么抓包分析必须盯住“握手”和“挥手”这两个阶段1.1 把连接的一生看成状态机而不是一堆报文刚学网络时我也喜欢背“SYN、SYN-ACK、ACK”但真正做起抓包分析才发现三次握手的意义不在“三”而在“状态确认”。客户端发SYN是告诉服务端“我想建立连接我带的初始序号是x”服务端回SYN-ACK是告诉客户端“我收到了我的初始序号是y同时我希望你确认”客户端再回ACK是告诉服务端“我收到你的序号了我们进入数据传输阶段”。这三步缺一不可因为TCP是全双工的双方都要确认“你发出的包我能不能收到”。放到抓包分析里这意味着什么呢意味着你看到一对IP和端口之间有通信第一件事不是去看载荷内容而是先看这条连接是怎么建立的。我自己的经验是分析一个pcap文件时如果第一条报文不是SYN那说明这个抓包起点在连接建立之后前面的握手过程丢了如果看到SYN之后直接是RST而不是SYN-ACK那说明对端端口不可达或服务没起来如果看到三个以上的SYN重传且始终没有SYN-ACK那基本可以断定目标主机在线但端口被防火墙过滤或者根本没开这个服务。这些判断全部建立在“正常三次握手应该是什么样”这个底图之上。1.2 握手与挥手的“间隙”恰恰是异常藏身之处漏洞抓包分析和普通性能分析最大的区别在于普通分析关注“快不快”漏洞分析关注“像不像”。一个恶意程序完全可以让自己的网络行为看起来像正常访问但它很难伪装底层的状态机行为。举个我实际遇到的例子某次排查内网一台主机持续外连流量不大载荷也看不出明显特征。我把过滤器只保留TCP SYN包按目的IP一统计发现它每秒对几十个不同的高位端口发SYN但从不完成第三次握手。懂三次握手的人一眼就能判断这绝不是正常的应用访问而是典型的端口探测行为。如果不懂握手状态你可能会盯着载荷内容分析半天方向完全跑偏。同样四次挥手也藏着大量信息。一台正常的服务器关闭连接时走的是FIN、ACK、FIN、ACK的完整流程如果一台主机大量主动发RST而不走正常挥手流程那就很可能是程序异常崩溃、连接被中间设备重置或者有人在刻断链路。状态机行为就是协议层的“指纹”这是抓包分析里最值得花时间打牢的基础。2. TCP三次握手连接建立的封包细节与seq/ack推理2.1 从Wireshark视角看三次握手的完整序列先给一个最典型的握手序列我用自己抓包时最常见的相对序号来说明Wireshark默认显示相对序号方便人读第1包客户端 → 服务端SYNseq0第2包服务端 → 客户端SYN-ACKseq0ack1第3包客户端 → 服务端ACKseq1ack1注意看ack的推算逻辑第2包里ack1是“我期望你下一个包序号从1开始”也就是对第1包seq0的确认第3包里ack1是对第2包seq0的确认。TCP的确认号表示的是“期望收到的下一个序号”而不是“已经收到的最后一个序号”这个细节很容易记反但它对理解重传和丢包非常关键。实际抓包时有些场景会因为中间设备而让序号出现“偏移”。比如中间有个NAT或者负载均衡设备重写了TCP头客户端发出的seq可能是1000服务端看到的却是2000。这时候如果只看单包会觉得序号对不上但只要抓住“三包两确认”的状态逻辑就不会被表象带偏。排查问题时我习惯直接在Wireshark里输入过滤表达式tcp.flags.syn1 and tcp.flags.ack0只看纯SYNtcp.flags.syn1 and tcp.flags.ack1只看SYN-ACK然后按源地址统计一眼就能看出握手失败的范围。2.2 seq与ack为什么必须用数据包“推”出来而不是看数字本身初学者常犯一个毛病把seq和ack当成单纯的“包序号”用加减法硬套。实际上在Wireshark里看到连续的数据包seq不像0、1、2那样间隔均匀原因有几种数据负载如果数据包携带了长度为N的载荷下一个同方向包的seq会加上N。例如客户端发了一个seq1、载荷Len1400的包那下一个seq就应该是1401而不是2。TCP分段与重组大文件传输时TCP会把数据切成MSS大小的段每个分段的seq都不同。如果抓包点位于发送方或接收方之外还可能因为中间设备的TSO/GRO卸载产生巨型包导致观感上的“乱序”。重传如果某个包没收到ACK发送方会重传相同的seq。抓到两个相同seq的包不代表它们重复极有可能是网络丢包后触发的重传。我在做漏洞分析时最常用的是“沿同方向追踪seq差值”的方法。比如某个数据流疑似被篡改正常情况一个方向的序号是单调递增且等于上一次seq载荷长度如果你发现某个包的seq突然比预期的少或者多了一大截那就是有人在这个连接里注入了数据包或者中间设备改了载荷。2.3 握手阶段的异常行为每个都对应一种安全信号三次握手阶段常见的异常我已经在1.2里提了一部分这里补充几个实战中特别有代表性的SYN重传风暴客户端不断重传SYN服务端始终没有回应。除了端口真的没开还有一种可能是服务端半连接队列已经满了。半连接队列是内核里保存“握手未完成连接”的地方队列满了内核会丢弃新到的SYN。持续满意味着服务器可能正被连接洪泛。SYN-ACK重传服务端回了SYN-ACK但客户端一直不补最后的ACK。这种情况通常是客户端IP是伪造的SYN-ACK根本回不到真实来源接收方自然无法完成第三次握手。拔线式连接三次握手刚完成紧接着就发一个RST建立连接的表面过程完全正常但毫秒级就拆线。这种短命连接在漏洞利用里出现过——为了验证某个端口是否存活或者为了快速建立隧道而抢时间正常情况下几乎没有业务会这么干。安全信号的判断核心不是某一个包而是“时序形态”。单独一个SYN重传可能只是网络抖动但如果配合目的端口跨度大、源IP分散、持续时间短这些维度攻击行为的可信度就非常高了。3. 四次挥手与RST重置连接结束时那些容易被忽略的信号3.1 为什么正常关闭要“四”次而不是“两”次很多人对四次挥手的死记硬背是A发FINB回ACKB发FINA回ACK。但只记住四步不理解为什么需要四步在分析时会频繁踩坑。TCP是全双工的A发FIN只代表“A这边没有数据要发了”不代表B没有。B可能手里还有一大堆数据要发给A所以B先回ACK确认收到A的FIN然后继续把剩余数据发完最后再发自己的FIN。这两条独立的单向关闭过程合起来就是四次交互。如果恰好A在发送FIN之前已经收到了B的“数据send完成”信号场景里可能把中间两步合并成三次交互这在抓包里是正常现象不要以为是四次挥手缺失。抓包分析里遇到的最常见困惑是关连接时只看到一两个FIN包后续没有了。这往往是因为抓包点只覆盖了路径的一段。比如在客户端侧抓包看到客户端发了FIN、收到了ACK但B方向的FIN可能需要跨网段才到没有被抓到。遇到这种“残包”不要慌先把原始数据保存换个抓包点再验证而不是直接下结论。3.2 FIN是协商下线RST是异常失控FIN和RST虽然都能拆连接但性质完全不同。FIN是“打个招呼再走”RST是“直接撂电话”。这个区别放在漏洞分析里价值极高正常业务关闭连接几乎不会用RST。如果你在一个稳定的内网环境里看到某台服务端的连接大量以RST结束优先怀疑应用层崩溃、socket被异常关闭或者有中间安全设备做了丢包重置。端口扫描场景里扫描方收到目标主机的RST通常意味着“端口关着别费劲了”如果没收到RST也没收到SYN-ACK则是被防火墙静默丢弃。这个结论对判断目标主机是否在线、防火墙策略是否生效非常关键。某些恶意行为会主动发RST来“抢断”其他进程的TCP连接比如一些局域网工具实现“防蹭网”会伪造网关发RST给本机所有外部连接。如果你在抓包里发现大量来源不是真实对端IP的RST包就要警惕存在中间人干预。还有一个细节RST包本身是不需要确认的收到方收到后会丢弃这条连接的后续所有包。所以RST包具有“一次性摧毁连接”的破坏力在抓包里出现RST的时机越异常问题的优先级越高。3.3 TIME_WAIT与CLOSE_WAIT连接结束后仍会说话的状态连接从“四次挥手”状态到真正消失TCP协议栈里还有两个尾巴状态TIME_WAIT和CLOSE_WAIT。这两个状态在抓包层面很少直接显示但会强烈影响连接层的现象。CLOSE_WAIT被动关闭方通常是服务端收到了对方的FIN自己也回了ACK但应用层还没调用close()导致内核既不能发FIN也不能释放连接。大量连接堆积在CLOSE_WAIT说明服务端程序的连接管理有bug多半是忘记读数据或者忘记关闭socket。TIME_WAIT主动关闭方在发出最后一个ACK后进入的状态持续2个MSL最大报文段生存期时长。很多人不理解为什么要等这么久核心为了两个目的一是确保最后一个ACK能到达对端如果丢了还能重发二是让这条连接里的旧迟到包在网络中彻底消失避免它们影响下一个使用相同四元组的连接。在做高并发抓包分析时TIME_WAIT多不可怕CLOSE_WAIT多是问题。TIME_WAIT多说明主动关闭方在频繁地“正常关闭”连接完全可以依赖端口复用CLOSE_WAIT多才是排查的重点需要结合应用日志定位哪里没释放句柄。4. TCP与UDP的核心差异从状态机看待“可靠”与“无状态”4.1 TCP的可靠机制在抓包里都有具体的表现形态TCP是可靠传输协议这个“可靠”不是网络不会丢包而是TCP自己有一套机制来保证“丢了能发现、错了能纠正、快了能限速”。抓包分析里这些机制都会变成具体的报文形态确认与重传发送方发出一个包后会启动一个定时器如果超过RTO重传超时时间没收到ACK就重传。抓包里表现为相同seq的包出现了两次且第二次出现前没有对应的ACK。快速重传如果一个包丢了接收方后面收到的都是乱序包它会立刻发三个连续的重复ACK发送方收到三个重复ACK后不等定时器超时马上重传缺失包。这在抓包里表现非常明显三个相同的ackXXX后面紧跟着一个seqXXX的包。滑动窗口与拥塞控制TCP的窗口字段会动态变化。抓包里如果发现某段时间的接收窗口突然缩小到接近0说明接收方缓冲区已经满了应用层消费速度跟不上这时发送方会主动降低发送速率甚至停止发送。做好这些识别之后漏洞分析里很多“网络慢”的锅才能甩对地方。我遇到过好几次应用层报告“接口慢”结果抓包一看是接收窗口持续为零问题根本不在网络链路而在服务端应用没有及时读走数据。4.2 UDP没有“连接”但为了分析我们还是会给它造出“会话”UDP包头的字段比TCP少很多只有源端口、目的端口、长度、校验和。它没有SYN和FIN没有seq和ack没有窗口和状态。UDP一发就是纯粹的用户数据报文发送后既不知道对方收没收到也不会因为丢包而重传。所以在协议栈层面UDP是标准无连接协议。但到了抓包分析层面我们必须“牵强附会”地把它组织成会话Wireshark会按照“源IP源端口目的IP目的端口”的组合把UDP报文归组显示。很多安全工具也沿用“udp连接”这种说法其实只是一个方便分析的抽象内核里并没有UDP连接状态。搞懂这个区别对漏洞分析非常重要。比如DNS、TFTP、DHCP这些服务都用UDP你抓包时会发现客户端一个UDP请求发出去服务端回一个UDP响应整个过程只有两个包。少了握手环节就意味着一切都得靠应用自己防止伪造和重放。因此在分析基于UDP的协议时我习惯重点关注两个东西一是源端口和目的端口是否匹配业务约定二是载荷本身的格式是否完整。没有握手帮你过滤恶意流量UDP的安全边界全在应用层判断。4.3 TCP与UDP抓包行为对比表下面这张表是我在排查问题时经常对照的把两者的核心差异从抓包视角罗列出来对比维度TCPUDP连接状态有连接存在完整的建立/维护/拆除状态机无连接没有握手没有状态机报文头部开销头部至少20字节包含序号、确认号、窗口等字段头部仅8字节只有端口、长度、校验和可靠性提供确认、重传、排序、流量控制尽力而为不保证送达和顺序传输模式面向字节流报文之间无边界面向报文每个UDP包都带有明确边界抓包中识别方式关注SYN、SYN-ACK、ACK、FIN、RST、重传、窗口主要关注源/目的端口、长度、载荷格式典型应用HTTP、HTTPS、SSH、远程桌面、数据库连接DNS、DHCP、TFTP、RTP音视频、部分游戏同步安全弱项握手被滥用如半连接耗尽、序列号推测等无握手导致伪造容易需要应用层自建安全机制这张表每一条背后都有对应的抓包现象。比如一个流里如果出现大量重传你首先要检查这是不是TCP——如果对方用的UDP那就根本没有重传机制丢包会直接表现为应用层的间歇性卡顿这时候去责怪“UDP重传不满意”就属于问错人了。4.4 UDP与应用层可靠性的折中从QUIC看“伪连接”思想UDP的无连接特性带来一个直接的后果应用想用UDP就得自己解决可靠性和连接管理问题。以前我们习惯说“游戏用UDP因为快、可以容忍偶尔丢包”但现在是2020年代一个更典型的例子是QUIC协议。QUIC在UDP之上实现了类似TCP的连接建立、加密协商、可靠传输和拥塞控制底层却踩着UDP的报文格式。这意味着它既有UDP的灵活性又能在应用层完成连接建立、序号管理和重传。对抓包分析来说QUIC这类协议会给你制造一个错觉看起来是UDP端口但里面封装了一个“类TCP”的会话状态。我特意提这个是因为很多新人对“UDP无连接”死记硬背看到QUIC的UDP报文里有连接ID、有包序号就开始怀疑“UDP不是没有序号吗”——其实这些字段不在UDP头里而是QUIC自己定义的载荷格式。UDP头永远简单复杂的是应用层给它套的“马甲”。看清这一点你就不会在抓包分析时把传输层协议和应用层协议混为一谈。5. 漏洞抓包分析中的实战判读握手异常、UDP行为与检测思路5.1 SYN扫描与半开连接特征先看握手再看载荷在授权测试和应急排查场景里识别端口扫描是基本功。SYN扫描的核心特征就是只完成“半次握手”扫描方发出SYN收到SYN-ACK说明端口开放随后直接回RST拆掉连接不进行第三次ACK如果收到RST说明端口关闭如果一直没反应说明被防火墙静默。用Wireshark验证时我一般这样操作先用过滤表达式把纯SYN包提取出来tcp.flags.syn1 and tcp.flags.ack0观察源IP是不是同一个目的端口是否连续或分散SYN包之间的时间间隔是否均匀。如果目的端口从1到1024全部轮询了一遍且没有后续数据交互那几乎可以断定是扫描行为。注意我这里描述的是识别方法不是教你拿去扫别人的机器。协议分析能力是用来做防御和检测的任何未授权的探测行为都可能违反法律法规也只应该在自建靶场或明确授权的测试环境里进行。5.2 UDP端口探测靠“无响应”和ICMP响应反推端口状态UDP因为没有握手检测端口是否开放的方法和TCP完全不同。向一个UDP端口发送数据包时如果端口关闭目标主机会返回一个ICMP端口不可达Port Unreachable消息如果端口开放通常没有响应如果被防火墙丢弃没有响应也没有ICMP。所以在抓包里UDP端口探测的判断逻辑是“反证法”大量UDP报文飞向某个IP的不同端口同时伴随ICMP port unreachable回包说明对方活跃且端口没开如果UDP请求发出去完全静默则需要结合其他信息判断是防火墙丢弃还是端口开放。识别这种模式时要特别小心ICMP响应也有可能成为被利用的对象攻击者可以借生成ICMP流量造成中间设备压力。分析时必须同时关注ICMP的速率和来源。5.3 识别SYN FloodCONNECTION-SYN风暴的典型封包形态SYN Flood是典型的握手滥用攻击。正常情况下三次握手应该在极短时间内完成也就是“SYN → SYN-ACK → ACK”三连一发就完事。攻击场景下攻击者向着目标端口发送大量SYN但从不回应SYN-ACK目标主机的半连接队列最终被填满。在Wireshark里识别SYN Flood的方法非常直观过滤tcp.flags.syn1 and tcp.flags.ack0如果同一时间窗口内SYN包数量异常大且几乎没有任何关联的ACK包完成三次握手那就高度可疑。再利用统计功能按目的端口分组看看SYN是否集中在少数几个端口——通常攻击载荷会集中在服务端口比如80或443。防御思路上常见的是启用SYN Cookie、增大半连接队列、启用防火墙同步代理。这些内容很多这里不展开但理解攻击为什么有效才是调整防护参数的前提。5.4 协议状态机攻击与模糊测试的安全边界除了扫描、洪泛这些烂大街的攻击行为协议状态机本身也是漏洞研究的方向。比如TCP的序列号预测、窗口缩放因子的协商被滥用、同时打开场景的异常处理等都属于“协议实现bug”。这类研究我强烈建议在本地虚拟机环境或者专门的靶场平台里进行不要对公网主机做任何验证动作。我之前自己搭过一套实验环境用三台虚拟机模拟客户端、服务端和“观察者”跑通了三次握手、四次挥手、RST注入、UDP丢包等场景抓包效果非常直观。这个经验分享给卡在理论上的读者与其反复背状态转换图不如自己开两个端口用三方抓包看一眼真实报文。看到SYN-ACK里的ackseq1那一下比背十遍都记得牢。最后再补充一个自己用得很顺手的排查技巧分析大量会话时不要直接在主窗口里一条条翻先用Wireshark的统计功能按IP、端口、协议大类做聚合把“对话异常度”最高的几组拎出来再针对性地打过滤条件看明细。先看森林再看树木才能避免在十万个包里迷失方向。