前言

到目前位置struts2的漏洞编号已经到了S2-057,一直想系统的学习下Struts2的漏洞,但由于工作量较大,一直搁浅。最近由于工作需要,借此机会来填下坑。个人认为一个框架漏洞出来了仅仅看下别人分析的文章是远远不够,因为这些文章往往都只针对个别漏洞,可能框架中还存在类似的漏洞你依然发现不了。所以我说需要系统的学习下,从框架的源码开始分析它的工作流程(当然这里我会有所取舍,全部都讲没意义),同时这样也会加深自己对该框架的理解,之后如果一个新的漏洞出来了,你可以仅根据官方的公告或变动的代码很简单地还原整个漏洞,同时这样做对代码审计也会有一定的帮助。这是我struts2系列文章的第一篇,篇幅会比较长(实际上分析源码的地方我已经省了很多)。之后我还会写spring、tomcat等系列的漏洞分析文章。

准备工作

我使用的是eclipse+struts-core2.1.6,struts2的各版本是由些许区别的,但是大致流程都是相同的,这里采用较老的版本是因为S2早期的漏洞都可以在里面找到,方便分析。

Struts2的工作流程

在原生的jsp+servlet项目中,常用会到Filter过滤器来过滤一些参数等等,这里struts2就是将自己的核心过滤器配置在web.xml中,这样可以让指定的HTTP请求都经过Struts2。早期struts2的核心过滤器是FilterDispathcer (org.apache.struts2.dispatcher.FilterDispatcher),但是struts2>=2.1.3之后就变为了StrutsPrepareAndExecuteFilter,而StrutsPrepareAndExecuteFilter在配置的时候也经常会分开为StrutsPrepareFilter和StrutsExecuteFilter,这是方便开发者更加灵活的使用,配置信息如下:

Filter的执行顺序是然配置顺序来的,所以这里我们先从StrutsPrepareFilter开始分析。

一个Filter比较重要的两个方法,一个是init一个doFilter,init是Filter初始化的时候才会调用,一般是容器刚启动时,而传入的参数FilterConfig实际上就是对应web.xml中的Filter配置信息,doFilter方法是一个Filter功能实现的核心。Filter处理StrutsPrepareFilter的init方法主要是初始化dispatcher,这是由于dispatcher是一个非常重要的类,但是由于如果详细解释dispatcher比较麻烦,大家有兴趣可以自行了解。

这里主要分析doFilter方法,59行处调用了工具类PrepareOperations的createActionContext创建一个action的上下文。

由于是第一次,所以会进入到else分支中,74行处通过工厂模式创建了一个ValueStack(值栈),大家到这里debug一下就知道这里创建的实例实际上是一个OgnlValueStack对象,而它就是Struts2的ognl表达式注入的元凶(后面我们分析漏洞的时候再进入该类中看下源码)。随后又将request对象、response对象以及servlet上下文放入了OgnlValueStack中的Context属性(一个map),并用该Context又创建了action上下文并返回。

回到StrutsPrepareFilter的doFilter方法中,assignDispatcherToThread将当前dispatcher放入到当前本地线程中,setEncodingAndLocale用于设置请求的本地化,语言以及编码格式,不用管。需要注意的是wrapRequest方法,该方法根据请求类型的不同,采用不同的request包装类,当为'multipart/form-data'时代表文件下载,将使用JakartaMultiPartRequest类,此类与S2-045有关,我们之后的文章再详细分析。findActionMapping方法用于构建action的映射类,最后调用do.Filter进入到下一个过滤器(这里是StrutsExecuteFilter)。

更进findActionMapping函数:

同样的,大家在184行处debug一下就知道了这里调用的是DefaultActionMapper的getMpping方法,跟进:

该方法内就是通过uri来解析对应的action配置信息,例如namespace、actionname、method。parseNameAndNamespace方法根据uri和配置文件中的namespace进行对比来判断namespace,S2-057漏洞就和该函数相关(后面的文章分析)。handleSpecialParameters是struts2识别请求url后的特殊参数然后做一些特殊做处理,S2-016、S2-017、S2-018都与此函数相关。会识别如下四种特殊字符:

parseActionName方法用于,当项目开启了动态方法调用时,也就是struts.xml配置了常量<constant name="struts.enable.DynamicMethodInvocation" value="true" />时,识别 !后面字符串作为action的method。

到这里StrutsPrepareFilter就分析完了,主要工作有两点:一是为struts2执行做一些相关的准备,如加载相关的配置信息。二是为struts2的request请求处理相关的信息。

接下来到了StrutsExecuteFilter,该拦截器才是真正执行action请求的,进入doFilter方法:

跟进executeAction发现实际上是调用了Dispatcher.serviceAction,这里直接跟进serviceAction就好了:

值得注意的是如果此时的mapping中已经有了Result说明该请求时直接访问的页面,将会进入if分支,执行StrutsResultSupport.execute方法,关于这个方法,我们后面会讲到。

StrutsActionProxy的execute方法中实际上又是通过调用了DefaultActionInvocation的invoke来执行action的

也就是说Dispatcher类是重要的调结者,而DefaultActionInvocation类才是执行action类实例的行动者。action代理类(ActionProxy类)则是他们之间的中间人。相当于Dispatcher类通过action代理类(ActionProxy类)命令DefaultActionInvocation类去执行action类实例。跟进DefaultActionInvocation的invoke方法:

struts2自动的默认拦截器中也存在很多问题,不仅只有S2-019,还有S2-020(ParametersInterceptor)、S2-021(ParametersInterceptor)、S2-022(CookieInterceptor)

跟进invokeActionOnly中又通过调用了invokeAction,跟进invokeAction:

大家可以看到invokeAction中才是真正执行action的地方,不过由于版本的不同,高版本中该函数内并不是通过反射机制而是ognl表达式来的执行的action。执行完action中的方法后将会返回一个Result对象。Result对象就是将mvc模式中controller层和view层连接起来的地方。

回到DefaultActionInvocation的invoke方法中,执行完action后就是操作返回的result了。

跟进executeResult方法:

createResult()就是我们之前说的,执行完action后如果返回的是字符串,需要去配置文件(struts.xml)中找对应的Result类型,如果没有设置type默认是dispatcher,对应着的Result类是org.apache.struts2.result.ServletDispatcherResult。所有的Result类都会继承StrutsResultSupport类,这里execute方法时父类StrutsResultSupport的(前面提到过这个),跟进:

1.conditionalParse用于处理房前的location,也就是跳转地址,里面会判断location是否有ognl表达式,有的话将会执行表达式,也是因为可能是动态返回结果。我们后面分析漏洞时后详细介绍该函数。

2.接着就是调用StrutsResultSupport子类的doExecute了。

Struts2自带多个Result类型,在struts-default.xml中可以看到

strut2的部分漏洞也是和他们相关的,比如说S2-031就和xslt这个返回类型有关。

这里我们只进入ServletDispatcherResult类中的doExecute看看

里面的内容比较简单,大概就是通过请求转发到下一个servlet(jsp本身就是一个servlet)。到这里struts2的基本工作流程就分析完了

参考文章:

https://www.cnblogs.com/hayasi/category/869760.html

https://cwiki.apache.org/confluence/display/WW/Security+Bulletins

Struts2系列漏洞起始篇的更多相关文章

  1. 【中间件】Struts2系列漏洞POC小结

    #Struts2-045 ''' CVE-2017-5638 影响范围:Struts 2.3.5 – Struts 2.3.31,Struts 2.5 – Struts 2.5.10 触发条件:基于J ...

  2. 程序世界系列之-struts2安全漏洞引发的安全杂谈(上)

    目录: 1.讨论关于struts 安全问题. 2.黑客文化. 3.如何降低安全漏洞的出现. 4.忠告建议. 题记: 这篇文章本来很早应该和大家见面的,中间由于个人原因调整了系列文章发布时间,实属罪过. ...

  3. margin系列之内秀篇(二)

    本系列摘自  飘零雾雨的博客 可挖掘性 之前已经写过一篇关于 margin 应用场景的文章:margin系列之内秀篇,当然,它的应用场景会远大于文中所述,无法一一列举. 所以本篇权当是对此的补遗好了, ...

  4. 跟Google学习Android开发-起始篇-构建你的第一个应用程序(4)

    说明:此系列教程翻译自Google Android开发者官网的Training教程,利用Chome浏览器的自动翻译功能作初译,然后在一些语句不顺或容易造成误解的地方作局部修正.方便英文不好的开发者查看 ...

  5. 【SSH框架】之Struts2系列(二)

    微信公众号:compassblog 欢迎关注.转发,互相学习,共同进步! 有任何问题,请后台留言联 1.Struts2常量配置 (1).Struts2默认常量配置文件路径,如下图: (2).Strut ...

  6. 【SSH框架】之Struts2系列(一)

    微信公众号:compassblog 欢迎关注.转发,互相学习,共同进步! 有任何问题,请后台留言联系 1.Struts2框架概述 (1).什么是Struts2 Struts2是一种基于MVC模式的轻量 ...

  7. Mysql高手系列 - 第10篇:常用的几十个函数详解,收藏慢慢看

    这是Mysql系列第10篇. 环境:mysql5.7.25,cmd命令中进行演示. MySQL 数值型函数 函数名称 作 用 abs 求绝对值 sqrt 求二次方根 mod 求余数 ceil 和 ce ...

  8. Mysql高手系列 - 第24篇:如何正确的使用索引?【高手进阶】

    Mysql系列的目标是:通过这个系列从入门到全面掌握一个高级开发所需要的全部技能. 欢迎大家加我微信itsoku一起交流java.算法.数据库相关技术. 这是Mysql系列第24篇. 学习索引,主要是 ...

  9. javascript面向对象系列第三篇——实现继承的3种形式

    × 目录 [1]原型继承 [2]伪类继承 [3]组合继承 前面的话 学习如何创建对象是理解面向对象编程的第一步,第二步是理解继承.本文是javascript面向对象系列第三篇——实现继承的3种形式 [ ...

随机推荐

  1. Qt编写控件属性设计器5-属性中文

    一.前言 在上一篇文章中就提到过,使用qtpropertybrowser来加载属性,对应加载到的属性是英文的,也就是控件类中Q_PROPERTY描述的变量名称,如何变成中文或者其他语言显示呢?这个就需 ...

  2. Spring Boot使用JDBC方式连接MySQL

    首先去spring官网下载一个名为test的Spring Boot项目模板:https://start.spring.io/ 然后在mysql中的testdb数据库中新建一张名为test_user的表 ...

  3. Java读取Excel文件(包括xls和xlsx)的样例程序

    样例程序如下所示,其中: parseXls()函数依赖于jxl,只能读取xls格式文件: parseExcel()函数依赖于apache poi,能够读取xls和xlsx两种格式的文件. jxl的依赖 ...

  4. 第一章 Shiro简介——《跟我学Shiro》

    转发地址:https://www.iteye.com/blog/jinnianshilongnian-2018936 目录贴:跟我学Shiro目录贴 1.1  简介 Apache Shiro是Java ...

  5. Egret入门学习日记 --- 第一篇 (引擎的选择)

    第一篇 (引擎的选择) 我人比较笨,得慢慢学,我就一点一点来好了. 首先,我个人喜欢游戏.网页开发相对游戏开发来说,网页开发实在太枯燥了,没劲.所以打算转游戏开发了. 游戏开发要选择游戏引擎,我去看了 ...

  6. Flarum 安装问题 编译安装 fileinfo.so

    大部分人上传 会遇到文件没有权限这一问题 ,这个好解决 下边是服务器 php.ini 扩展 fileinfo 由于php 版本是7.1.8 最新的 又是用的一键环境安装 所以 没有安装这个扩展 1.去 ...

  7. go timer定时器 WaitGroup用法

    参考文章: timer定时器: https://www.cnblogs.com/oxspirt/p/7107312.html WaitGroup用法: https://studygolang.com/ ...

  8. iframe里访问父级里的方法属性

    window.parent.attributeName;  // 访问属性attributeName是在父级窗口的属性名 window.parent.Func();  // 访问属性Func()是在父 ...

  9. yum 安装 epel-release 后出现yum doesn’t have enough cached data to continue错误的解决方案

    工作中需要部署docker,由于是内网环境,无法直接访问外网,于是考虑在内网搭建yum私有源进行安装,内网服务器操作系统为centos 7.4.根据docker的官方安装方式进行安装时,要求安装 ep ...

  10. 通过js操作,将div设置为contenteditable的内容设为全选状态

    因为div设置为contenteitable可编辑的文本内容用 select()选择全部内容不生效,所以只能用下列方法: 先 creatTextRange或者 createRange <div ...