Pyjail沙箱逃逸总结
本文最后更新于 2026年10月4日 下午
在此之前接触过不少pyjail沙箱逃逸题目,玩法颇多,这里总结一下
Pyjail基础解法
最简单的Python沙箱
1 | |
把 __builtins__ 换成了一个白名单字典,没有所谓的危险方法。
pyjail的基础解法就是利用Python 里任何对象都能顺着类继承链爬到 object遍历所有子类,从而执行open、eval等危险函数。
基础payload
获取os模块
1 | |
恢复 __builtins__
1 | |
其中warnings.catch_warnings可以用codecs.IncrementalDecoder或者importlib._bootstrap._ModuleLock平替
读文件
如果环境里加载了 importlib 的引导类,它们的 __init__.__globals__ 里通常直接有 _io 模块,而 _io 里有 open:
1 | |
如果子类列表里有 FileLoader、SourceFileLoader 这类类,它们的全局变量里往往有 _io 或 _os,而且 SourceFileLoader 本身就有 get_data 方法,可以直接读文件:
1 | |
沙箱
审计钩子沙箱
审计钩子(Audit Hook)是 Python 3.8 引入的一项运行时安全机制(PEP 578),它允许你在解释器层面拦截几乎所有的敏感操作。和之前玩的“沙箱”不同,它不是靠过滤名字,而是在 C 语言层面直接监听事件。
1 | |
[SHCTF_3rd]Eazy_Pyrunner
通过任意文件读取漏洞我们可以读到源代码
1 | |
一个python执行沙盒,我们重点关注两部分
WAF:
1 | |
沙箱:
1 | |
python有一个特性,我们可以重新定义内置函数

这样我们就可以绕过审计钩子
1 | |
下面可以通过继承链获取os
1 | |
AST沙箱
AST 沙箱的核心思路是:在代码执行前,先把它解析成一棵抽象语法树(AST),然后检查树上是否存在危险的“节点类型”,如果不存在才放行执行。
简单沙箱过滤的是字符串(比如 "import"),而 AST 沙箱过滤的是语法结构。这带来一个关键优势:无论你怎么拼接字符串,最终生成代码的语法形态是固定的。
比如 __import__ 和 getattr(__builtins__, "__imp"+"ort__"),前者在 AST 里是一个 Name 节点,后者是一个 Call 节点。沙箱可以只禁止 ast.Call(函数调用),这样两者都会被拦截。
1 | |
[0xGame2026]漏风的沙箱
这题真的出的很好,教科书式的AST沙箱,比赛还未结束,我就先不放题解了。
绕过手法
unicode绕过
Python3开始支持非ASCII字符的标识符,也就是说,可以使用Unicode字符作为Python变量名,函数名等。python在解析代码时,可以使用Unicode Normalization From KC(NTKC)规范化算法,将一些视觉上相似的Unicode字符统一为一个标准化。
但是如果在正则检查之前进行了标准化转义操作就不能用Unicode绕过了
1 | |
[LitCTF2026]lit_pyjail_unicode
核心逻辑如下
1 | |
这里有两个关键点:
- 过滤器检查的是”原始源码字符串”。
- eval() 时把完整 builtins 暴露出来了。
也就是说,只要想办法在源码层面绕过正则,就还能调用内置函数。
1 | |
多行限制的绕过
exec —— 用字符串执行多行语句
eval 只能接表达式,import os 是语句。把语句写成字符串塞进 exec,exec 本身是函数调用(表达式),所以能被 eval 接受。
1 | |
- 关键:
\n换行符让exec执行多条语句 - 注意:
import("os")是错的,import不能当函数调;要导模块用__import__("os")
compile —— 编译成 code object 再执行
exec/eval 被禁时的替代。compile(source, filename, mode) 把字符串编译成代码对象,再用 eval 执行。
1 | |
mode='exec'允许语句块,;或\n分隔多条语句- 比
exec更底层,沙箱常漏掉
海象表达式 := —— 在单个表达式里串起赋值链
eval 只能吃表达式,普通 = 赋值不能出现在表达式里。海象 := 可以,于是能在表达式内部完成“导入 → 保存 → 调用”。
1 | |
- 执行顺序:先
a := __import__("os"),再b := a.system("id") - 外层
[...]只是构造列表,让两个海象都求值 - 需要 Python 3.8+
Typhon的使用
typhon是一个pyjail一把梭工具,可以极大程度辅助做题
[SHCTF_3rd]Eazy_Pyrunner
还是上面那题,上面已经讲了审计钩子怎么绕过,我们把禁用字符串放进typhon里面跑一下
1 | |
跑出的payload运行会报错
1 | |
我们发现会报错,原因是uuid需要os模块而它被污染,那么有没有办法恢复

os模块对象被污染所以无法重载

直接删除就行了,typhon有一个优点就是会展示每一步绕过的结果,我们顺着上去找一下

1 | |
这样就恢复os模块了,我们就可以直接顺势直接调用subprocess模块和getoutput
1 | |
写这篇文章的时候已经没有复现环境了,恢复os之后继续使用上面跑出来的payload应该也行吧🤔
[MiniVN]check_in
1 | |
typhon跑出来一个能打通但是没回显的payload,直接用这个输出的是0
1 | |
手动改改才能执行命令,但是不能有空格,没法直接读flag,读一下目录还可以
1 | |
改成open(‘flag’)读flag
1 | |
参考文献
Python沙箱逃逸(pyjail) - N1ngY - 博客园