Exploiting server-side template injection vulnerabilities

利用服务端模板注入漏洞

在本节中,我们将更仔细地了解一些典型的服务端模板注入漏洞,并演示如何利用之前归纳的方法。通过付诸实践,你可以潜在地发现和利用各种不同的服务端模板注入漏洞。

一旦发现服务端模板注入漏洞,并确定正在使用的模板引擎,成功利用该漏洞通常涉及以下过程。

  • 阅读
    • 模板语法
    • 安全文档
    • 已知的漏洞利用
  • 探索环境
  • 构造自定义攻击

阅读

除非你已经对模板引擎了如指掌,否则应该先阅读其文档。虽然这可能有点无聊,但是不要低估文档可能是有用的信息来源。

学习基本模板语法

学习基本语法、关键函数和变量处理显然很重要。即使只是简单地学习如何在模板中嵌入本机代码块,有时也会很快导致漏洞利用。例如,一旦你知道正在使用基于 Python 的 Mako 模板引擎,实现远程代码执行可以简单到:

1
2
3
4
5
<%
import os
x=os.popen('id').read()
%>
${x}

在非沙盒环境中,实现远程代码执行并将其用于读取、编辑或删除任意文件在许多常见模板引擎中都非常简单。

阅读安全部分

除了提供如何创建和使用模板的基础知识外,文档还可能提供某种“安全”部分。这个部分的名称会有所不同,但它通常会概括出人们应该避免使用模板进行的所有潜在危险的事情。这可能是一个非常宝贵的资源,甚至可以作为一种备忘单,为你应该寻找哪些行为,以及如何利用它们提供指南。

即使没有专门的“安全”部分,如果某个特定的内置对象或函数会带来安全风险,文档中几乎总是会出现某种警告。这个警告可能不会提供太多细节,但至少应将其标记为可以深入挖掘研究的内容。

例如,在 ERB 模板中,文档显示可以列出所有目录,然后按如下方式读取任意文件:

1
2
<%= Dir.entries('/') %>
<%= File.open('/example/arbitrary-file').read %>

查找已知的漏洞利用

利用服务端模板注入漏洞的另一个关键方面是善于查找其他在线资源。一旦你能够识别正在使用的模板引擎,你应该浏览 web 以查找其他人可能已经发现的任何漏洞。由于一些主要模板引擎的广泛使用,有时可能会发现有充分记录的漏洞利用,你可以对其进行调整以利用到自己的目标网站。

探索

此时,你可能已经在使用文档时偶然发现了一个可行的漏洞利用。如果没有,下一步就是探索环境并尝试发现你可以访问的所有对象。

许多模板引擎公开某种类型的 selfenvironment 对象,其作用类似于包含模板引擎支持的所有对象、方法和属性的命名空间。如果存在这样的对象,则可以潜在地使用它来生成范围内的对象列表。例如,在基于 Java 的模板语言中,有时可以使用以下注入列出环境中的所有变量:

1
${T(java.lang.System).getenv()}

这可以作为创建一个潜在有趣对象和方法的短名单的基础,以便进一步研究。

开发人员提供的对象

需要注意的是,网站将包含由模板提供的内置对象和由 web 开发人员提供的自定义、特定于站点的对象。你应该特别注意这些非标准对象,因为它们特别可能包含敏感信息或可利用的方法。由于这些对象可能在同一网站中的不同模板之间有所不同,请注意,你可能需要在每个不同模板的上下文中研究对象的行为,然后才能找到利用它的方法。

虽然服务端模板注入可能导致远程代码执行和服务器的完全接管,但在实践中,这并非总是可以实现。然而,仅仅排除了远程代码执行,并不一定意味着不存在其他类型的攻击。你仍然可以利用服务端模板注入漏洞进行其他高危害性攻击,例如目录遍历,以访问敏感数据。

构造自定义攻击

到目前为止,我们主要研究了通过重用已记录的漏洞攻击或使用模板引擎中已知的漏洞来构建攻击。但是,有时你需要构建一个自定义的漏洞利用。例如,你可能会发现模板引擎在沙盒中执行模板,这会使攻击变得困难,甚至不可能。

在识别攻击点之后,如果没有明显的方法来利用漏洞,你应该继续使用传统的审计技术,检查每个函数的可利用行为。通过有条不紊地完成这一过程,你有时可以构建一个复杂的攻击,甚至能够利用于更安全的目标。

使用对象链构造自定义攻击

如上文所述,第一步是标识你有权访问的对象和方法。有些对象可能会立即跳出来。通过结合你自己的知识和文档中提供的信息,你应该能够将你想要更彻底地挖掘的对象的短名单放在一起。

在研究对象的文档时,要特别注意这些对象允许访问哪些方法,以及它们返回哪些对象。通过深入到文档中,你可以发现可以链接在一起的对象和方法的组合。将正确的对象和方法链接在一起有时允许你访问最初看起来遥不可及的危险功能和敏感数据。

例如,在基于 Java 的模板引擎 Velocity 中,你可以调用 $class 访问 ClassTool 对象。研究文档表明,你可以链式使用 $class.inspect() 方法和 $class.type 属性引用任意对象。在过去,这被用来在目标系统上执行 shell 命令,如下所示:

1
$class.inspect("java.lang.Runtime").type.getRuntime().exec("bad-stuff-here")

使用开发人员提供的对象构造自定义攻击

一些模板引擎默认运行在安全、锁定的环境中,以便尽可能地降低相关风险。尽管这使得利用这些模板进行远程代码执行变得很困难,但是开发人员创建的暴露于模板的对象可以提供更进一步的攻击点。

然而,虽然通常为模板内置对象提供了大量的文档,但是网站特定的对象几乎根本就没有文档记录。因此,要想知道如何利用这些漏洞,就需要你手动调查网站的行为,以确定攻击点,并据此构建你自己的自定义攻击。