zoukankan      html  css  js  c++  java
  • Struts2系列漏洞起始篇

    前言

    到目前位置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

  • 相关阅读:
    Endnote
    C#在子线程Thread中使用await会出问题
    httpwebrequest抓取网页数据非字符串时要使用流直接写文件
    此流不支持查找操作
    http请求头中Referer的含义和作用
    C# Net Core 使用 ClientWebSocket 实现 WebSocket 客户端
    C# 实现WebSocket服务端实例
    WebSocket 协议初探
    WebSocket技术
    WebSocket的使用
  • 原文地址:https://www.cnblogs.com/jinqi520/p/10813466.html
Copyright © 2011-2022 走看看