Struts2-016 动态调试与分析

最近终于下定决心开始研究一下java web的安全。相比起php web, 调试java web往往会出现各种各样的环境问题,其中一个原因就是开发java web应用会大量引用已存在的各种成熟组件,如同建筑一栋高楼,如果其中一根底层支柱出了问题,整栋大楼就构建不起来。大部分想要去做安全研究的同学其实都没有太多的开发经验,因此在环境调试上面的问题会变得非常棘手。

这就成为了不少想要入门java web安全的同学的一道高门槛,比如你兴致勃勃地拿到了一个java web应用项目代码,开始构建应用的时候发现爆了一个错误,解决这个错误可能就会耽搁你一下午,等到你解决完了这个问题,你最初的激情可能已经磨灭了一大半了。其实如果最终能够解决问题也还算不错,更糟的情况可能是你至始至终都没有解决这个问题。

以上其实就是我个人在这段时间研究java web时的一些感想。废话不多说了,下面我会以一个java web安全初学者的视角,比较详细地记录自己调试struts2-016的过程。

0x01 环境搭建

Struts是apache基金会jakarta项目组的一个开源项目,采用MVC模式,能够很好的帮助我们提高开发web项目的效率。Struts主要采用了servlet和jsp技术来实现,把servlet、jsp、标签库等技术整合到整个框架中。

我下载的struts2源码版本是 struts-2.3.14.3-src.zip (不带jar包),目录结构如下。

我常用的ide是jetbrain idea,在示例web应用中选择了代码最简洁的struts-blank应用。首先open project,选择apps/blank文件夹,然后等待maven下载完依赖的jar包。

依次打开project structure ,选择library,如下图所示关联struts2-core 和 xwork-core两个包的源码,源码分别在core目录和xwork-core目录。

然后配置下运行环境,这个就不多介绍了。最终成功运行如下。

用以下poc打下

redirect:$%7b%23w%3d%23context.get('com.opensymphony.xwork2.dispatcher.HttpServletResponse').getWriter(),%23w.println('struts2-016'),%23w.flush(),%23w.close()%7d

0x02 动态调试

StrutsPrepareAndExecuteFilter 是struts2框架的默认filter,所有的filter都需要在web.xml中进行配置。

StrutsPrepareAndExecuteFilter 作用是过滤所有的action请求并进行映射,简单的理解就是路由分发。比如用户请求HelloWorld.action时,就会根据相应的路由规则映射到controller层的HelloWorld类,经过处理后再渲染到view层/example/HelloWorld.jsp。相应的映射规则在struts.xml中配置。

struts.xml

example.xml

简单的了解了StrutsPrepareAndExecuteFilter的作用后,我们开始在第77行下一个断点进行调试。

上图中是doFilter的代码,理解这个方法其实就是理解整个struts2框架路由映射的关键。像struts2这样知名的开源框架,其命名必然是有道理的,有的时候我们可以根据方法名来直接判断这个方法的大致作用(这样可以略过一些于漏洞本身无关紧要的方法)。

比如上图77行的setEncodingAndLocale(),字面意思就是设置编码和场景,其作用就是设置编码和初始化环境。

78行的createActionContext(),即创建action的上下文。ActionContext正如其名,是Action执行的上下文,它包含了request、session、application、action、attr、parameters等属性。

83行这里先略过。17年三月份爆发的struts2 045漏洞就与它有关。

84行findActionMapping()。寻找action的映射,按f7跟进函数中。

再跟进getMapping(),可以看到一个handleSpecialParameters()的调用。函数名的字面意思为“处理特殊的参数”,而特殊的参数就是我们poc里面的 redirect:${xxxxx}

f7跟进handleSpecialParameters()。首先提取出了key redirect:${xxxxx} ,然后把key作为参数之一调用了parameterAction.execute()。

继续f7,进入了第一个箭头所指的代码段。提取出了ognl表达式 ${xxxxx} 并赋值给了redirect的location属性。

至此。我们已经分析完了 struts2 中特殊参数redirect的作用。如 http://localhost:8081/example/HelloWorld.action?redirect:http://www.baidu.com 就会把http://www.baidu.com赋值为redirect的location属性并302跳转到百度。

那么什么时候最终执行了ognl表达式呢?我们跳出到最开始的doFilter()里面。。

跟进91行,executeAction()。这里没什么好说的。

继续f7,进入了Dispatcher类的serviceAction()。前面已经完成了action的映射(正常情况下是HelloWorld.action->HelloWorld.java,目前是要处理redirect),serviceAction()的544行的作用就是执行映射后的逻辑代码(正常情况下执行HelloWorld.java里的具体逻辑代码,不过这里是执行redirect)。

跟进execute()。后面的逻辑都比较简单,按顺序一路跟进。


conditionalParse()。包含了ognl表达式的location被作为了conditionalParse()的参数,并最终在translateVariables()中执行了ongl表达式。



0x03 思考

为什么会在conditionalParse()里面解析ognl?开发者是出于一个怎样的意图?

参考资料

攻击JavaWeb应用[5]-MVC安全

稿源:Th1s's Bl0g (源链) | 关于 | 阅读提示

本站遵循[CC BY-NC-SA 4.0]。如您有版权、意见投诉等问题,请通过eMail联系我们处理。
酷辣虫 » 综合编程 » Struts2-016 动态调试与分析

喜欢 (0)or分享给?

专业 x 专注 x 聚合 x 分享 CC BY-NC-SA 4.0

使用声明 | 英豪名录