.pcap文件结构
.pcap文件是常用的数据报存储形式,不是简单的文本文件,是具有特定结构的二进制文件。
.pcap/.cap文件结构如下:
Pcap Header
文件头,具有24个字节,而文件头又分成7个部分。
字段 | 意义 |
---|---|
Magic(4字节) | 标记文件开始,并用以识别文件和字节顺序。若值为0xa1b2c3d4 ,表示大端存储模式,依序读取;若值为0xd4c3b2a1 ,表示小端存储模式,每个存储单元都是从低地址读取至高地址。现行的计算机设计以小端存储模式居多。 |
Major(2字节) | 当前文件的主要版本号,一般为0x0200 。 |
Minor(2字节) | 当前文件的次要版本号,一般为0x0400 。 |
ThisZone(4字节) | 当地标准时间,如果使用GMT(格林威治标准时间)则全为0;一般全为0。 |
SigFigs(4字节) | 时间戳经度,一般全为0。 |
SnapLen(4字节) | 最大存储长度,设置所抓取数据包的最大长度。如果所有数据包都需要抓取,将值设定为65535。 |
LinkType(4字节) | 链路类型。解析数据包首先需要判断其链路类型,一般值为1,即以太网。 |
常用的LinkType(链路类型)如下:
- 0: BSD loopback devices, except for later OpenBSD
- 1: Ethernet, and Linux loopback devices
- 6: 802.5 Token Ring
- 7: ARCnet
- 8: SLIP
- 9: PPP
- 10: FDDI
- 100: LLC/SNAP-encapsulated ATM
- 101: “raw IP”, with no link
- 102: BSD/OS SLIP
- 103: BSD/OS PPP
- 104: Cisco HDLC
- 105: 802.11
- 108: later OpenBSD loopback devices (with the AF_value in network byte order)
- 113: special Linux “cooked” capture
- 114: LocalTalk
Packet Header
数据包头,具有16个字节,每个数据包头后面都是真正的数据包。数据包头分为4个部分。
字段 | 意义 |
---|---|
Timestamp(4字节) | 时间戳高位,精确到秒(seconds),为Unix时间戳。捕获数据包的时间一般以该值为根据。 |
Timestamp(4字节) | 时间戳低位,可以精确到微秒(microseconds)。 |
Caplen(4字节) | 当前数据区的长度,即抓取数据帧的长度,由此可以得到下一数据帧的位置。 |
Len(4字节) | 离线数据长度,网路中实际的数据帧长度,一般不大于Caplen。多数情况下与Caplen值一致。 |
Packet Data
链路层中的数据帧,长度为在Packet Header中定义的Caplen,即.pcap文件并没有规定抓取的数据帧之间需要间隔字符串。数据帧部分的内容格式为标准的网络协议格式。
开始试验
以下操作基于文件aim.pcap,目标是提取其中的flag。
打印基本信息:
from scapy.all import *
if __name__ == '__main__':
pcap = rdpcap('./aim.pcap')
print(pcap)
可以看到结果<aim.pcap: TCP:1088 UDP:87 ICMP:0 Other:5>
。
打印pcap对象信息:
print(type(pcap))
可得pcap即为scapy库所定义的包列表。
对pcap迭代:
for item in pcap:
print(repr(item))
# 或者 print(item.show())
可以看到包信息:
信息筛查
提取HTTP项:
for item in pcap:
if('TCP' in item) and (item['TCP'].fields['dport']==80):
print(repr(item))
通过筛选打印出的包体信息,发现对flag的访问目标IP为192.168.0.123,所以再增加筛选条件:
for item in pcap:
if('TCP' in item) and (item['TCP'].fields['dport']==80) and (item['IP'].fields['dst']='192.168.0.123'):
print(repr(item))
至此得到所有关于访问flag的请求包信息(为GET类型)。
将响应信息也打印出来:
for item in pcap:
if ("TCP" in item) and ("IP" in item):
src = item['IP'].fields['src']
dst = item["IP"].fields['dst']
sport = item['TCP'].fields['sport']
dport = item['TCP'].fields['dport']
if (src=='192.168.0.123' and sport==80) or (dst=='192.168.0.123' and dport==80):
print(repr(item))
在这些信息中就能找到对flag文件成功访问的请求:
请求 | 响应 | 内容 |
---|---|---|
/ | 200 | Hello World |
/favicon.ico | 404 | |
/flag | 404 | |
/flag/5 | 200 | None |
/flag/2 | 200 | - |
/flag/1 | 200 | flag |
/flag/4 | 200 | ULRGB} |
/flag/3 | 200 | {YKLTG |
/flag/100 | 200 | None |
得出结果
按照数字顺序拼接,可以得到flag值,即flag-{YKLTGULRGB}。