一、前言
2020年8月13日,Apache官方发布了一则公告,该公告称Apache Struts2使用某些标签时,会对标签属性值进行二次表达式解析,当标签属性值使用了%{skillName}
并且skillName
的值用户可以控制,就会造成OGNL
表达式执行。
二、漏洞复现
我这里选用的测试环境 Tomcat 7.0.72
、Java 1.8.0_181
、Struts 2.2.1
,受影响的标签直接使用官网公告给出的例子
<s:url var="url" namespace="/employee" action="list"/><s:a id="%{payload}" href="%{url}">List available Employees</s:a>
测试漏洞URL
http://localhost:8088/S2-059.action?payload=%25{3*3}
在s2-029
中由于调用了completeExpressionIfAltSyntax
方法会自动加上"%{" + expr + "}"
,所以payload
不用带%{}
,在s2-029
的payload
里加上%{}
就是s2-059
的payload
,具体原因看下面的分析。
三、漏洞分析
根据官网公告的漏洞描述及上面的测试过程可以知道,这次漏洞是由于标签属性值进行二次表达式解析产生的。struts2 jsp
标签解析是org.apache.struts2.views.jsp.ComponentTagSupport
类的doStartTag
和doEndTag
方法。debug
跟下 doStartTag
方法。
跟下populateParams
方法
org/apache/struts2/views/jsp/ui/AnchorTag.class
这里又去调用了父类的populateParams
方法,接着调用org/apache/struts2/views/jsp/ui/AbstractUITag.class
类的populateParams
方法
可以看到这里有给setId赋值,跟下setId方法,org/apache/struts2/components/UIBean.class
由于id不为null,会执行this.findString
方法,接着跟下.org/apache/struts2/components/Component.class
altSyntax
默认开启, 所以this.altSyntax()
会返回true
,toType
的值传过来是String.class
,if
条件成立会执行到TextParseUtil.translateVariables('%', expr, this.stack)
可以看到这里是首先截取去掉%{}
字符,然后从stack
中寻找payload
参数,传输的payload
参数是%{3*2}
,这里会得到这个值。
执行完populateParams
方法可以得知这个方法是对属性进行初始化赋值操作。接着跟下start
方法
org/apache/struts2/components/Anchor.class
的start
方法调用了父类org/apache/struts2/components/ClosingUIBean.class
的start
方法
在接着跟下org/apache/struts2/components/UIBean.class$evaluateParams
方法
接着调用了populateComponentHtmlId
方法
在看下findStringIfAltSyntax
方法的实现
org/apache/struts2/components/Component.class$findStringIfAltSyntax
可以看到这里又执行了一次TextParseUtil.translateVariables
方法.
整个过程跟S2-029
和S2-036
漏洞产生的原因一样,都是由标签属性二次表达式解析造成漏洞。分析完漏洞产生原因后,我查看了UIBean class
相关代码,并没有发现除id
外其它标签属性值可以这样利用。
四、总结
此次漏洞需要开启altSyntax
功能,只能是在标签id
属性中存在表达式,并且参数还可以控制,这种场景在实际开发中非常少见,危害较小。
五、参考链接
https://cwiki.apache.org/confluence/display/WW/S2-059
http://blog.topsec.com.cn/struts2%e6%bc%8f%e6%b4%9es2-029%e5%88%86%e6%9e%90/