
CTF流量分析题说难也难说简单也简单。我见过太多人一上来就双击打开pcap文件看到满屏五颜六色的包直接懵掉然后开始一个个点点了半天也不知道自己在找什么。实际上这类题目的规律性非常强出题人把flag塞进网络流量的位置就那么几种你只要掌握了对应的Wireshark分析技巧大多数题目都能在十分钟内解出来。这篇文章我挑了5个在CTF里出现频率特别高的流量分析技巧配合我实际打比赛遇到的案例来讲从最基础的HTTP流追踪到TLS解密、VoIP录音还原、USB键盘流量恢复每个都给出可直接复用的操作步骤。不管你是刚入门不知道怎么下手还是已经打过几场想体系化补短板这篇应该都能帮你省下不少试错时间。1. 先搞明白流量分析题在考什么1.1 出题人的视角flag藏在哪流量分析题属于杂项Misc或者取证Forensics方向出题人先构造一个场景——比如模拟某台服务器被入侵、某个人登录了某个网站、某个设备在通信——然后把flag“藏”在流量包的某个角落里。你需要做的是把包拆开、把会话拼起来、把数据还原出来。从出题人的角度flag的藏法无非这几种藏在HTTP请求的参数里藏在TCP流的内容里藏在FTP传的文件里藏在DNS查询里藏在VoIP通话录音里藏在USB键盘按键数据里藏在各种被加密的会话里。想清楚这个逻辑你就知道为什么要学那几个固定技巧了你要做的不是去阅读每一个包而是用正确的方式去“筛”和“还原”。1.2 必备工具和基础过滤器Wireshark本身是主力但实际解题过程中我经常配合tshark因为命令行在处理大流量包和批量提取时比GUI高效太多。还有一个容易被忽略的工具是binwalk用来分析从流量里导出的文件。另外Audacity必不可少处理音频题时全靠它。过滤器是Wireshark的灵魂先记下这五个高频过滤条件http tcp.port 80 tcp.stream eq 0 dns usb.transfer_type 0x02tcp.stream eq 0这种写法在追踪单个TCP连接时非常好用Follow TCP Stream只是图形化操作本质上就是在用这个过滤器。如果你看到某个响应是乱码不用慌多半是没做流重组或者显示格式不对后面会细说。2. 技巧一HTTP/HTTPS流量追踪与敏感信息提取2.1 三步拿到POST参数里的flagCTF里最直白的流量题就是HTTP题flag常常就藏在一个POST请求的表单参数里。用Wireshark打开pcap后你不需要翻包翻到头昏眼花直接三步走第一步在过滤栏输入http.request这会把所有HTTP请求过滤出来。第二步从请求列表里快速扫一眼找URL比较可疑的比如包含login、flag、upload、download这种关键词的。第三步右键目标请求选择“追踪流 → HTTP流”在弹出的窗口里直接看原始请求和响应内容。实际操作中你会发现POST请求的Body部分就包含了用户名、密码、甚至flag本身。但有个坑如果题目模拟的是真实网站登录请求体可能是URL编码的你看到的passwd%E6%82%AC%E5%BF%B5这种格式需要在快捷键CtrlShiftU或者手动解码才能看到明文。我遇到过一道题flag被分割成三段分别放在三个不同的POST请求里如果只追踪单个TCP流你会以为只找到一段这时候应该用http.request.method POST把所有POST请求拉出来再逐个追踪流把三段拼起来才是完整flag。2.2 TLS加密流量也能解会话密钥与key log文件现在越来越多的出题人喜欢考HTTPS流量因为裸HTTP太简单了。遇到这种情况最直接的方法是看题目附件里有没有提供key log文件或者环境变量SSLKEYLOGFILE生成的日志。如果有操作步骤如下打开Wireshark进入“编辑 → 首选项 → Protocols → TLS”在“(Pre)-Master-Secret log filename”里指定key log文件的路径点确定后Wireshark会自动解密所有TLS流量。解密完成后你可以看到HTTP明文请求也可以用tls.handshake.type 1过滤出ClientHello然后追踪流看完整内容。如果没有key log文件那这题大概率不是让你硬解TLS的而是考你从ClientHello里提取信息比如客户端使用的密码套件、SNI域名、证书指纹等。有一道经典题目是让你从ClientHello里提取SNI扩展里的域名拼接后就是flag。这时候在过滤器里输入tls.handshake.extensions_server_name就能把所有握手包里的服务器名称列出来。2.3 真实案例一个登录接口泄露的完整cookie链有一次模拟题流量包里全是HTTPS请求初看觉得无从下手。我翻了附件果然有一个keys.log文件在TLS设置里加载后所有流量瞬间变成明文。我先用http.request.method POST过滤发现有个请求专门向/api/login提交用户名参数。继续追踪该TCP流发现在登录成功后的响应包里服务端返回了Set-Cookie头其中包含sessionflag{...}。这个案例给了一个很重要的经验不要只盯着请求看响应的Header里经常有意外收获。尤其是Set-Cookie、Authorization、Location这些字段出题人很喜欢把flag伪装成会话标识或者重定向地址。3. 技巧二从“统计”入手定位恶意流量3.1 先看全局协议分层与端点统计有些流量包不是你想象的那么简单里面可能有成千上万个包有正常的DNS、ARP、内部聊天记录还有隐藏的恶意交互。如果你一上来就开始过滤很容易被正常的背景流量带偏。我的习惯是先看统计信息用“统计 → 协议分级”看协议分布。这一步能帮你快速判断包的类型如果ICMP包数量异常大说明可能存在ICMP隧道如果UDP包很多而你又没看见什么音视频应用可能要留心是否有人在用UDP传数据。再看“统计 → 端点”或“IPv4统计”重点关注哪些IP之间通信频率最高。CTF题目的出题人往往会模拟几台正常服务器和一个攻击者IP你一旦看到某个IP和众多内网地址都有大量TCP连接十有八九就是扫描或者攻击行为flag就藏在这些连接里。3.2 扫描行为识别SYN flood和ICMP探测识别扫描行为更多靠经验但有个很直观的技巧——用tcp.flags 0x002过滤出SYN包如果发现同一个源IP对大量不同目标端口发SYN且没有后续的SYN-ACK那基本可以断定是端口扫描。这时候题目很可能问“攻击者扫描了哪些端口”或者让你在扫描流量里找一段被编码的字符串。ICMP探测也有套路。正常ping包的内容是固定的但有些题目会用ping命令的-p参数构造数据把flag写到ICMP的payload里。这时用icmp过滤后逐条查看ping包的数据字段很可能在某个包的数据部分看到可识别的ASCII字符串。我还遇到过把flag拆成多段放在连续多个ICMP echo请求的数据区里如果你只看首尾两个包就会漏掉。3.3 案例找出payload中的命令注入一次比较有代表性的题目是模拟Web服务器被命令注入攻击流量包里有大量HTTP请求其中有一个请求参数看起来很不正常GET /ping?ip127.0.0.1;cat%20/flag我是先用http.request过滤再按时间排序找异常的GET请求。字符串里出现了分号和cat基本可以确定是命令注入攻击。随后追踪该TCP流在响应里能看到服务器返回了命令执行结果flag就藏在页面回显里。这个案例启发是很多流量分析题本质上是“在流量里考古”你不需要理解攻击原理的全部细节但至少要能识别出特征是命令、是SQL、还是文件读取。4. 技巧三VoIP通话录音还原4.1 流量特征和识别方法VoIP题在CTF里不算特别高频但一旦出现很多新人直接放弃因为看着一堆UDP包和SIP协议完全不知道在干嘛。其实识别方法很简单先用“统计 → 协议分级”看有没有SIP协议如果看到了基本就是VoIP题没跑了。这类题目的场景一般是模拟两个人在打电话flag就藏在通话录音里。还有一种间接识别方法流量包里包含大量RTP包媒体类型为音频。RTP包的特征是UDP端口通常为偶数且负载数据是变长的音频帧。如果你在“统计 → 端点”里看到两个IP之间有持续不断的UDP小包往来十有八九是音视频流。4.2 用Wireshark的Telephony菜单还原录音还原VoIP录音的操作Wireshark已经集成得非常傻瓜化了。菜单栏里选择“电话 → VoIP通话”会弹出一个会话列表里面会列出所有检测到的VoIP呼叫包括主叫方、被叫方、开始时间、持续时间。选中你要分析的对话点击“播放”按钮Wireshark的VoIP播放器会自动解析RTP流并调用系统播放器播放音频。如果点“播放”没声音或者播放器打不开就用备用方案进入“电话 → RTP → RTP流”从流列表里选中媒体流点击“分析”在弹窗里能找到“导出”或“另存为”把音频导出成.au或.raw文件。再用Audacity打开注意导入格式如果是raw需要手动选择编码为“Signed 16-bit PCM”采样率可以用8000HzVoIP最常见的G.711编码默认就是8kHz。4.3 听录音之外的思路波形和频谱大部分情况下你只要听完录音就能拿到flag录的内容通常是一串数字或英文口述出来。但真实比赛里我遇到过录音背景噪音很大人声听不清楚的情况。这时候不要反复播放浪费时间把音频丢进Audacity看波形和频谱图。喊数字的语音段在波形上会呈现出明显的间隔你可以一段一段标记出来如果flag是英文看频谱图里高频谐波的变化也能辅助辨认。还有一种极限情况flag不是用声音说的而是用DTMF双音多频信号拨出来的。这时Audacity的频谱分析就很关键不同的频率组合对应不同数字键你可以从频谱图里读出按键序列再把数字映射成ASCII或直接拼接成flag。这类题考察的就是你对音频处理工具的熟悉程度。5. 技巧四USB键盘流量还原5.1 USB pcap的特征USB流量是另一个高频考点。这类pcap文件里看起来全是USB协议的包不懂的人根本不知道从哪看起。最典型的出题方式是模拟一个USB键盘的按键记录你要从捕获的USB HID报文里还原出键盘敲了哪些键通常是一串字母数字拼出来就是flag。打开pcap后先看有没有usb字段。正常的键盘数据一般出现在URB Interrupt传输里也就是USB中断传输。可以用usb.transfer_type 0x02过滤出中断传输再用usb.direction 0x00过滤出主机接收到数据的方向对于键盘方向是从设备到主机。过滤之后你看到的每个包的数据区域就是一次按键事件。5.2 提取按键数据的两种方法推荐直接用tshark批量提取比在GUI里一个个看高效得多tshark -r usb.pcap -Y usb.transfer_type 0x02 usb.direction 0x00 -T fields -e usb.capdata输出的每行就是一个8字节的capdata例如02000e0000000000、0000040000000000这样。第一个字节是修饰键值比如0x02表示左Shift被按下0x20表示右Shift第三个字节是实际按键的HID键码0x04对应a0x05对应b以此类推。拿到数据后不要手动翻译写个简单的Python脚本解析最稳妥keys [0,0,0,0,0,0,0,0, , , a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z] for line in open(data.txt): data line.strip() if not data: continue cap data.split(:) modifier int(cap[0], 16) keycode int(cap[2], 16) if 4 keycode 29: ch keys[keycode] if modifier 0x02 or modifier 0x20: ch ch.upper() print(ch, end)注意一个关键坑同一个按键按下的瞬间capdata里可能只有键码但松开按键时数据变成了0000000000000000。如果你不过滤掉全零的数据行还原结果里会出现大量空字符。5.3 大小写映射和修饰键的坑大小写是我见过翻车最多的地方。很多新手只会读取键码不解析修饰键结果还原出一串全小写的字母拼出来的东西完全读不通。实际上出题人只要按住Shift再敲字母还原出来的就是大写。正确逻辑是先看capdata的第一个字节如果是02左Shift或者20右Shift后面紧跟着的字母就转成大写。还有一种情况是数字键上的符号。比如键码0x1E在无Shift时是数字1按下Shift后就是感叹号!这类符号映射表需要单独准备。所以写脚本时不要只处理字母把数字对应的符号也补全否则你会卡在最后一步。6. 技巧五导出对象与隐写信息提取6.1 导出HTTP对象一键还原服务器文件流量包里最常出现的可导出对象是HTTP传输的文件比如图片、压缩包、PHP文件、JS脚本。用“文件 → 导出对象 → HTTP”Wireshark会把所有HTTP响应体里传输的文件对象列出来按大小和类型排列。CTF里你经常会看到一个名为flag.zip或者image.jpg的对象直接选中导出就行。除了HTTPSMB协议和TFTP协议也支持导出。SMB协议题里可能出现共享文件TFTP题里可能传输了配置文件或固件。这些都在“文件 → 导出对象”的二级菜单里不要只盯着HTTP。命令行对应的操作是tshark -r traffic.pcap --export-objects http,output_dir6.2 从TCP流里直接拼出图片和压缩包如果导出对象里没看到可疑文件别急着放弃你要考虑flag可能不是“传输”过来的而是“拼接”出来的。我在比赛里遇到过这样一个套路流量包里每次响应只返回文件的一部分数据分布在不同的TCP段里需要你把所有TCP流的数据按顺序拼接后保存成图片才能看到flag。具体做法是选中涉及的目标TCP流进入“追踪流 → TCP流”把显示格式切换到“原始数据”然后点击“另存为”保存成二进制文件。保存后用binwalk检查文件类型如果检测出JPEG或PNG头说明拼接成功如果显示“数据无意义”可能是你保存的流不对或者需要把多个流的payload按时间顺序合并后再保存。6.3 延展伪加密压缩包的处理导出的压缩包有时会遇到伪加密的情况——打开zip时提示输入密码但实际上它根本没有加密只是加密标志位被篡改了。遇到这种情况不要花时间跑字典爆破先检查zip文件的加密标志。用十六进制编辑器打开zip文件找到50 4B 03 04本地文件头其后的第6、7字节是加密标志位。如果该值是09 00代表文件被标记为加密把它改成00 00后保存再打开zip就能直接解压出内容。为什么要在流量分析里提这个因为很多题目的流程就是从pcap中导出压缩包 → 解压出另一个文件 → 文件里才是真正的flag。伪加密卡住你十分钟完全没必要。7. 常见问题与排查技巧实录7.1 流量文件打不开、显示不全经常有人在群里问“为什么Wireshark打不开这个pcap文件”。最常见的原因是文件头损坏或者Wireshark版本太老不认识新格式。第一步先升级Wireshark大部分问题都能解决如果还是打不开用pcapfix这类工具修复文件头。还有一种特殊情况是文件后缀是.pcapng但编译器生成的其实是raw格式这时候可以尝试用“文件 → 导入十六进制转储”手动指定封装类型导入。另一个高频问题是“为什么Wireshark里一个TCP包只显示520字节怎么不显示整个2090字节的数据”。要区分两种情况如果是因为抓包时设置了捕获长度snaplen那超出的字节根本没被记录在文件里不存在你无论在Wireshark里怎么调都调不出来只能回源头重新抓包如果只是显示层被截断在“追踪TCP流”对话框里把“显示并保存数据为”改成“原始”再勾选“显示整个会话”通常就能看到完整的流内容。判断方式很简单看“帧”协议的“捕获长度”和“帧长度”是否一致如果不一致说明是抓包时截断了一致的话就说明是展示问题。7.2 筛选UDP前后两包的时间间隔关于“如何筛选UDP前后两包的时间间隔”首先明确Wireshark里有一个字段叫frame.time_delta_displayed表示当前包与上一个显示的包之间的时间差。你可以在显示列里右键表头选择“列首选项”添加一列字段填frame.time_delta_displayedWireshark就会为每个包显示跟前一个包的时间差。如果你想用过滤表达式筛选出“间隔大于某个秒数”的包直接写udp frame.time_delta_displayed 1这个过滤条件在排查慢速攻击、隐蔽信道时很实用。比如某道题故意把flag的字符放在间隔不等的UDP包中包内容本身是正常的随机数据但间隔时间编码了信息。这种题靠肉眼几乎不可能发现规律你需要先把frame.time_delta_displayed列导出来用脚本分析时间差再转成字符。7.3 常用过滤器速查表需求过滤表达式只看HTTP请求http.request只看POST请求http.request.method POST追踪指定TCP会话tcp.stream eq 5只看DNS查询dns只看TLS握手tls.handshake查找指定的IP通信ip.addr 192.168.1.10只看出站流量ip.src 192.168.1.10只看UDP载荷非空udp.length 0USB键盘数据usb.transfer_type 0x02 usb.direction 0x00时间间隔超过1秒frame.time_delta_displayed 18. 我的沉淀流量分析的学习路径建议这几种技巧并不需要一次性全部掌握你可以按优先级来先学会HTTP/TCP流追踪和导出对象这两项能解决大约一半的入门题再学统计视角看异常和VoIP还原覆盖剩下的大部分场景最后再啃USB键盘和TLS解密因为这两个相对少见且需要额外工具。平时怎么练除了刷题我更推荐自己构造流量。比如用虚拟机搭一个Web服务自己发几个带参数的请求通过浏览器访问触发各种HTTP行为再用Wireshark抓包尝试从结果里找到你刚才输入的测试字符串。这个过程比刷十道题都管用因为你同时站在了出题人和做题人两个视角对流量特征的理解会深很多。最后分享我自己的一个习惯拿到任何pcap文件我第一件事不是打开看包而是先用tshark -r file.pcap -z io,phs -q看一眼协议统计几秒钟就能知道这题大概考什么方向。方向对了解题就是顺水推舟的事。