如何使用Scapy从raw bytes中提取自定义Header?
·190 words·1 min·
0
·
0
·
Author
Ryan
Table of Contents
How to extract custom header from raw bytes using Scapy #
自定义协议 #
有些时候,需要构造一些自定义的协议以完成某些功能。但是这些协议不属于Scapy中已知协议的一部分,因此Scapy无法自动的将数据流中的raw bytes解析为已知的协议。因此,需要经过一些手动的步骤来完成解析。
构造自定义协议 #
Scapy中已经内置了一些常见的协议,可以非常方便的构造给予这些协议的包。
常用协议 #
例如,构造一个Ether+IP的包
import scapy.all as scapy
pkt = scapy.Ether(src="ff:ff:ff:ff:ff:ff",dst="ff:ff:ff:ff:ff:ff")/scapy.IP(src="127.0.0.1",dst="233.233.233.233")
pkt.show()
print(scapy.raw(pkt))
输出如下
###[ Ethernet ]###
dst = ff:ff:ff:ff:ff:ff
src = ff:ff:ff:ff:ff:ff
type = IPv4
###[ IP ]###
version = 4
ihl = None
tos = 0x0
len = None
id = 1
flags =
frag = 0
ttl = 64
proto = ip
chksum = None
src = 127.0.0.1
dst = 233.233.233.233
\options \
b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x08\x00E\x00\x00\x14\x00\x01\x00\x00@\x00(\x15\x7f\x00\x00\x01\xe9\xe9\xe9\xe9'
可以看到,直接指定layer的名字即可构造一层。其中layer的内容有默认值,也可以如上所示在构造的时候指定某些字段的值。
构造协议 #
在Scapy中,如果要构造一个layer,只需要一个新的类继承Packet即可,并制定新的layer有哪些字段。
class MyLayer(scapy.Packet):
name = "my layer"
fields_desc=[
scapy.BitField("first",0,size=4),
scapy.XBitField("second",0,size=4)
]
可以看到,自定义的header中,有两个字段。一个是长4bit的字段,第二个也是长4bit的字段,不过用16进制的方式显示。
构造一个有自定义协议的包
pkt = scapy.Ether(src="ff:ff:ff:ff:ff:ff",dst="ff:ff:ff:ff:ff:ff")/MyLayer(first=6,second=0xf)
pkt.show()
print(scapy.raw(pkt))
###[ Ethernet ]###
dst = ff:ff:ff:ff:ff:ff
src = ff:ff:ff:ff:ff:ff
type = 0x9000
###[ my layer ]###
first = 6
second = 0xf
b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x90\x00o'
解析自定义协议 #
在Scapy中,使用sniff可以自动嗅探网卡,并将得到的数据包的数据给解析为对应的字段。不过本例中不使用该方式,而是将一个包转化为raw bytes,再将raw bytes转化为包。
pkt = scapy.Ether(src="ff:ff:ff:ff:ff:ff",dst="ff:ff:ff:ff:ff:ff")/MyLayer(first=6,second=0xf)
raw_bytes = scapy.raw(pkt)
new_pkt = scapy.Ether(raw_bytes)
new_pkt.show()
输出如下
###[ Ethernet ]###
dst = ff:ff:ff:ff:ff:ff
src = ff:ff:ff:ff:ff:ff
type = 0x9000
###[ Raw ]###
load = 'o'
可以看到,此时只能将raw bytes解析为Ethernet,无法继续解析。此时除了人Ethernet层以外的字节被当作了payload,但payload具体是什么还不知道,因此需要告诉scapy下一层是什么。
new_pkt.decode_payload_as(MyLayer)
new_pkt.show()
输出
###[ Ethernet ]###
dst = ff:ff:ff:ff:ff:ff
src = ff:ff:ff:ff:ff:ff
type = 0x9000
###[ my layer ]###
first = 6
second = 0xf
可以看到scapy正确的解析了MyLayer层,并得到了和构造包的时候相同的字段值。