漏洞描述
Apache Struts是美国阿帕奇(Apache)基金会的一个开源项目,是一套用于创建企业级Java Web应用的开源MVC框架。
Apache Struts在特定条件下,存在文件上传漏洞(网宿评分:高危、CVSS 3.0 评分:8.1):
攻击者可以操纵文件上传参数来实现路径遍历,在某些情况下,这可能导致恶意文件上传。
影响版本
Struts 2.0.0 - 2.3.37(EOL)
Struts 2.5.0 - 2.5.33(EOL)
Struts 6.0.0 - 6.3.0.2
环境搭建
同S2-066
漏洞成因
S2-067
与S2-066
有90%的相似,S2-067
是S2-066
补丁的绕过。
通过前一篇文章的分析我们直到S2-066
的修复是在向ActionContext
的parameters
属性添加一个参数,先检查parameters
属性是否为空,如果为空,则直接添加参数,
如果parameters
不为空,则遍历文件上传的参数ContentType
与UploadFileName
等,将其先同意转换为小写,然后在与parameters
中的元素比较,
当存在相同的元素的时候先删除parameters
中的参数再将新的参数添加到parameters
中,这样就避免了用户上传表单中非文件参数对文件上传参数的影响覆盖。
通过对S2-066
的学习我们还可以直到,form表单参数的name
属性的值会被当作OGNL
解析,用来向ValueStack
上的root
映射中的元素设置属性值。
既如此,name
属性的值就可以是任何有效的OGNL
表达式,从而实现任意属性的设置。
当我们使用这样的表达是的时候top.uploadFileName
会发生什么。
让我们定位到com.opensymphony.xwork2.interceptor.ParametersInterceptor.setParameters
方法
这里面调用了ValueStack
的setParameter
方法向ValueStack
的root
映射中设置属性值。
1 | protected void setParameters(final Object action, ValueStack stack, HttpParameters parameters) { |
通过setParaameters
的方法签名也可以看出来其第一个参数是一个OGNL
表达式。
1 | public void setParameter(String expr, Object value) { |
程序继续向下执行最终会来到 com.opensymphony.xwork2.ognl.OgnlUtil.compileAndExecute
方法。
这个方法会根据ognl
表达式来获取ognl
表达式对应的ognl
树,然后解析ognl
树。
当ognl
表达式为uploadFileName
的时候,得到的tree
为ASTProperty
类型,S2-066
就是执行ASTProperty
的setValueBody
方法设置ValueStack
的root
映射中的元素。
当ognl
表达式为top.uploadFileName
的时候,得到的tree
为ASTChain
类型,S2-067
就是执行ASTChain
的setValueBody
方法设置ValueStack
的root
映射中的元素。
1 | private <T> Object compileAndExecute(String expression, Map<String, Object> context, OgnlTask<T> task) throws OgnlException { |
ASTChain
的setValueBody
方法
1 | protected void setValueBody(OgnlContext context, Object target, Object value) throws OgnlException { |
ASTChain
的Children
包含两个元素均为ASTProperty
类型,就是通过.
将top.uploadFileName
进行了分割成两部分。
首先通过top
节点去取target
的值,注意这里target
之前是有值的就是ValueStack
的root
映射部分,即一个CompoundRoot
对象,包含两个元素UploadAction
以及DefaultTextProvider
对象。这里也就是通过top
节点取取一个值来覆盖原来的target
。
代码继续向下执行会来到com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor.getProperty
方法。
这里判断name
是否为top
,如果为top
则返回root
的第一个元素,否则会遍历root
中的元素,如果元素中有name
属性则返回该元素。root
的第一个元素即为UploadAction
,即上一步求的target
为UploadAction
。
1 | public Object getProperty(Map context, Object target, Object name) throws OgnlException { |
重新求得target
后则会调用uploadFileName
的节点得setValue
方法为target
设置值。uploadFileName
节点是ASTProperty
类型,这就是典型得OGNL
表达式的语法了,后面的内容就与S2-066
的逻辑一致了。
因为在S2-067
中我们使用的payload
是top.uploadFileName
与UploadFileName
在统一大小写后也并不相等,所以就能完美的绕过S2-066
添加的remove
方法的补丁了。
1 | this._children[this._children.length - 1].setValue(context, target, value); |
另外,ValueStack
的root
映射中包含两个元素,一个是UploadAction
,一个是DefaultTextProvider
,既然UploadAction
的属性可以被设置,那么DefaultTextProvider
的属性也是可以被设置的。
这样我们就可以控制DefaultTextProvider
对象的属性值,是不是可以做些什么呢?
漏洞修复
新增了一个类并被推荐使用。。。。FileUploadAction并没有被修改,应该是这样的。赶时间
参考链接
无