在MVC的设计模式下,一般从 Model 层中读取数据,然后将数据传到 View 层渲染(渲染成 HTML 文件),而 View 层一般都会用到模板引擎。
模板引擎包含了各种参数,并能够由模板处理系统通过识别某些特定语法来替换这些参数的文档,用来生成输出文本(HTML网页,电子邮件,配置文件,源代码等)。
模板专注于如何展现数据,而在模板之外可以专注于要展示什么数据。模板引擎可以让网站程序实现界面与数据分离,业务代码与逻辑代码分离,这样提升了开发效率,良好的设计也使得代码重用变得更加容易。
模板引擎分为服务端和客户端:
1) 客户端模板引擎:主要结合js实现html,一种是常规字符串模板引擎,包括doT.js、dust.js、mustache.js;另一种是Dom模板引擎,包括vue.js、Angular.js、React.js等。
2) 服务端模板引擎:由各服务端语言生成html返回客户端,主要包括: PHP:Smarty、Twig;
Java:Freemarker、Velocity;
Python:Jinja2、Tornado、Marko;
Ruby:Slim、ERB;
NodeJS:Jade等
1)后端模板引擎
以JSP为例:
上方 <%%>内的是Java代码,为模板内容、<div></div> 是页面内容
当JSP在服务端运行被编译为Servlet Class后, <div></div> 被加引号成为字符串,输出字符串内容,需要在服务端运行。
2)前端模板引擎
前端模板引擎依赖客户端,在浏览器渲染页面,而不依赖于服务端。
任何一项新技术的引入同时也会带来新的攻击方式。除了常规的 XSS 外,注入到模板中的代码还有可能引发 RCE(远程代码执行)。通常来说,这类问题会在博客,CMS,wiki 中产生。虽然模板引擎本身会提供沙箱机制,但攻击者依然有许多手段绕过它。
看一个销售软件的例子,业务场景中要求发送大量的邮件给客户,并在每封邮件前插入问候语:
这段代码的功能是,通过Twig模板引擎可以把输入转换成特定的HTML文件或者email格式进行相应输出。
很明显我们会发现代码存在xss,但问题不止如此,如果我们输入custom_email={{7*7}},$output结果为49,这种探测方式和SQL注入也极为类似,原理也都是将未过滤的数据传给引擎解析。
对于模板注入漏洞的研究可以参考SQL注入,客户端的模板注入(CSTI)只能XSS,而服务端模板注入(SSTI)则可能造成XSS、LFI和任意代码执行。
漏洞发现及利用步骤分为:探测、判断、利用(读取、探索、攻击)
1、文本类型
大多数的模板都支持文本的输入和输出:
如:freemarker=Hello ${username},smarty=Hello {user.name}
探测方法有两种:
1)XSS语句弹框测试;
2)使用模板语法:如reemarker=Hello${7*7},输出为Hello 49
2、代码类型
用户输入也可以放在模板语句中,通常作为变量名称,
如:personal_greeting=username
这种情况下,XSS的方法就无效了。但是我们可以通过破坏 template 语句,并附加注入的HTML标签以确认漏洞,如:
personal_greeting=username<tag>
检测到模板注入后,我们需要判断具体的模板引擎。我们需要 fuzz 不同的字符,再通过返回的错误判断。当模板引擎屏蔽错误后,该类当法就失效了,并且暴力 fuzz对攻击自动化不友好:
根据不同模板引擎的特性,通过输入上述payload可以快速判断模板引擎,
这里的绿线表示结果成功返回,红线反之。有时同一个可执行的 payload 会在不同引擎中返回不同的结果,比方说{{7*'7'}}会在 Twig 中返回49,而在 Jinja2 中则是7777777。
和构造sql payload类似,对于模板注入的利用程度也取决于对于各个模板特性的了解,具体需要关注:
1) Template 使用手册,了解模板的基本语法
2) 内建方法,函数,变量,过滤器
3) 插件、扩展及沙箱机制
主要的payload集中在实现的攻击效果在:任意对象创建,任意文件读写,远程文件包含,信息泄露以及提权。
如:Jinja2:
Marko:
FreeMaker 是 Java 下最受欢迎的模板引擎,在查看文档时我们发现有两个已发布的可接受用户输入并执行命令的类实现TemplateModel:
<#assigntest="freemarker.template.utility.Execute"?new()>
<#assignob="freemarker.template.utility.ObjectConstructor"?new()>
以上的payload可以在创建模板时新建一个实例,后续调用会使得命令执行:
Velocity是另一种流行的Java模板语言,同样发现了两个可以利用的方法和属性:
$ class.inspect(类/对象/串) 返回一个检查指定类或对象的新ClassTool实例
$ class.type 返回正在检查的实际类
可以使用$ class.type 链接$ class.inspect以获取对任意对象的引用。然后使用Runtime.exec()在目标系统上执行任意shell命令:
Smarty 是一款 PHP 的模板语言。它使用安全模式来执行不信任的模板。它只运行 PHP 白名单里的函数,因此我们不能直接调用 system()。而文档表示可以通过 $smarty 来获取许多环境变量后面,我们又发现了 getStreamVariable,这个方法可以用来读取服务器读取+写入权限的任何文件:
1)任意读取文件
2)写文件创建后门:
Swig 和 Smarty 类似,不过我们不能用它调用静态方法。但它提供了 _self,提供了指向 Twig_Environment 的env 属性。Twig_Environment 其中的 setCache 方法则能改变 Twig 加载 PHP 文件的路径。这样就可以通过改变路径实现 RFI:
在 getFilter 里有危险函数 call_user_func。通过传递传递参数到该函数中,可以调用任意 PHP 函数,注册 exec 为 filter 的回调函数并调用造成命令执行:
Jade 是一款 Node.js 模板引擎,可以在Node.js等框架中使用,它有比较简单的语法和编写方式:
AngularJS是由Google编写的MVC客户端框架。使用Angular,通过view-source或包含'ng-app'的Burp看到的HTML页面实际上是模板,将由Angular呈现。这意味着如果用户输入直接嵌入到页面中,则应用程序可能容易受到客户端模板注入的攻击。即使用户输入是HTML编码的并且在属性内,也是如此。
AngularJS通过使用我们称为指令(directives)的结构,让浏览器能够识别新的HTML标签。AngularJS读取自定义的HTML,并将页面中的输入或输出与JavaScript变量表示的模型绑定起来。这些JavaScript变量的值可以手工设置的,或者从静态或动态JSON资源中获取,但只能进行XSS攻击。
Payload如下:
对于模板注入的黑盒测试,主要是探测程序所用模板类型,寻找输出点及攻击特性进行攻击;白盒测试需查看项目导入的第三方包,通过查找相关类进行跟踪,构造攻击向量。
对于不同的模板引擎,防御方案也不相同。但做好对用户输入的清理/过滤,将能大大的降低此类问题带来的安全威胁。另一个选择是创建一个安全加固/沙箱环境,禁用或删除潜在的危险指令。