Learning Man's Blog

s2-057 漏洞分析

字数统计: 836阅读时长: 3 min
2018/10/08 Share

影响版本:

Struts 2.3 - Struts 2.3.34
Struts 2.5 - Struts 2.5.16

0x01 部署踩坑

  1. 下载需要的版本的all-zip,解压后取出src/apps/showcase
  2. 使用idea打开showcase,应会自动识别struts框架以及maven,等待maven将依赖包全部下好
  3. Maven Project中,右键下载需要调试的依赖的源码
  4. 在左侧项目导视中External Libraries即可调试

部署代码

这里需要注意两点

  1. alwaysSelectNamespace要设置为true
    可以在constant中直接修改全局变量,或在以下位置中修改

  2. 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 分析

跟进分析

  1. 通过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

![](media/15389829374894/15389831684022.jpg)
  1. 由于alwaysSelectFullNamespace为true,导致namespace可以被通过uri控制

  2. action结束后,调用ServletActionRedirectResult.execute()进行重定向Result的解析,通过getUriFromActionMapping将uri重组并传给父类StrutsResultSupport执行

  3. 在父类的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 利用条件

最小条件:

  1. alwaysSelectFullNamespace值为true
  2. 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. 执行前后对比


  2. 坑点1,注意注释,这里执行完的结果还要回到DefaultActionInvocation中处理

    然后调用createResult()来生产结果

  3. 坑点2,这里会再调用getResults()获取结果,(图好像没截对,都是执行后的,可以自行debug)

    获取结果前后对比

  4. 上面为什么会变化关键在于proxy的config记录的是原有的配置信息

0x05 POC构造

[占坑]

ognl-3.x.xx.jar!/ognl/OgnlContext.class

http://localhost:8088/struts2-showcase/${(111+111)}/actionChain1.action

  1. 较新版本已将CONTEXT_CONTEXT_KEYCLASS_RESOLVER_CONTEXT_KEY删除
  2. 发现在#request域下的struts.valueStack对象中存在context属性

参考资料

  1. https://mp.weixin.qq.com/s/iBLrrXHvs7agPywVW7TZrg
  2. https://xz.aliyun.com/t/2618
  3. https://paper.seebug.org/682/
  4. https://lgtm.com/blog/apache_struts_CVE-2018-11776
CATALOG
  1. 1. 0x01 部署踩坑
    1. 1.1. 部署代码
  2. 2. 0x02 分析
    1. 2.1. 跟进分析
    2. 2.2. 流程梳理
  3. 3. 0x03 利用条件
  4. 4. 0x04 利用方式
    1. 4.1. i. Redirect action & Postback result
    2. 4.2. ii. Action chaining
  5. 5. 0x05 POC构造
  6. 6. 参考资料