在本节中,将讨论什么是服务器端模板注入,并概述利用服务器端模板注入漏洞的基本方法。另外还将提出一些方法,确保模板的使用不会暴露在服务器端模板注入中。
如何构建一个服务器端模板注入攻击?
识别服务器端模板注入漏洞并制作一个成功的攻击,通常包括以下过程:
检测(Detect)
服务器端模板注入漏洞常常被注意到,并不是因为它们很复杂,而是因为只有明确寻找它们的审计人员才能真正发现它们。
如果能够检测到存在漏洞,那么利用它就会非常容易,在没有沙箱的环境中尤其如此。
与任何漏洞一样,利用漏洞的第一步是发现漏洞。也许最简答的初始方法是通过注入一连串模板表达式中常用的特殊字符来模糊模板,例如${{<%[%'"}%,如果出现异常,则表明注入的模板语法可能正在被服务器以某种方式解释,这是服务器端末班住漏洞可能存在的一个迹象。
服务器端模板注入漏洞发生两个不同的上下文中,每个上下文都需要自己的检测方法。
无论模糊化尝试的结果如何,也还要尝试以下特定于上下文的方法。因为如果模糊化没有结论,使用这些方法中的一种,漏洞仍然可能暴露出来。
即使模糊测试表明存在模板注入漏洞,仍然需要确定它的上下文,以便利用它。
纯文本环境
大多数模板语言允许自由地输入内容,可以直接使用HTML标签,也可以使用模板的本地语法,在HTTP响应发送之前,这些内容会在后端被渲染成HTML。
例如,在Freemaker中,render("Hello"+username)将会呈现Hello Carlos这样的内容。
这有时会被XSS利用,事实上经常被误认为是一种简单的XSS漏洞。然后,通过将数学运算设置为参数值,我们可以测试这是否也是服务器端模板注入攻击的潜在入口。
例如,考虑一个包含以下漏洞代码的模板:
render('Hello ' + username)
在审计过程中,我们可能会通过请求一个URL来测试服务器端的模板注入,如:
http://vulnerable-website.com/?username=${7*7}
如果结果输出包含Hello 49,这表明数学运算在服务器端被求值,这是一个很好的服务器端模板注入漏洞的概念证明。
不过注意,成功评估数学运算所需的特定语法会因为使用的模板引擎而有所不同,将在后面的步骤更详细的讨论这一点。
代码环境
在其他情况下,将用户的输入放在模板表达式中会暴露该漏洞,正如前面在电子邮件示例中看到的那样,这可以采取用户可控制的变量名称的形式放置在参数内,例如:
greeting = getQueryParameter('greeting')
engine.render("Hello {{"+greeting+"}}", data)
在网站上,产生的URL将是这样的:
http://vulnerable-website.com/?greeting=data.username
这将在输出中呈现Hello Carlos。
这种情况在上下文的评估过程中很容易被忽略,因为它不会导致明显的XSS,而且与简单的哈希图查询几乎没有区别。
在这种情况下,测试服务器端模板注入的一种方法是,首先通过向值中注入任意HTML来确定参数不包含直接的XSS漏洞:
http://vulnerable-website.com/?greeting=data.username<tag>
在没有XSS的情况下,这通常会导致输出中出现空白条目(只有Hello,没有用户名)、编码标签或错误消息。
下一步是尝试使用通用模板语法跳出语句,并尝试在语句之后注入任意HTML:
http://vulnerable-website.com/?greeting=data.username}}<tag>
如果这又导致了错误或空白输出,则说明要么使用了错误的模板语言的语法,要么没有使用有效的模板样式语法,服务器端模板注入不可能存在。
但是,如果输出结果与任意的HTML一起被正确的呈现,这是一个关键迹象,表明存在服务器端模板注入的漏洞,例如下面这种显示:
Hello Carlos<tag>
识别(Identify)
一旦检测到模板注入的可能性,下一步就是识别模板引擎。
虽然有大量的模板语言,但许多模板语言使用非常相似的语法,并特意选择不与HTML字符冲突的语法。
因此,在创建探测有效payload来测试正在使用的模板引擎相对比较简单。
简单地提交无效语法通常就足够了,因为产生的错误信息会准确告诉我们模板引擎是什么,有时甚至是哪个版本。
例如,无效的表达式<%=foobar%>会触发基于Ruby的ERB引擎的如下响应:
(erb):1:in `<main>': undefined local variable or method `foobar' for main:Object (NameError)
from /usr/lib/ruby/2.5.0/erb.rb:876:in `eval'
from /usr/lib/ruby/2.5.0/erb.rb:876:in `result'
from -e:4:in `<main>'
否则,需要手动测试不同语言的payload,并研究模板引擎如何解释它们。根据哪些语法看起来是有效的或无效的,使用排除法,可以更快地缩小选择范围。
一个常见的方法是使用不同模板引擎的语法注入任意的数学运算,然后观察它们是否被成功计算。
为了帮助完成此过程,可以使用类似于下面的决策树:
应该意识到,相同的payload有时可以在多个模板语言中返回一个成功的响应。例如,payload(7*7)在Twig中返回49,在Jinja2中返回777777。因此,不要根据一个成功的响应就下结论。
利用(Exploit)
在检测到潜在漏洞存在并成功识别模板引擎后,可以开始尝试寻找利用它的方法。
具体EXP的攻击示例,在后面章节中进行讲解。
SQL注入攻击-检索隐藏的数据
HTTP Host头漏洞攻击-概念梳理
原文始发于微信公众号(H君网安白话):服务器端模板注入(SSTI)-如何构建攻击
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论