本文翻译自:https://ha.cker.info/exploitation-of-server-side-template-injection-with-craft-cms-plguin-seomatic/
在最近的Web应用程序测试期间,我决定对CMS的URI中的某些路径进行一些模糊测试(fuzzing),并且碰巧在CMS的一个插件中找到了潜在的服务器端模板注入(SSTI)漏洞,然后我就能够成功利用它来获得非公开的信息。在这篇文章中,我想分享一下我如何通过分析思考一步步找到漏洞的。
这是我在最初的Fuzzing中偶然发现的SSTI。你可以看到我能够触发某种数学逻辑,它由服务器上的模板引擎处理,然后反映在canonicalURL中,它是响应中Link头的一部分:
首先:什么是SSTI?服务端模板注入,Server Side Template Injection简称SSTI。SSTI指的是用户输入的不安全内容嵌入到了模板中。大多数情况下,造成问题的原因时用户的自定义输入直接连接到模板中,并且此输入(本应是数据)包含了模板表达式,进而被服务器执行。
如果你不熟悉此类漏洞,请务必访问Portswigger博客并阅读James Kettle撰写的这篇文章(@albinowax)。你不会后悔,它是web应用安全话题的超级补充。他也提供了适合打印的pdf版本,并在BlackHat 2015(PDF/视频)上发表。我已经了解了这个漏洞背后的基本概念,但对我而言,这是我第一次真正在实际研究中遇到它,所以我决定更新我的知识储备并阅读詹姆斯关于这个主题的论文。
在加深了对这种漏洞的理解之后,我急于找到正确的攻击方法,我的第一种方法是通过利用名为TPLMAP的自动化exp工具试图一步到位。 (不)幸运的是,无脑的自动化武器并不成功,我被迫彻底地研究这个让我后来真正学到一些新东西的题目:
TPLMAP不顶事
好吧,脚本小子一头撞上了南墙。让我带你开始探索问题的旅程。首先:我们退回原点,通过尽可能地拆解已知的事实信息来评估情况。
我们确信我们可以注入任意内容并交由模板引擎处理。并根据header中给出的响应,我们可以推出该网站在Craft CMS上运行(https://craftcms.com):
Header Responses
不幸的是它没有泄漏确切的版本号,但对于初学者我们可以简单地尝试利用最新的文档,并根据此文档Craft使用的是Twig(这是James研究中涵盖的PHP模板引擎之一)。
那么让我们全面了解一下文档。这实际上将帮助我们实现我们的野心,并加深我们对CMS和模板引擎如何相互作用的理解。此外,它对于理解两个组件的体系结构和实际对象,方法和语法非常有用:
https://docs.craftcms.com/v2/
https://docs.craftcms.com/v3/
https://twig.symfony.com/doc/2.x/
此外,始终建议检查目标的旧/已知/现有漏洞。如果有,请审查代码以了解在连续发布的版本中是如何更改和修复这些漏洞的。上面的任何一点都可能引发一些想法。就我而言,我审查了一些已知问题。例如:
Craft CMS受服务器端模板注入的影响
Craftcms Craft Cms:安全漏洞列表 - CVE详细信息
Twig <2.4.4 - 服务器端模板注入
如上所述,了解旧漏洞始终是一个丰富自己技巧的好方法。即使问题已经解决,上面列出的以前存在的SSTI漏洞就是一个很好的样例作为参照,你可以通过阅读他们如何为这个漏洞创建PoC来找到一些有趣的想法。
最后一招,如果可以这么做的话:下载源代码,看看内幕!
如果你尝试利用自动利用和侦察工具(TPLMAP),请务必了解他们的能力范围和工作原理。
有趣的一点事实:在Craft CMS中使用Twig也解释了为什么我最初用TPLMAP的尝试没有收获任何战果,因为该工具不支持Twig:
TPLMAP支持情况一览表
根据我们的信息汇总,可以发现下面的重要线索,根据James的研究,Twig的_self对象及其env属性是突破口,能搞出来远程执行代码(RCE):
{{_self.env.registerUndefinedFilterCallback("exec")}}
{{_self.env.getFilter("id")}}
uid=1000(k)gid=1000(k)groups=1000(k),10(wheel)
我们尝试通过注入点调用它。但是,在我的测试中, 我发现 _self 不是一个对象, 而是一个返回模板名称的字符串:
_self 为字符串, 而不是引用对象
查阅了文档和其他声明, 结果是他们从Twig v1 更新到Twig v2 的时候把这里给改了。也就是说, 我们正在对付一个你没有见过的船新版本的Twig, 不容易在它上面利用詹姆斯挖出来的那个漏洞。目前似乎也没有已公开的漏洞exp可以对付Twig v2 (也解释了为什么 TPLMAP不支持Twig的Exp)。好吧, 我们到了山前才发现没路了。
但还是有希望的。
尽管目前还没人发表关于Twig v2 模板引擎的exp, 但我们仍然可以通过发现的注入点与 CMS 的组件进行交互。根据Craft CMS 文档, 有很多有趣的对象, 过滤器和方法可以从模板调用。而且似乎我们可以从Craft CMS 本身调用对象和方法。根据文档, 我们应该能够找到可编辑的部分:
文档中的示例方法
所以, 让我们尝试一下..。
读取可编辑的片段
哎!我们搞到了一个数组返回值, 就是说我们注入的玩意儿起效了。继续,我们要找到更多的宝贝。仔细阅读文档后会挖掘出一种, 看起来能出货的特定的方法, 因为它允许我们从配置文件中读取信息 (以前的Craft CMS漏洞利用那些人也是用的这个):
{{craft.config.get('someConfigSetting','someConfigFile')}}
让我们来看看配置文件, 并挑选出一些好东西:
来自 db. php 的内容
好多好多我们可以尝试去访问的宝~贝~, 但这次我们需要传递一些参数给 craft.config.get () 方法。让我们尝试在 db. php 文件中传入password:
编码后的控制字符
不幸的是, 框架附带了一些保护功能,通过将控制字符替换为相应的 HTML编码来进行防御。当陷入这样的问题时, 通常选择绕过过滤是一种很好的方式。例如, 有时你通过编辑外来字符转义序列或使用奇异编码方案可能就幸运地绕过了过滤器。我花了一些时间分析过滤器的行为, 得出的结论是, 它有相当强的鲁棒性, 所以需要改变战略。当我掉头回去阅读Craft文档时, 我开始去调戏所有可用的功能。craft.request看起来很有趣, 在我阅读它所支持的方法时, 我终于偶然发现了这个珍贵的宝石:
获取UserAgent
快速测试表明, 此函数确实会反射客户端的User-Agent header。正如你可以看到的,输出的又双叒是过滤后的HTML编码:
craft.request.getUserAgent ()
为了将返回值传递给另一个方法, 我们现在需要使用Twig的 set调用 , 并将结果存储在一个新变量中:
在Twig中使用变量
这使我们能够以更灵活的方式存储和反射函数。由于我们需要在User-Agent字符串中存储两个参数值, 所以我们需要使用第二种方法作为跳板, 或者我们可以使用Twig的过滤器来执行一些字符串操作。
在这种情况下, 我使用slice()把User-Agent header和多个值合并到一起。
到目前为止, 我们已经在一定范围内了解了一些关于 CMS 和模板引擎的内容。根据我们的知识, 我们现在可以通过调用方法在传递任意变量值时尝试访问目标上的敏感信息。语法应该类似于以下内容:
{% set dummy = craft.request.getUserAgent()|slice(0,8)%}
{% set dummy2 = craft.request.getUserAgent()|slice(9,2)%}
{{craft.config.get(dummy,dummy2)}}
User-Agent: password db
让我们尝试一下, 从目标的配置文件中提取数据库密码:
提取 DB 密码
在目前的情况下, 我们能做的就多了。例如, 我们可以遍历所有 CMS 用户, 记下他们的电子邮件地址, 告诉他们他们的网站需要安全修复:
{% forauthor incraft.users %}
{{author.email}}
{% endfor %}
以下是一些我认为有意思的例子:
提取战利品
事实证明, 这个问题是由一个叫做 SEOmatic 的 CMS 插件引起的, 你可以在这里了解更多的信息,还有这里
据开发人员所说,攻击只适用于在Craft CMS 中没有对应条目的url。原因是 canonicalUrl 字段的默认设置是Twig代码:
{{craft.app.request.pathInfo | striptags}}
SEOmatic 的工作方式是, 只有与其他情况都不匹配后, 才使用全局设置。大多数页面都会匹配某种其他类型的条目、类别或产品, 在这些情况下, canonicalUrl 不会被设置为可以包含攻击行为的Twig代码, 因此攻击不会奏效。
因此, 需要满足以下两个条件才能成为攻击URL。首先,有使用Twig模板 (所以它不会抛出 404), 然后也没有一个条目, 类别, 或产品与之关联。
我很高兴地确认, 开发人员在问题得到报告后就解决了问题。你可以在这里找到修复后的版本: https://github.com/nystudio107/craft-seomatic/releases/tag/3.1.4
这里是修复这个问题的提交: https://github.com/nystudio107/craft-seomatic/commit/1e7d1d084ac3a89e7ec70620f2749110508d1ce1
既然我们生活在一个美丽的信息时代, 现在是时候确定有少公开在互联网上的Craft CMS 实例可能受到此漏洞的影响。让我们从 Shodan.io 获得并提取一些数据(注: 有些人问我怎么一开始就找到他们的网站,就是靠这个)
从Shodan收集数据
为了能够进一步处理信息, 我将把它分成多个文件,按端口号分组:
按端口号对数据进行分组
不便的是,我们只能通过Shodan API 查询字符串。就是在Shodan收集的海量信息的数据块里面搜索某个字符串。因此,我需要筛选条目。符合的条目是通过链接头部表明目标是脆弱的,可被此方法攻击的。
清洗数据
最后我们从269条中筛选出了244条。到了最后一步: 让我们爬一下剩下来的目标,看看结果是什么:
易受攻击的主机
总之,我确定了65个可能会更糟的脆弱站点。然后, 我简单地dump了大概300个管理帐户的电子邮件地址,让他们知道这个问题。很多人很快回复了我,确认了漏洞并已经正确地更新了版本。由于开发者也在Twitter上声明了问题, 大多数人应该很快就会升级到修复后版本。
利用现有的扫描和开发工具总是很容易的。但是,一旦你撞到墙上了。多投入一些时间分析问题,磨刀不误砍柴工。确保识别和处理全面的信息,以便更好地了解你的目标。花费的时间最终会赚回来的。至少你也会学到一些新的东西。
时间表: