0x01 部署踩坑
- 下载需要的版本的
all-zip
,解压后取出src/apps/showcase
- 使用idea打开showcase,应会自动识别struts框架以及maven,等待maven将依赖包全部下好
- 在
Maven Project
中,右键下载需要调试的依赖的源码
- 在左侧项目导视中
External Libraries
即可调试
部署代码
这里需要注意两点
alwaysSelectNamespace要设置为true
可以在constant中直接修改全局变量,或在以下位置中修改
result的类型要设置为要测试的
结果类型
,这里用的redirectActoin<struts> <constant name="struts.mapper.alwaysSelectFullNamespace" value="true" /> <package name="actionchaining" extends="struts-default"> <action name="actionChain1" class="org.apache.struts2.showcase.actionchaining.ActionChain1"> <result type="redirectAction"> <param name = "actionName">register2</param> </result> </action> </package> </struts>
0x02 分析
跟进分析
通过patch查看漏洞触发点
P.S. 小技巧,git项目后面加
compare
会调到对比页面,可选择branch或tags,但是后者需要直接输入全称版本比较
https://github.com/apache/struts/compare/STRUTS_2_3_34...STRUTS_2_3_35
漏洞形成主要问题点
https://github.com/apache/struts/commit/918182344cc97515353cc3dcb09b9fce19c739c0
![](15389831684022.jpg)
由于alwaysSelectFullNamespace为true,导致namespace可以被通过uri控制
action结束后,调用ServletActionRedirectResult.execute()进行重定向Result的解析,通过getUriFromActionMapping将uri重组并传给父类StrutsResultSupport执行
在父类的conditionalParse中通过TextParseUtil.translateVariables()执行ognl表达式
流程梳理
st=>start: 输入URL:/struts2-showcase/$%{(111+111)}/actionChain1.action
a=>operation: 进入 org.apache.struts2.dispatcher.mapper.DefaultActionMapper#parseNameAndNamespace 解析 namespace
b=>operation: action 结束后通过 struts-default.xml 查找 name 为 redirectAction 的结果类型处理类
c=>operation: org.apache.struts2.dispatcher.ServletActionRedirectResult#execute中调用ActionMapper.getUriFromActionMapping()重组namespace和name
d=>operation: 由setLocation()将带namespace的location放入父类StrutsResultSupport中
e=>operation: StrutsResultSupport.execute()调用conditionalParse,后者再调用TextParseUtil.translateVariables
f=>operation: translateVariables经过多重重载后,实现ParsedValueEvaluator ognlEval = new ParsedValueEvaluator() {...}
en=>end: ognl执行
st->a->b->c->d->e->f->en
0x03 利用条件
最小条件:
- alwaysSelectFullNamespace值为true
- Struts2配置文件中,action元素未设置namespace属性,或使用了通配符
0x04 利用方式
这次的漏洞可以有多种攻击向量,根据漏洞作者blog有:
- Redirect action
- Action chaining
- Postback result
以上提及的三种都属于Struts2的跳转方式。在 struts-default.xml
<result-types>
<result-type name="chain" class="com.opensymphony.xwork2.ActionChainResult"/>
<result-type name="redirectAction" class="org.apache.struts2.result.ServletActionRedirectResult"/>
<result-type name="postback" class="org.apache.struts2.result.PostbackResult" />
</result-types>
i. Redirect action & Postback result
触发方式很像,而且会到跳转执行结果(url中显示)
ii. Action chaining
有点特殊,代码会执行但是不会跳转显示结果
org.apache.struts.xwork -> com.opensymphony.xwork2.ActionChainResult#execute
执行前后对比
坑点1,注意注释,这里执行完的结果还要回到DefaultActionInvocation中处理
然后调用createResult()来生产结果
坑点2,这里会再调用getResults()获取结果,(图好像没截对,都是执行后的,可以自行debug)
获取结果前后对比
上面为什么会变化关键在于proxy的config记录的是原有的配置信息
0x05 POC构造
[占坑]
ognl-3.x.xx.jar!/ognl/OgnlContext.class
http://localhost:8088/struts2-showcase/${(111+111)}/actionChain1.action
- 较新版本已将
CONTEXT_CONTEXT_KEY
和CLASS_RESOLVER_CONTEXT_KEY
删除 - 发现在
#request
域下的struts.valueStack对象中存在context属性