Learning Man's Blog

s2-057 漏洞分析

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

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

![](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. 0x01 部署踩坑
    1. 部署代码
  2. 0x02 分析
    1. 跟进分析
    2. 流程梳理
  3. 0x03 利用条件
  4. 0x04 利用方式
    1. i. Redirect action & Postback result
    2. ii. Action chaining
  5. 0x05 POC构造
  6. 参考资料