资讯详情

资讯详情

流量包分析必备:5种隐藏信息提取技巧与Python脚本实战

前阵子带着一批入门MISC的选手刷题我发现一个特别有意思的现象流量包分析在很多人眼里是最“劝退”的题型——一个几十MB的pcap文件扔过来Wireshark打开满屏都是包根本不知道从哪起手。但刷到后面大家都会认同一个结论流量包题目难不在技术而在“信息定位”。出题人把flag藏来藏去无非是那么几个地方你只要掌握对应的提取思路再配合Python脚本去做重复劳动效率和正确率都能上来一大截。这篇文章我把最近实战中总结的5种隐藏技巧完整拆开来讲从HTTP响应里的图片尾巴到DNS请求里的一串可疑字符再到TCP流中手捡文件头每一个都会给出可以直接复用的Python脚本。适合正在准备CTF比赛、想进阶MISC方向的选手也适合做流量分析但想提升效率的安全工程师。文章里所有脚本都是我在实际刷题环境里剪出来改过的能跑、能改照着抄基本就能应对大半流量包题目。1. 先摸清流量包里藏信息的三种路子流量分析题能玩的点其实绕不开三类信息载体。先把这三类搞清楚做题的时候就有了地图看到一个pcap不会两眼一抹黑。1.1 文件对象、协议元数据、载荷暗语这三类信息载体第一类是文件对象。HTTP协议在传输过程中最常见的载荷就是文件——图片、压缩包、PDF、甚至直接就是一段exe。这些文件通过HTTP响应体传过来肉眼在Wireshark里看不到完整结构但用工具提取出来后可以做文件层面的隐写分析。很多题目的flag不是直接写在包里的而是藏在某个被传输的图片的LSB位里或者附加在文件尾部。所以看到HTTP上传下载的痕迹第一反应就是“把文件捞出来”。第二类是协议元数据。不需要看载荷内容光看协议字段本身就能藏信息。最典型的就是DNS查询里的子域名出题人把编码后的flag拆成一段段子域名字符串塞进DNS请求里还有HTTP的头部字段、TCP的序列号、TLS握手的SNI字段都有被改写的可能。这类信息的特征是“藏得浅但隐蔽”因为一般分析者懒得逐条看协议字段。第三类是载荷暗语。TCP或UDP的payload可能是一整段经过编码的字符串比如base64、十六进制或者直接就是一段加密后的密文需要先解码、再解密、再分析。有些题目甚至直接把压缩包拆成多个切片分散在多个包里需要按序拼回去。这一类最考验解码和恢复能力也是脚本发挥最大价值的地方。1.2 为什么用 Python Scapy而不是纯 WiresharkWireshark当然适合做人工逻辑分析它的图形界面、过滤器、Follow TCP Stream都是神器。但它有两个痛点一是大pcap文件手动点着找太慢二是重复性的提取操作每次都重新点一遍就很折磨。所以我一般的主流程是用Wireshark做第一轮“人眼侦查”确认可疑方向后再用Python的Scapy或者dpkt库做第二轮批量挖掘。Scapy的rdpcap能把整个pcap读成包列表每个包都能按层去索引比如pkt[TCP].payload直接拿TCP载荷配合pkt[IP].src、pkt[DNS].qd.qname这些字段就能快速过滤。如果你更喜欢命令行的方式tshark做文本导出也很顺手但遇到复杂的解码、重组逻辑最终还是Python顺手。关于工具链建议安装Scapy、PillowPIL、pyzipper这三个库就够了后面脚本都基于它们。解析大部分pcap和图片隐写操作都不用额外再装什么重型依赖。2. 从流量包抠flag的5种隐藏技巧这五种技巧是我从一类类题目里筛出来的基本是流量包MISC题里出现频率最高的五种藏法。每一种我都会讲清楚“藏在哪里”、“怎么发现”、“怎么提取”有基础的朋友可以直接跳到对应小节看脚本思路。2.1 技巧一HTTP响应里的文件先提取再检查图片尾巴和LSB这种题目的pcap里会有一个明显的HTTP GET请求请求某个图片或者压缩包响应体里就是这个文件。难点从来不在“拿到文件”而在于“拿到文件之后做什么”。我的标准流程是这样的先用tshark把HTTP响应里的文件数据导出来或者用Python脚本遍历HTTP层抓http.file_data字段。拿到文件后先用file命令看真实类型用binwalk扫一遍有没有附加数据再用strings拽一遍看有没有明文字符串。如果这三步都没有结果就要对图片本身做隐写分析检查尾部是否被追加了数据处理LSB隐写留意EXIF信息或PNG的tEXt注释块。我实际遇到过一道题pcap里传输了一张PNG表面上看是一张普通的二维码。但binwalk显示文件尾部有额外数据把尾部的一段十六进制转ASCII后直接就是flag{...}。这种属于出题人给你送的温暖。更常见的是尾部没有额外数据但图片用StegSolve打开后在Red plane 0、Green plane 0通道能看到一行若隐若现的字符这就是LSB隐写。处理这类情况建议优先用zsteg工具一键检测比手动提取RGB值快得多。这个技巧的核心经验是不要在拿到文件的那一刻就以为题做完了文件本身就是分析对象。2.2 技巧二DNS查询子域名里的变形字符串DNS请求里藏数据在真实攻击中也存在攻击者会把窃取的数据拆成一段段字符串放在域名前缀里发出去绕过高延迟的HTTP通道。CTF题目里直接把这种思路改成了“把flag编码后藏在子域名里”。分析方法第一步是过滤出所有DNS查询请求也就是dns.qr 0的包。然后在Wireshark里看dns.qname字段如果你发现大量请求指向同一个根域名但每个请求的子域名部分是一串无意义字符基本就是中招了。这时候把子域名前缀全部拼接到一起再根据字符集形态选择解码方式。解码方式的选择是有门道的如果拼接后的字符串全是十六进制字符0-9和a-f第一优先尝试hex解码如果字符串长度是32的倍数、字符集包含大写字母A-Z和数字2-7那就是base32用Python的base64.b32decode直接解如果是大小写混合的base64要注意DNS解析会把域名统一转成小写所以原大写字母会被破坏这种情况下可以观察字符串是否包含/等base64特征字符如果包含就尝试手动补全大小写后再做base64解码。我遇到的一道练习题比较常规域名是example.com前缀是几段等长的字符串拼接后长度能被8整除通过base32解码直接拿到了flag。还有一道进阶题把flag分成了多段放到了多次DNS请求里顺序不是按时间排列的还需要根据请求序号或者子域名里的序号字段重新排序这个坑要在做题时特别注意。2.3 技巧三TCP流里手捡magic number提文件有些题目不走HTTP直接把一个文件拆成原始数据塞进TCP流里。这时候Wireshark的“Follow TCP Stream”虽然能看内容但文件是二进制的话界面里全是乱码得依赖脚本做自动提取。我从实战中总结出来一个很实用的搜索思路遍历pcap中所有TCP载荷然后用Python的bytes.find()在整段拼接后的流数据里搜索各种文件头特征也叫magic number。比如PK开头的是ZIP压缩包\x89PNG\r\n\x1a\n是PNG图片\xff\xd8\xff是JPEG%PDF是PDF文档7z\xbc\xaf\x27\x1c是7z压缩包。一旦命中就把从这个位置开始的文件数据切出来保存。但这个操作有个隐含的坑TCP是流协议同一个连接的数据包可能在传输过程中乱序还可能重传。如果直接按pcap里的包顺序拼接数据提取出来的文件大概率是坏的。正确做法是以四元组源IP、源端口、目的IP、目的端口为维度做流重组并且按TCP序列号排序后再拼。脚本里我会用字典按流存数据、再按seq排序这样提取出的文件才是完整的。如果提取出来的是加密ZIP就进入下一个常见的处理链路先用zipfile测试是否能直接解压如果不能去pcap里搜口令——这里就引出后面的技巧五了。2.4 技巧四两张图做像素运算还原flag流量里出现两张大小一致、肉眼看起来完全相同的图片这种题目的flag通常就藏在“两张图的差别”里。常见的操作包括异或、相减、叠加、灰度通道拆分等。原理其实很简单如果出题人把一张干净的图片跟一张写有flag的图片做了异或处理得到的结果就是一张充满噪点的“密图”。解题时把那两张原始图重新做异或噪点会抵消flag信息就浮现出来了。做题的人只需要把两张图逐像素取出RGB值按位置做异或运算再把结果写回一张新图片即可。我自己写脚本的时候优先用Pillow库通过Image.open()读取getdata()拿到全部像素再用生成器表达式做运算最后putdata()写回。这里必须注意两点一是图片尺寸必须一致否则逐像素运算会报错如果不一致可以先用resize()统一尺寸二是通道数要一致有些图是RGBA四通道直接跟RGB三通道做异或会出问题需要先转成RGBA或者RGB格式。还有一种变体题目是两张图中一张是原始图另一张是附加了flag的噪点图直接相减就能出结果。这时候可以把自己的运算函数参数化成op模式灵活选择XOR、SUB、ADD三种运算。2.5 技巧五加密压缩包的口令藏在会话或其他载荷里流量包题里提取出ZIP后往往发现它是加密的这时候如果直接上爆破效率低不说成功率也不高。出题人不可能弄一个高强度密码让你硬刚密码几乎一定藏在pcap的某个角落。我常用的检索方式是遍历所有包的payload把可打印字符串提取出来然后用正则搜索包含password、pass、key、口令、密码这些关键词的上下文。很多时候密码就在一段聊天流量里比如IRC消息、HTTP POST参数、或者某人通过FTP传的txt文件里。也有变态一点的题目密码被拆成几段分散在多个UDP包的载荷末尾需要先拼出来再用。判断加密方式是另一个关键细节传统ZipCrypto加密的ZIP标准库zipfile可以尝试用密码解压但如果ZIP使用的是AES加密特征是压缩包里有AES标志zipfile不支持需要改用pyzipper库。我第一次遇到AES加密ZIP时在zipfile上报RuntimeError: File is encrypted换到pyzipper后用同样密码秒解。还有一个实用信息有些加密ZIP会有一个明文“提示”文件比如注释里写了“密码是生日”那就要关注流量里的日期信息如果写了“密码是MAC地址”那就去看ARP或DHCP包里的MAC信息。出题人不会无缘无故写提示看到就直接去对应位置找。3. 能直接跑的Python脚本集这部分直接放代码。所有脚本我都拆成了独立函数你完全可以只拷贝自己需要的部分pcap路径改成自己的文件名就能跑。3.1 pcap读取与流重组框架读pcap最基础的就是rdpcap但大文件容易内存爆掉这时候建议用PcapReader做流式读取一个包一个包地处理既能控内存又能做流重组。下面这个函数会把整个pcap里的TCP载荷按四元组拆分、按序列号排序最终返回每个TCP流的完整字节流。from scapy.all import PcapReader, TCP, IP def reassemble_tcp_streams(pcap_path): streams {} with PcapReader(pcap_path) as packets: for pkt in packets: if not (pkt.haslayer(TCP) and pkt[TCP].payload): continue key ( pkt[IP].src, pkt[TCP].sport, pkt[IP].dst, pkt[TCP].dport ) streams.setdefault(key, []).append( (pkt[TCP].seq, bytes(pkt[TCP].payload)) ) for key, chunks in streams.items(): chunks.sort(keylambda x: x[0]) yield key, b.join(data for _, data in chunks)这个函数是用生成器的形式写好的遍历的时候直接for key, data in reassemble_tcp_streams(a.pcap):就可以。排序时注意只按seq排对于超大文件的乱序可能需要处理回绕但CTF题目一般不会考到那么深。3.2 从HTTP流自动提取文件HTTP下的提取我建议不要自己写HTTP解析器直接用Scapy的TCP载荷加简单的头部分割就够了。下面的脚本会识别HTTP响应体把文件数据抠出来并用HTTP头里的filename字段作为文件名保存到指定目录。import os, re from scapy.all import PcapReader, TCP, IP def extract_http_files(pcap_path, outdirfiles): os.makedirs(outdir, exist_okTrue) files {} with PcapReader(pcap_path) as packets: for pkt in packets: if not (pkt.haslayer(TCP) and pkt[TCP].payload): continue payload bytes(pkt[TCP].payload) # 只挑HTTP响应 if payload.startswith(bHTTP/) or bHTTP/1.1 200 in payload[:40]: headers, _, body payload.partition(b\r\n\r\n) if not body: continue fname_match re.search( rbfilename?([^;])?, headers ) if fname_match: fname fname_match.group(1).decode(errorsignore) files[fname] files.get(fname, b) body elif bContent-Type: image in headers: fname fimg_{len(files)}.dat files[fname] files.get(fname, b) body for name, data in files.items(): with open(os.path.join(outdir, name), wb) as f: f.write(data) return list(files.keys())这个脚本的局限是它假设一个包就是完整的HTTP响应体如果文件跨多个TCP包就要结合上面的流重组来做。稳妥一点是把所有HTTP响应流先重组再切分我一般习惯直接先跑流重组再对每个流用相同逻辑提取这样对大文件更保险。3.3 DNS可疑字符串解码器DNS解码脚本的核心只有两步收集所有查询域名然后剥掉根域名后缀。很多题目的根域名是固定的比如example.com所以我会把收集到的域名先按最后的两个标签去掉剩下前面的标签拼接成一个字符串再做hex、base32、base64三种尝试。import base64, binascii from scapy.all import PcapReader, DNS def collect_dns_queries(pcap_path, root_domainexample.com): labels [] with PcapReader(pcap_path) as packets: for pkt in packets: if pkt.haslayer(DNS) and pkt[DNS].qr 0: qname pkt[DNS].qd.qname.decode().rstrip(.) domain . root_domain if qname.endswith(domain): prefix qname[: -len(domain)].replace(., ) labels.append(prefix) return .join(labels) def try_decode(s): # 1. hex try: return fhex - {bytes.fromhex(s).decode(errorsignore)} except ValueError: pass # 2. base32 try: return fbase32 - {base64.b32decode(s.upper()).decode(errorsignore)} except Exception: pass # 3. base64 try: return fbase64 - {base64.b64decode(s * (-len(s) % 4)).decode(errorsignore)} except Exception: pass return no result s collect_dns_queries(dns.pcap) print(s) print(try_decode(s))如果DNS查询里有多个不同根域名就把root_domain参数改成一个不含的域名或者直接把整段域名拼接起来再试着解码。有一个容易被忽略的点DNS请求可能重复出现重试机制会产生相同的查询所以收集时用set去重最好。3.4 从TCP流提取magic bytes文件这个脚本重点展示如何搜索文件头。我定义了一组常见格式的magic bytes遍历之前生成的流数据用bytes.find定位文件头然后把文件头开始处的数据全部保存。如果文件长度未知就先把流尾部到文件头之间的数据都截出来再根据流结束位置判断文件是否完整。MAGIC { zip: bPK\x03\x04, zip_spanned: bPK\x07\x08, png: b\x89PNG\r\n\x1a\n, jpg: b\xff\xd8\xff, pdf: b%PDF, gz: b\x1f\x8b, 7z: b7z\xbc\xaf\x27\x1c, rar: bRar!\x1a\x07, } def extract_by_magic(data, outdirextracted): import os os.makedirs(outdir, exist_okTrue) result [] for name, magic in MAGIC.items(): pos data.find(magic) if pos ! -1: chunk data[pos:] path os.path.join(outdir, fstream_{name}_{len(result)}.bin) with open(path, wb) as f: f.write(chunk) result.append((name, path)) return result # 配合流重组函数使用 for key, stream_data in reassemble_tcp_streams(capture.pcap): found extract_by_magic(stream_data) for name, path in found: print(key, name, path)搜索出来的文件直接用file命令判断是否完整如果报“ truncated”就说明切割长度不对需要手动调整。有些图片文件后面还会跟着别的数据所以切的时候只取到magic number开始的区域即可后续内容可以在文件层面继续分析。3.5 像素运算还原图片最后这个函数用来做像素级运算。传入两张图片路径和一个运算模式返回运算结果图片。注意它会把两张图转换成同一个尺寸和模式再逐像素处理。from PIL import Image def pixel_merge(img1_path, img2_path, opxor, out_pathmerged.png): im1 Image.open(img1_path).convert(RGB) im2 Image.open(img2_path).convert(RGB) if im1.size ! im2.size: im2 im2.resize(im1.size) p1 im1.load() p2 im2.load() out Image.new(RGB, im1.size) po out.load() for y in range(im1.size[1]): for x in range(im1.size[0]): r1, g1, b1 p1[x, y] r2, g2, b2 p2[x, y] if op xor: po[x, y] (r1 ^ r2, g1 ^ g2, b1 ^ b2) elif op sub: po[x, y] (abs(r1 - r2), abs(g1 - g2), abs(b1 - b2)) elif op add: po[x, y] (min(r1 r2, 255), min(g1 g2, 255), min(b1 b2, 255)) else: raise ValueError(unknown op) out.save(out_path)跑起来可能有点慢图片如果太大的话可以先把尺寸压小一点或者用NumPy向量化运算加速。对于像素级隐写图片分辨率一般不会太高纯Python循环也够用。4. 常见问题与排查窍门实录流量包分析翻车最多的不是思路不对而是细节没处理好。我把刷题和带人过程中遇到的高频问题列出来按“现象、原因、解法”的方式整理成速查表方便你卡壳时快速对照。4.1 我会遇到的5个高频坑第一个坑是DNS域名大小写问题。DNS协议在传输过程中域名会被统一转成小写如果出题人用base64编码flag大小写字母一混合解码必挂。我现在的做法是优先试hex和base32因为这两种编码不依赖大小写混合能规避大部分协议干扰。第二个坑是TCP乱序。直接用pcap原始顺序拼文件经常会拼出损坏文件。不要偷懒一定要按序列号排序重组。我之前在某个数据包中直接提取ZIP解压时报BadZipFile最后发现是流重组没按seq排序片段倒序了。这个坑很多人都会踩。第三个坑是Scapy层解析问题。有时候pcap文件不是标准的以太网帧比如某些采集环境是Linux cooked captureSLL封装这时候包没有Ether层直接pkt[IP]会报错。我的建议是写解析脚本时先判断pkt.haslayer(IP)再做IP层访问不要假设一定有Ethernet。第四个坑是加密ZIP的AES误判。zipfile解不开加密包时不要直接认定密码错误。先看压缩包里的加密算法如果提示AE-x这类参数说明是AES加密必须用pyzipper或7-Zip命令行。我当时在某道题卡了半个多小时后来发现根本原因是用错了解压库。第五个坑是大pcap内存溢出。rdpcap把整个pcap读入内存如果文件快1GB机器就会卡死。优先用PcapReader迭代读取这样每条包只是临时占用内存。对刷题来说基本不会爆但处理真实流量样本时必须养成这个习惯。4.2 排查思路速查表现象可能原因解决思路提取的文件打开后报损坏TCP流未按序列号重组按四元组分组后按seq排序再拼接base64解码出来是乱码DNS域名被转小写先尝试hex、base32或手动恢复大小写zipfile解压报File is encryptedZipCrypto或AES加密用pyzipper或7z命令行确认密码两张图片像素运算报错尺寸或通道数不一致先resize、统一convert模式Scapy访问IP层报错pcap基于SLL封装用pkt.haslayer(IP)做保护或加载SLL层图片用StegSolve打开没东西隐写不在可见通道用zsteg自动扫描LSB检查图片尾部数据找不到任何文件头数据被编码后再传输先尝试对整个TCP流做base64/hex解码再搜索DNS子域名拼接后无法解码请求顺序错乱或重复用请求序号排序或者用set去重这个速查表是我实际使用频率最高的复盘清单刷题遇到卡壳时先查一遍比自己瞎试快得多。我在做流量包题目时最深的体会是耐心比技术重要脚本比肉眼可靠。很多隐藏信息用Wireshark手动翻也能看到但一个大pcap里可能混着几千个包手翻既慢又容易漏脚本跑一遍就不会漏。所以我现在处理流量包的基本套路都是先Wireshark快速定位可疑协议再用Python脚本做批量提取和重组最后对提取出的文件做隐写检查。这套流程帮我解决了不少难题也希望这篇内容能给你省下一些踩坑的时间。最后分享一个小经验刷流量分析题一定要养成积累脚本的习惯把HTTP提取、DNS解码、文件头搜索这些基础函数保存好下次套用就会很轻松。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →