SSTI(以Twig模板引擎为例)
一、模板注入与常见Web注入
就注入类型的漏洞来说,常见 Web 注入有:SQL 注入,XSS 注入,XPATH 注入,XML 注入,代码注入,命令注入等等。注入漏洞的实质是服务端接受了用户的输入,未过滤或过滤不严谨执行了拼接了用户输入的代码,因此造成了各类注入。下面这段代码足以说明这一点:
// SQL 注入
$query = "select * from sometable where id=".$_GET['id'];
mysql_query($query);
------------- 华丽的分割线 -------------
// 模版注入
$temp->render("Hello ".$_GET['username']);
而服务端模板注入和常见Web注入的成因一样,也是服务端接收了用户的输入,将其作为 Web 应用模板内容的一部分,在进行目标编译渲染的过程中,执行了用户插入的恶意内容,因而可能导致了敏感信息泄露、代码执行、GetShell 等问题。其影响范围主要取决于模版引擎的复杂性。
二、模板注入原理
模板注入涉及的是服务端Web应用使用模板引擎渲染用户请求的过程,这里我们使用 PHP 模版引擎 Twig 作为例子来说明模板注入产生的原理。考虑下面这段代码:
1 <?php
2 require_once '../Twig-1.35.3/lib/Twig/Autoloader.php';
3 Twig_Autoloader::register(true);
4 $twig = new Twig_Environment(new Twig_Loader_String());
5 $output = $twig->render("Hello {{name}}", array("name" => $_GET["name"])); // 将用户输入作为模版变量的值
6 echo $output;
使用 Twig 模版引擎渲染页面,其中模版含有 {{name}} 变量,其模版变量值来自于 GET 请求参数 $_GET["name"] 。显然这段代码并没有什么问题,即使你想通过 name 参数传递一段 JavaScript 代码给服务端进行渲染,也许你会认为这里可以进行 XSS,但是由于模版引擎一般都默认对渲染的变量值进行编码和转义,所以并不会造成跨站脚本攻击:

但是,如果渲染的模版内容受到用户的控制,情况就不一样了。修改代码为:
1 <?php
2 require_once '../Twig-1.35.3/lib/Twig/Autoloader.php';
3 Twig_Autoloader::register(true);
4 $twig = new Twig_Environment(new Twig_Loader_String());
5 $output = $twig->render("Hello {$_GET['name']}"); // 将用户输入作为模版内容的一部分
6 echo $output;
上面这段代码在构建模版时,拼接了用户输入作为模板的内容,现在如果再向服务端直接传递 JavaScript 代码,用户输入会原样输出,测试结果显而易见:

对比上面两种情况,简单的说服务端模板注入的形成终究还是因为服务端相信了用户的输入而造成的(Web安全真谛:永远不要相信用户的输入!)。当然了,第二种情况下,攻击者不仅仅能插入 JavaScript 脚本,还能针对模板框架进行进一步的攻击,此部分只说明原理,在后面会对攻击利用进行详细说明和演示。
三、模板注入检测
上面已经讲明了模板注入的形成原来,现在就来谈谈对其进行检测和扫描的方法。如果服务端将用户的输入作为了模板的一部分,那么在页面渲染时也必定会将用户输入的内容进行模版编译和解析最后输出。
借用本文第二部分所用到的代码:
1 <?php
2 require_once '../Twig-1.35.3/lib/Twig/Autoloader.php';
3 Twig_Autoloader::register(true);
4 $twig = new Twig_Environment(new Twig_Loader_String());
5 $output = $twig->render("Hello {$_GET['name']}"); // 将用户输入作为模版内容的一部分
6 echo $output;
在 Twig 模板引擎里,{{ var }} 除了可以输出传递的变量以外,还能执行一些基本的表达式然后将其结果作为该模板变量的值,例如这里用户输入 name={{2*10}} ,则在服务端拼接的模版内容为:
Hello {{2*10}}
Twig 模板引擎在编译模板的过程中会计算 {{2*10}} 中的表达式 2*10 ,会将其返回值 20 作为模板变量的值输出,如下图:

现在把测试的数据改变一下,插入一些正常字符和 Twig 模板引擎默认的注释符,构造 Payload 为:
IsVuln{# comment #}{{2*8}}OK
实际服务端要进行编译的模板就被构造为:
Hello IsVuln{# comment #}{{2*8}}OK
这里简单分析一下,由于 {# comment #} 作为 Twig 模板引擎的默认注释形式,所以在前端输出的时候并不会显示,而 {{2*8}} 作为模板变量最终会返回 16 作为其值进行显示,因此前端最终会返回内容 Hello IsVuln16OK ,如下图:

通过上面两个简单的示例,就能得到 SSTI 扫描检测的大致流程(这里以 Twig 为例):

同常规的 SQL 注入检测,XSS 检测一样,模板注入漏洞的检测也是向传递的参数中承载特定 Payload 并根据返回的内容来进行判断的。每一个模板引擎都有着自己的语法,Payload 的构造需要针对各类模板引擎制定其不同的扫描规则,就如同 SQL 注入中有着不同的数据库类型一样。
简单来说,就是更改请求参数使之承载含有模板引擎语法的 Payload,通过页面渲染返回的内容检测承载的 Payload 是否有得到编译解析,有解析则可以判定含有 Payload 对应模板引擎注入,否则不存在 SSTI。
四、小结
本文简单介绍服务端模版注入漏洞如常规 Web 注入漏洞之间的关系,分析了其产生的原理,并以 PHP 模板引擎 Twig 为例讲解了 SSTI 常规的扫描和检测方法。虽然说 SSTI 并不广泛存在,但如果开发人员滥用模板引擎,进行不安全的编码,这样 Web 应用就可能出现 SSTI,并且根据其模板引擎的复杂性和开发语言的特性,可能会造成非常严重的问题。
在后续的文章中会针对各语言流行的模板引擎做一个较为详细的研究和分析,给出对应的可利用点和方法。
来自FreeBuf黑客与极客(FreeBuf.COM)
http://blog.knownsec.com/2015/11/server-side-template-injection-attack-analysis/
SSTI(以Twig模板引擎为例)的更多相关文章
- opencart 引入 TWIG 模板引擎
1.首先将 twig 包放入 system\library 目录. 2.在 system/startup.php 文件最后添加引入语句. require_once(DIR_SYSTEM . 'lib ...
- 构建自己的PHP框架(Twig模板引擎)
完整项目地址:https://github.com/Evai/Aier Twig 模板引擎 模版引擎 twig 的模板就是普通的文本文件,也不需要特别的扩展名,.html .htm .twig 都可以 ...
- 原生twig模板引擎详解(安装使用)
最近在学习SSTI(服务器模板注入),所以在此总结一下 0x00 Twig的介绍 什么是Twig? Twig是一款灵活.快速.安全的PHP模板引擎. Twig的特点? 快速:Twig将模板编译为纯粹的 ...
- yii2 使用twig 模板引擎
yii2 默认使用PHP 和html 混合的方式来写视图层,但我个人还是喜欢纯模板语言的方式.而且已经非常习惯使用twig的语法,最近想使用yii2进行开发,所以还是选择使用twig视图引擎. git ...
- twig 模板引擎使渲染视图更加优雅
在使用 laravel 的时候接触过 blade 模板引擎.在学习的时候,接触到了另外一个强大的模板引擎:twig 官网:https://twig.sensiolabs.org/ 中文手册:http: ...
- symfony2 twig模板引擎
1.基本语法 Says something:{{ }} Does something:{% %} Comment something:{# #} {% extends "App ...
- laravel Blade 模板引擎
与视图文件紧密关联的就是模板代码,我们在视图文件中通过模板代码和 HTML 代码结合实现视图的渲染.和很多其他后端语言不同,PHP 本身就可以当做模板语言来使用,但是这种方式有很多缺点,比如安全上的隐 ...
- 第115天:Ajax 中artTemplate模板引擎(一)
一.不分离与分离的比较 1.前后端不分离,以freemarker模板引擎为例,看一下不分离的前后端请求的流程是什么样的? 从上图可以看出,前后端开发人员的工作耦合主要在(3)Template的使用.后 ...
- thinkphp5.1 - twig模板-全局变量
thinkphp5.1 - twig模板-全局变量我们在定义 ccs 之类的静态文件的时候,经常会使用<link rel="stylesheet" href="__ ...
随机推荐
- mit6.830-lab2-常见算子和 volcano 执行模型
一.实验概览 github : https://github.com/CreatorsStack/CreatorDB 这个实验需要完成的内容有: 实现过滤.连接运算符,这些类都是继承与OpIterat ...
- 混沌映射初始化种群之Logistic映射
Logstic混沌映射初始化种群 Step 1: 随机生成一个\(d\)维向量\({X_0}\),向量的每个分量在0-1之间. Step 2: 利用Logistic映射生成N个向量.L ...
- ciscn_2019_s_3 一道收获很多的题(进步大只能说明基础差)
32位与64位 系统调用的区别: 1. 传参方式不同 2. 系统调用号 不同 3. 调用方式 不同 32位: 传参方式:首先将系统调用号 传入 eax,然后将参数 从左到右 依次存入 ebx,ecx, ...
- Table.RowCount行列计数…Count(Power Query 之 M 语言)
数据源: 任意五行两列 目标: 计算行数(包括空行) 操作过程: [转换]>[对行进行计数] M公式: = Table.RowCount( 表 ) 扩展: 对表中列进行计数:= Table.C ...
- 静态日志框架Extensioner.Logging
静态日志框架,输出文本文件,基于log4net扩展,轻量,方便,无侵入! 使用方法 执行Install-Package Extensioner.Logging -Version 2.0.0导入Nuge ...
- libevent源码学习(9):事件event
目录在event之前需要知道的event_baseevent结构体创建/注册一个event向event_base中添加一个event设置event的优先级激活一个event删除一个event获取指定e ...
- JAVA 接口返回JSON格式转换类
使用了Lombok插件 Result.java package com.utils; import com.jetsum.business.common.constant.Constant; impo ...
- JAVA携带参数(带有请求参数,请求头参数)直接发送POST请求
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpcl ...
- vue-组件化编程
1.传统编写方式和组件编写方式的区别 组件方式编写可以很方便的复用和封装某些功能模块/组件的命名最好语义化,方便维护和阅读 编写时,我们可以将某些共用的功能或者样式部分抽象,得到对应的组件,按需要引入 ...
- istio的sidecar原理学习
目的 从内嵌到应用的SDK模式转成istio servicemesh,再到最新提出来的proxyless可谓是发展太快了.刚开始我只是围绕着服务注册和发现是怎么转变来展开研究,但是发现这个话题有点大, ...