利用OpCode绕过Python沙箱
字数 771 2025-08-25 22:58:20
Python沙箱逃逸:利用OpCode绕过限制
1. OpCode基础概念
OpCode(操作码)是Python源代码编译后的结果,Python虚拟机无法直接执行人类可读的源代码,而是需要先编译为OpCode序列。
1.1 查看函数OpCode
def a():
if 1 == 2:
print("flag{****}")
print("Opcode of a():", a.__code__.co_code.encode('hex'))
输出结果:
Opcode of a(): 6401006402006b020072140064030047486e000064000053
1.2 使用dis模块解析OpCode
import dis
dis.dis('6401006402006b020072140064030047486e000064000053'.decode('hex'))
解析结果:
0 LOAD_CONST 1 (1)
3 LOAD_CONST 2 (2)
6 COMPARE_OP 2 (==)
9 POP_JUMP_IF_FALSE 20
12 LOAD_CONST 3 (3)
15 LOAD_BUILD_CLASS
16 YIELD_FROM
17 JUMP_FORWARD 0 (to 20)
>> 20 LOAD_CONST 0 (0)
23 RETURN_VALUE
2. 常见字节码指令
| 变量 | 指令名 | 操作 |
|---|---|---|
| LOAD_GLOBAL | 读取全局变量 | |
| STORE_GLOBAL | 给全局变量赋值 | |
| LOAD_FAST | 读取局部变量 | |
| STORE_FAST | 给局部变量赋值 | |
| LOAD_CONST | 读取常量 | |
| POP_JUMP_IF_FALSE | 当条件为假的时候跳转 | |
| JUMP_FORWARD | 直接跳转 | |
| COMPARE_OP | 比较操作 |
3. 利用OpCode改变程序逻辑
3.1 方法一:直接读取常量
def a():
if 1 == 2:
print("flag{****}")
print(a.__code__.co_consts) # 输出所有常量
3.2 方法二:修改函数代码对象
CodeType构造函数:
def __init__(self, argcount, nlocals, stacksize, flags, code, consts, names, varnames, filename, name, firstlineno, lnotab, freevars=None, cellvars=None):
获取函数代码对象属性:
def a():
if 1 == 2:
print("flag{****}")
for name in dir(a.__code__):
print(name, getattr(a.__code__, name))
构造新代码对象:
def a():
if 1 == 2:
print("flag{****}")
# 构造目标代码的OpCode
newcode = type(a.__code__)
code = "6401006402006b030072140064030047486e000064000053".decode('hex')
code = newcode(0, 0, 2, 67, code, (None, 1, 2, 'flag{****}'), (), (), "xxx", "a", 1, "")
a.__code__ = code
a() # 输出flag
4. 闭包环境中的OpCode修改
def target(flag):
def printflag():
if flag == "":
print flag
return
printflag
flag = target("flag{")
del target
构造替代函数:
def target(flag):
def printflag():
if flag != "":
print flag
return
printflag
a = target("xxx")
import types
code = a.__code__.co_code.encode('hex')
print code
EXP:
newcode = type(flag.__code__)
code = "8800006401006b030072140088000047486e000064000053".decode('hex')
code = newcode(0, 0, 2, 19, code, (None, ''), (), (), "example2.py", "printflag", 2, "", ('flag',), ())
flag.__code__ = code
flag() # 输出flag
5. 防御措施
- 限制对
__code__属性的访问 - 禁止使用
types.CodeType或type(func.__code__) - 监控和限制字节码操作
- 使用更严格的沙箱环境如PyPy沙箱
6. 总结
通过修改Python函数的OpCode,攻击者可以绕过沙箱限制,改变程序执行逻辑。这种技术的关键在于理解Python字节码的结构和操作方式,以及如何通过修改代码对象来改变函数行为。防御此类攻击需要从多个层面进行防护,包括限制敏感属性访问和监控代码修改行为。