前言
模板引擎
模板引擎(这里特指用于Web开发的模板引擎)是为了使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档,用于网站的模板引擎就会生成一个标准的HTML文档。
模板引擎会提供一套生成HTML
代码的程序,然后只需要获取用户的数据,然后放到渲染函数里,然后生成模板 用户数据的前端HTML
页面,然后反馈给浏览器,呈现在用户面前。
这是一个模板的例子:
代码语言:javascript复制<html>
<head>
<title>{{title}}</title>
</head>
<body>
<form method="{{method}}",action={{action}}>
<input type="text" name="user" value="{{username}}">
</form>
<p>
This page took {{microtime(true) - time}} seconds to render.
</p>
</body>
</html>
对应的后端代码逻辑是:
代码语言:javascript复制$templateEngine = new TemplateEngine();
$tpl = $templateEngine->loadFile(login.tpl);
$tpl->assign('title','Login');
$tpl->assign('method','post');
$tpl->assign('action','login.php');
$tpl->assign('username',getUserNameFromCookie());
$tpl->assign('time',microtime(true));
$tmp->show();
SSTI(服务器端模板注入)
SSTI
(Server-Side Template Injection)就是服务器端模板注入。
SSTI
的本质也是注入,
SQL注入
在本应该插入正常数据的地方插入了SQL
语句,破坏了原本的SQL
语句的格式,从而执行攻击者想要的SQL
语句。
注入就是格式化字符串漏洞的一种体现。
利用漏洞可以对服务端进行输入,服务端在接收用户的恶意输入以后,未经任何处理就将其作为 Web 应用模板内容的一部分,模板引擎在进行目标编译渲染的过程中,执行了用户插入的可以破坏模板的语句,因而可能导致了信息泄露
、代码执行
、GetShell
等问题。
各模板引擎的相关信息
SSTI模板注入基本原理
用户的输入作为模板变量
中的值
代码语言:javascript复制<?php
require_once(dirname(__FILE__).'/../lib/Twig/Autoloader.php');
Twig_Autoloader::register(true);
$twig = new Twig_Environment(new Twig_Loader_String());
$output = $twig->render("Hello {{name}}", array("name" =>$_GET["name"])); // 将用户输入作为模版变量的值
echo $output;
?>
对这段代码输入<script>alert(welcome)</script>
,不会执行脚本中的代码,会进行HTML
编码转义,以原样输出,不会造成XSS
攻击。
用户的输入作为模板内容
的一部分
代码语言:javascript复制<?php
require_once(dirname(__FILE__).'/../lib/Twig/Autoloader.php');
Twig_Autoloader::register(true);
$twig = new Twig_Environment(new Twig_Loader_String());
$output = $twig->render("Hello {$_GET['name']}"); // 将用户输入作为模版内容的一部分
echo $output;
?>
对这段代码模板输入<script>alert(welcome)</script>
,这段JavaScript
代码会作为模板内容的一部分并执行,会造成XSS
漏洞。
不同的模板有不同的语法,见本文各模板引擎相关信息
。
例题
题目基本信息
看题目名,可以知道是考察SSTI
相关知识。
解题步骤
查看网页的源代码
需要我们传入一个flag
参数。
同时可以看到这样一段注释:
代码语言:javascript复制<!-- You know, in the flask, We often set a secret_key variable.-->
可知,该网页使用的是Flask
框架,模板引擎使用的是Jingja2
。
在Flask
模板中,config
是Flask
模版中的一个全局对象,它包含了所有应用程序的配置值。会有一个SECRET_KEY
变量,根据这个提示,我们需要获取这个SECRET_KEY
。
接下来我们尝试用get
方式传入一段HTML
代码:
可以看到源码发生了改变,所以可以使用SSTI
进行攻击。
下面是Jinja2
的基础语法:
{% … %}
{{ … }}
{# … #}
要查看SECRET_KEY
,设置我们的payload为:
?flag = {{config.SECRET_KEY}}
使用get
方式传参得到flag。