简介:针对中职学校网络安全技能竞赛中的流量分析赛项,这份《B.pcap流量分析解析.docx》围绕B.pcapng数据包,提供了从环境说明到Flag提交的完整解题方案,适合网络安全、网络空间安全方向的学生备赛,以及数据流量分析、数据安全取证的入门者参考。内容以一问一答形式依次梳理数据库Flag末字符、扫描主机IP、服务器内核版本、扫描网段命令、一句话木马上传文件、服务器下载文件内容等6个关键考点,既给出判断依据,也附上具体Flag、解码方式与操作提示,并还原了渗透机场景下的分析思路,可直接对照实验复盘。资源包共1个docx文档,大小约3.27MB,页面结构紧凑,适合打印或在线查阅,也便于快速定位某一小题的答案。该资料已有744人学习,对备战中职技能大赛或开展网络安全流量分析基础训练具有较高实用价值。
1. B.pcap流量分析解析.docx:先把"还原文件"这个目标立住
拿到一个名叫B.pcap的抓包文件,任务却是"流量分析解析docx"——本质上不是找显眼字符串,而是把一个被拆散、编码、甚至截断过的docx从数据里还原出来。做过取证的人都知道,pcap流量分析第一步不是猜答案,而是先建立"文件在传输中会经过哪些转换"的假设:直接上传、分片重组、base64打包、加密压缩,每种方式在包里长相完全不同。这类任务适合三类人:打MISC方向想稳定拿分的选手;做数据泄露回溯、抓包还原文件的取证工程师;以及需要从车载诊断抓包里提取附件或配置文档的汽车电子测试人员。以B.pcap命名的流量分析样本在历年CTF里很常见,解法往往就是还原一个docx附件。接下来按实际干活顺序走,从体检统计到解压docx取出隐藏内容,命令都能直接抄。
2. 给B.pcap做体检:用capinfos和tshark先回答"流量里装了什么"
我拿到B.pcap后通常不会直接双击Wireshark。CTF里一个包只有几百帧,肉眼能扫完,但容易漏;企业取证里包动辄几百万帧,人眼更不现实。先跑一轮统计命令,两分钟就能判断这是哪类流量,再决定往哪个方向深挖。
2.1 用capinfos看文件类型和数据链路层
capinfos B.pcap这条命令输出的是B.pcap的元信息,重点看四项:文件类型(pcap还是pcapng)、数据链路类型、包数量和时间跨度。数据链路类型决定了后面能不能按IP过滤:Ethernet就是普通IP流量;Linux cooked(SLL)常见于tcpdump在无链路头环境下抓的包;如果是CAN,那这个包根本不是IP流量,得换一套工具链。
判断逻辑很简单:pcap和pcapng的封装差异对tshark影响不大,都能读;但链路类型直接影响协议解析。见过有人拿CAN的pcap在Wireshark里按ip.addr过滤半天,过滤结果永远是空的,最后才发现链路是CAN,白白浪费半小时。先看capinfos能省掉这类翻车。
2.2 用协议分层统计找"不该出现"的流量
tshark -r B.pcap -z io,phs -q-z io,phs打印协议分层统计(Protocol Hierarchy Statistics),每个协议占多少字节、多少包,一眼能看到大头在哪。-q是静默模式,只输出统计结果,不打印每个包。正常抓包里HTTP/DNS/ARP都有合理占比;如果看到一大堆归属为"Data"的包,或者某个高位TCP端口占了几十KB,说明这段流量里夹杂着未被解析的应用数据,十有八九就是被处理过的文件。
再补一个端点统计,确认对端和传输总量:
tshark -r B.pcap -z endpoints,tcp -q构造出来的B.pcap通常包数不多,这条命令的输出很短,谁是发送方一目了然。如果某个IP端口对上传了与docx体积相近的字节数,后面就在这条会话上做文章。
2.3 用显示过滤和Follow Stream把范围缩到一条流
统计完就有方向,接下来用tshark把可疑HTTP请求列出来:
tshark -r B.pcap -Y "http.request" -T fields -e http.host -e http.request.uri-Y是显示过滤,-T fields指定输出字段。如果B.pcap里有一段正常HTTP交互,这里会列出所有请求的host和uri,有文件名直接导出;没有HTTP,就把过滤条件换成别的协议(比如smb、ftp、dns),逐个排除。
找到TCP会话的线索后,用下面这条看流的原始内容:
tshark -r B.pcap -z follow,tcp,raw,0最后一个0是会话编号,从conv,tcp输出里读。这条命令会把整条TCP流的原始字节以十六进制转储打出来,前后有分隔线。注意:不要把分隔线一起存成文件,第5章会专门讲这个坑。这里先拿它确认流的开头是不是PK或其他文件头。
2.4 非IP流量别硬解:CAN报文的pcap要靠DBC/BLF/ODX那套工具链
链路层不是以太网的B.pcap在车载场景很常见。车厂测试时,CANoe或PCAN抓包默认输出blf、asc格式,有时为了统一分析会转成pcap。这种pcap里的帧没有IP头,Wireshark打开会看到一堆DLC、ID和0到8字节的payload,能用"Decode As"挂上can协议来解析。
但CAN要还原成"信号"就必须有DBC文件(CAN数据库),LIN总线对应ldf描述文件,AUTOSAR架构用arxml,诊断服务常用odx/pdx描述。没有这些描述文件,CAN报文只是一堆十六进制,等于黑匣子。判断方法如下:
capinfos B.pcap | grep -i "Data link type"输出中出现can、can_socketcore,或者链路类型是Linux cooked且包长很短(大部分是16字节左右),基本可以转向CAN方向,第4章会专门讲这个思路。
3. 把藏着的docx从B.pcap里抠出来:导出对象、追踪流与重组
流量分析做到这里,目标是明确的:把文件从包里拿出来。导出对象、追踪流、脚本重组,这三条路从快到慢,命中率从低到高,按顺序试。
3.1 先试HTTP导出对象:五秒钟能成,但别指望它是全部
Wireshark里有"文件→导出对象→HTTP",命令行等价于:
mkdir -p export tshark -r B.pcap --export-objects "http,export"--export-objects接受"协议,目录"格式,会把HTTP响应体里的可还原对象按文件名导出。这是拿到文件的第一个入口,但有三类情况它捞不到:文件不是走HTTP传的;文件名在HTTP头里被改写或乱码;文件被拆进多个请求分段上传。所以导出的对象如果打不开,或压根没有导出文件,正常,往下走。
3.2 追踪TCP流拿原始字节:别用"另存为",用字段导出
Follow TCP Stream在Wireshark图形界面是右键流,但我更推荐用tshark的字段导出来拿原始字节,因为界面里"Show and save data as Raw"保存出来的文件容易被编辑器换行污染。命令行下稳定做法是:
tshark -r B.pcap -Y "tcp.stream==0 && tcp.payload" -T fields -e tcp.payload \ | tr -d '\n' | xxd -r -p > out.bintcp.payload字段输出的是连续十六进制字符串,每个包一行;tr -d '\n'把所有行拼成一条,xxd -r -p把十六进制文本还原成二进制。这样拿到的out.bin和线上传输的字节一致,没有被Wireshark显示层加工过。
如果流的编号不是0,改成tcp.stream==5之类的条件即可。是不是需要先确认流编号?用tshark -r B.pcap -z conv,tcp -q看,哪条流的字节数最大就选哪条。
3.3 用Python+scapy把TCP分片拼成完整docx
B.pcap里的docx不一定是连续一整块。TCP分段、乱序、多次连接都可能导致直接导出的文件缺块或顺序错。用scapy按TCP流重组是最可控的方案:
from scapy.all import rdpcap, TCP, IP streams = {} for pkt in rdpcap("B.pcap"): if TCP in pkt and len(pkt[TCP].payload) > 0: key = (pkt[IP].src, pkt[TCP].sport, pkt[IP].dst, pkt[TCP].dport) streams.setdefault(key, bytearray()).extend(bytes(pkt[TCP].payload)) for key, data in streams.items(): if bytes(data[:2]) == b"PK": with open(f"out_{key[1]}_{key[3]}.bin", "wb") as f: f.write(bytes(data)) print(f"stream {key[1]}->{key[3]} len={len(data)} head={bytes(data[:16]).hex()}")这段代码按四元组(源IP、源端口、目的IP、目的端口)把每个方向的TCP载荷聚合成一个字节流。rdpcap是scapy的读包函数,TCP.payload取TCP层负载,len(pkt[TCP].payload) > 0跳过纯ACK包。聚合后如果前两个字节是PK,就认定是docx或zip类文件,按端口命名写出。这里没有处理seq乱序,假设pcap本身无乱序;如果打印长度比预期少,按5.2节用seq排序重拼。
3.4 编码层拆包:base64、十六进制和单字节异或的识别
聚合出来如果开头不是PK,而是大段字母或十六进制文本,说明文件在传输前被编码了。常见三种情况,先用文件头特征表快速定位:
| 文件类型 | 文件头(hex) | ASCII特征 |
|---|---|---|
| docx/xlsx/zip | 50 4B 03 04 | PK.. |
| doc旧格式 | D0 CF 11 E0 A1 B1 1A E1 | 乱码 |
| 25 50 44 46 2D | %PDF- | |
| png | 89 50 4E 47 0D 0A 1A 0A | .PNG... |
| gif | 47 49 46 38 39 61 | GIF89a |
base64的特征:除了大小写字母、数字、加号、斜杠,几乎没有别的字符,末尾常带等号,用base64 -d解码。十六进制文本的特征是只有0-9和a-f,数量是原始字节的两倍,用xxd -r -p还原。单字节异或表面看是乱码,但字符频率被整体偏移。试试对每字节做异或爆破,看能否还原出PK头:
def detect_xor_byte(data): for k in range(256): out = bytes(b ^ k for b in data[:64]) if out[:4] == b"PK\x03\x04": return k, bytes(b ^ k for b in data) return None这里data[:64]只取前64字节做试探,遍历0到255共256个密钥,每个密钥把数据逐字节异或,检查前4个字节是否等于PK\x03\x04。爆破成功就返回密钥和完整解密结果。多字节密钥(比如重复的异或口令)不能用这个,得用已知明文攻击或者求密钥长度,但单字节在MISC里出现频率很高,值得先试。
4. 解析还原docx:zip结构、文件头修复与信息提取
文件从流量里抠出来只是第一步。还原docx之后,里面可能藏着flag或敏感信息,位置和格式都要花时间确认。
4.1 docx的本质是zip压缩包,不是文档
拿到一个疑似docx的文件,先别急着用Office打开,用file和unzip验证:
file flag.docx unzip -l flag.docxfile输出会说明这是Zip archive data,后面跟着Microsoft Word版本信息;unzip列出压缩包里的目录,能看到word/document.xml、word/media等路径。这一步的意义是确认文件结构完整性。document.xml保存正文,media目录存放图片,embeddings目录存放嵌入对象,flag可能藏在任何一个位置,只看正文会漏。
4.2 flag在docx里的三种常见藏法
第一种是直接明文,最常见也最直白:
unzip -p flag.docx word/document.xml | grep -o "flag{[^}]*}"-p把指定文件内容输出到标准输出,grep匹配花括号内的flag字样。如果这里没有,看嵌入对象:
python3 -c "import zipfile; data=zipfile.ZipFile('flag.docx').read('word/embeddings/oleObject1.bin'); print(data[:64].hex())"嵌入对象可能是OLE文件或另一个压缩包,先看头部再决定怎么打开。第三种藏在超链接关系文件里,要查word/_rels/document.xml.rels里r:id指向的外部target或自定义URL。
4.3 文件头污染与坏zip修复:用Python把docx从流里"切"出来
流量里还原的文件经常多带几个字节,或者尾部被截断,直接unzip会报"BadZipFile"。常见的修复方式是找到第一个本地文件头PK\x03\x04切掉前面脏数据,再找EOCD标记截断尾部:
import zipfile, io def repair_zip(raw: bytes) -> zipfile.ZipFile: start = raw.find(b"PK\x03\x04") if start == -1: raise ValueError("no local file header") raw = raw[start:] eocd = raw.rfind(b"PK\x05\x06") if eocd == -1: return zipfile.ZipFile(io.BytesIO(raw)) eocd += 22 return zipfile.ZipFile(io.BytesIO(raw[:eocd])) raw = open("out.bin", "rb").read() zf = repair_zip(raw) print(zf.namelist())PK\x03\x04是zip本地文件头,PK\x05\x06是中央目录结尾标记(EOCD),EOCD固定22字节,后面可能带注释,所以从尾部用rfind找最靠后的那个作为结束点。正文里也可能出现伪造的PK\x03\x04,但这个函数只取第一个,足够应对流量提取场景。
4.4 当docx不是来自IP流量:从CAN报文的payload里重组文件
第2.4节提到的CAN场景,docx可能是通过诊断仪或测试设备把文件分片塞进CAN帧的data域。常规的追踪TCP流完全不适用,需要先用DBC把报文解析成带信号名的帧,再按业务ID重组:
import canmatrix db = canmatrix.formats.loadp("vehicle.dbc")[0] for frame_id, frame in db.frames.items(): for sig in frame.signals: print(sig.name, sig.start_bit, sig.size)canmatrix读取DBC后,每个frame里有signals,包含起始位和长度。如果抓包工具导出时顺便生成了blf或ldf描述,也可以用同样方式加载。没有DBC时,常见的做法是按CAN ID分组,把payload按时间戳顺序拼接,再拿前两个字节做序号校验。这种做法有点碰运气,但能在缺少描述文件时省下找资料的时间。
5. 避坑:流量还原docx的5个翻车现场与排查路径
流量还原看起来不复杂,但每一步都有经典的翻车点。以下五个问题我基本每轮分析都会遇到一两个,按"现象→原因→解决"写清楚。
5.1 Wireshark"另存为"得到的文件头多了0D 0A
现象:从Follow TCP Stream的Raw模式保存成文件,打开报格式错误,file一看是ASCII text,开头是PK但中间夹杂大量点号和回车换行。
原因:Wireshark显示区的复制和保存会把换行转成CRLF,有些版本还会把不可见字节显示成点号,保存时没有还原成原始字节。血泪经验:不要从显示窗口复制,用命令行导出字段。
解决:回到3.2节的字段导出方式,用-T fields -e tcp.payload拿原始十六进制再xxd还原。如果B.pcap已经关闭,重新打开再跑一次tshark即可,不用回到Wireshark界面。
5.2 按四元组拼接后文件只有一半
现象:Python脚本拼接出来的文件能打开但内容少,或者到中间变成乱码。
原因:直接extend(bytes(pkt[TCP].payload))忽略了TCP的seq序号。如果pcap里有乱序或重传,按抓包顺序拼接会把一段数据放到错误位置,文件后半段自然对不上。
解决:按seq排序后拼接:
segments = sorted(raw_packets, key=lambda p: p[TCP].seq) data = b"".join(bytes(p[TCP].payload) for p in segments)TCP的seq表示字节流起始位置,按seq排序等于在应用层重组。如果存在重传,同一个seq会出现两次,需要先用dict按seq去重,保留第一次完整收到的那个分片。
5.3 找到一个PK却找不到完整docx
现象:数据里能搜到PK\x03\x04,但解压报错说中央目录定位失败,或者整段数据长度和docx体积差很远。
原因:docx可能是先压缩再base64,PK头在编码后不连续;或者文件被分成多个TCP流、多个协议报文传输,只抓了其中一条流。
解决:先用grep -c "PK"统计PK头出现次数,如果文件本身是完整zip,PK头只会在文件开头出现一次。多条流的情况,把会话列表里所有TCP流都跑一遍3.3节的脚本,按时间戳把所有含PK的流合并。如果PK前后夹着base64字符,先还原编码再找文件头。
5.4 解压报"BadZipFile: File is not a zip file"
现象:file命令已经识别出Zip archive data,但zipfile或unzip打开报错。
原因:File的前面多出几个脏字节,或者EOCD之后的注释被截断。另一种情况是zip头部被恶意改过,比如把PK\x03\x04替换成别的字节,这在流量里可能是传输损坏不是人为。
解决:用4.3节的repair_zip切头,先找第一个PK\x03\x04,再从尾部rfind PK\x05\x06截断。如果头部被改,用单字节异或爆破脚本扫一遍,看能不能还原出PK。修复后再用unzip -t验证完整性,不要急着打开文档。
5.5 解出来的文本全是乱码
现象:docx能正常打开,但grep不到flag,正文在文本编辑器里是乱码。
原因:提取字节流时,源流量可能是UTF-16编码的docx内容;或者编辑器默认用GBK解码UTF-8文本,中文显示成乱码。判断编码不能靠猜,要用工具看。
解决:
file -i extracted.txt iconv -f UTF-16LE -t UTF-8 extracted.txt -o clean.txtfile -i会输出charset信息,FF FE开头是UTF-16 LE,FE FF开头是UTF-16 BE。如果xml里声明了gb2312,用iconv -f GB18030 -t UTF-8转换。处理完再grep,flag往往就藏在转码后的文本里。
6. 把提取过程固化成一个可复验的流水线
每次拿到新的pcap都从头点Wireshark太慢了,我习惯把前面几步固化成脚本,先全量扫描再人工确认。这里给一个最简版本,循环处理多条TCP流:
for i in $(seq 0 20); do tshark -r B.pcap -Y "tcp.stream==$i && tcp.payload" \ -T fields -e tcp.payload 2>/dev/null \ | tr -d '\n' | xxd -r -p > stream_$i.bin file stream_$i.bin | grep -qE "Zip|Microsoft Word" && echo "hit: stream $i" done循环范围可以放宽到50,流编号从0开始连续计数,超出实际流数时tshark输出为空,生成的stream_x.bin是空文件,不影响结果。脚本的重点是先用file过滤掉无关流,再对有命中的流做人工分析。验证一个文件是否还原成功,我一般固定跑三条命令:
file out.bin unzip -t out.bin unzip -p out.bin word/document.xml | grep -o "flag{[^}]*}"只有unzip -t输出"No errors detected"我才认为这个文件是可用的。有一次分析只盯着第一条TCP流,结果真正的docx藏在第7条流里,从那以后我再也不跳过全量扫描这一步,每还原出一个文件都先验证再继续。流量还原这件事,慢工出细活,希望帮到你。
本文还有配套的精品资源,点击获取