0x01 环境创建
我使用IDEA进行Struts2的环境创建,这其中有坑。
首先便是Struts2必要jar包获取,最终采用了用解压的Struts-Blank.war部署在tomcat服务器的方式。这其中注意事项(也就是我踩过的坑)
JAVA环境变量的JAVA_HOME和JRE_HOME必须设置好且正确,tomcat的startup.bat才不会报错
IDEA创建Struts2项目后,正确配置JDK和Tomcat服务于IDEA,并且导包后是不行的,这里不会进行报错,但是IDEA中Tomcat日志会报错
java.lang.ClassNotFoundException: org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter是S2的核心过滤器,其配置在web.xml中
在第三方包环境是有这个java文件的:
百度得以解决,在IDEA中的WEB-INF中新建lib文件夹并再拷一份第三方lib过去
https://blog.csdn.net/lihuan6656/article/details/53502842
然后自己简单写了点demo跑起来之后看着这里的一个错误的demo配置https://www.freebuf.com/column/208925.html
环境已经搭建完成。
0x02 进还是不进?
在调试过程中多次遇到一个包进不去的情况,原因是因为该包没有被导入该对象属于tomcat底层对象如request
若在对request.setAttribut()使用了F7将进入org.apache.catalina这个包,可是我们只能看到Frame界面其行数但是游标不会进入该包,也看不到其代码。
解决:
可以看到,其归属于tomcat的lib包,在执行过程中tomcat能够进行解析,这就是为什么能执行但是IDEA无法跟进的原因。同样jdk的jar包也是一样,不过只要有该jar导入了IDEA便能让IDEA去反编译它。因此,调试过程中即使使用pom构建方式千万别忘了导入JDK和tomcat的lib包:
这样便能跟进tomcat层的jar包了
PS:只能用该种该方式导入,否则如果是在pom库找到的jar包会因版本和代码不一致等问题产生编译错误,IDEA优先选择导入的jar包。程序运行就会报错。
TIPS:除了跟进。还有一种很好的方式可以避免该错误:不进,如果不需要跟到tomcat层的问题。也就是该漏洞不由tomcat产生。推荐使用这种方式。思考有两种实现方式:
- 在request的方法同时不要使用F7而使用F8,这样将不会进入方法体或者下断点使用F9
- 在调试器设置选择绕过一些jar包(推荐):
0x03开始调试
根据漏洞描述将端点打在了struts2-core-2.3.24-sources.jar!\org\apache\struts2\dispatcher\mapper\DefaultActionMapper.java#parseNameAndNamespace ↓
恶意数据存入namespace和mapping ↓
继续F7下去 到达#getMapping方法,其调用的刚刚断点的#parseNameAndNamespace方法: ↓
我们看到这个#handleSpecialParameters方法,考虑是否跟进,语义 处理特殊参数 可跟可不跟,无法确定这个特殊参数会不会处理我们的表达式。节省时间下个断点在265行,再下个在266行,不调用跟踪先。然后F9直接跳断点忽略该方法的跟进。 ↑
然后是266的parseActionName,明显是指引action名字,简单看一下,因为我们如果又要使用断点跳过,在return还要通过useage得到返回 ↓
然后返回,上一级继续Return到达了org\apache\struts2\dispatcher\ng\PrepareOperations.java#findActionMapping ↓
这个#findActionMapping就是查看了下前文mapping取到了没,没取到就在值栈中去取,值栈的知识不再赘述的,其是Struts的上下文。 ↓
传入三参数的#findActionMapping,F7一下回到了org\apache\struts2\dispatcher\ng\filter\StrutsPrepareFilter.java#doFilter这里是过滤器处理的类,就在之前调用了#findActionMapping,所以#findActionMapping结束回到了#doFilter ↓
遗憾的来到了这个catalina(tomcat底层包),刚刚那个Step设置有待商榷,解救一下,断点F9
这里不是我们想看的内容,几次F8一下,我们到了struts2-core-2.3.24-sources.jar!\org\apache\struts2\dispatcher\ServletActionRedirectResult.java#execute ↓
下面便调了namespace = invocation.getProxy().getNamespace();去取namespace ↓
下面一点,这里不确定是不是,语义分析或者去实现类看下或者F7进去看一下两种方式排查一下并不是执行ognl的地方 ↓
我选择了F7跟进的方式,178和180跟完了都不是 ↓
再调父类 ↑
org\apache\struts2\dispatcher\StrutsResultSupport.java#execute最终执行,传入invocation参数 ↓
再F7跟进一下,到达本类的#conditionalParse方法: ↓
执行了几步,这里就是OGNL值执行地(OgnlTextParser#evaluate) ↓
至此,传入的ognl表达式被com\opensymphony\xwork2\util\OgnlTextParser.java#evaluate予以解析。