Struts2 漏洞分析系列 - 初识 Struts2

 

0x00 概述

Struts2是以MVC架构为基础的WEB框架,通过WEB Filter的方式内嵌在WEB服务器中进行使用。

 

0x01 搭建

  1. 搭建一个WEB项目
  2. 通过Maven引入Struts2的依赖
    <dependencies>
      <dependency>
        <groupId>org.apache.struts</groupId>
        <artifactId>struts2-core</artifactId>
        <version>2.0.5</version>
      </dependency>
    </dependencies>
    
  3. 添加Tomcat的启动环境,配置部署的WAR包,并将Struts的依赖引入到WAR中
  4. 安装Struts2的IDEA插件(方便后续配置高亮等,直接在Plugins搜struts2即可),在resources目录下新建一个struts.xml(如果安装了插件可以直接在新建时选择XML Configuration File -> Struts Config进行创建)
    <?xml version="1.0" encoding="UTF-8"?>
    
    <!DOCTYPE struts PUBLIC
            "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
            "http://struts.apache.org/dtds/struts-2.0.dtd">
    
    <struts>
    </struts>
    
  5. 在web.xml中添加struts2的filter
    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
    </filter>
    
    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    <welcome-file-list>
          <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
    

上述步骤走完后,一个基本的struts2的环境就搭建完成了,后续只需要按需进行配置即可,完整的目录结构如下:

 

0x02 Struts2基本使用方式

2.0 action == struts2?

如果在学习Struts2相关漏洞之前有尝试过当个脚本小子用过工具去攻击存在ST2-xxx漏洞的网站,会发现实际上大部分情况下我们攻击的都是.action后缀的文件。

那么是否.action后缀的文件就一定会对应着使用了Struts2?答案是至少目前看来是的,还没有其他开源框架使用.action作为自己的一个标志,除非开发者自定义了Filter。

2.1 struts.xml

struts.xml是Struts2中的一项重要配置,所有与Struts2相关的配置都在这里进行。

默认模板如下:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
        "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
</struts>

2.1.0 include

在大型系统下必然会存在许多的配置,并且可能每个配置关联的只是一组模块,这时候如果全部写在一个xml内未必显得太过于臃肿,此时必然会考虑通过包含的语法进行解耦,Struts2也支持这种写法,通过include引入其余xml文件。

比如我有一个user.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
    <package name="wwfy" extends="struts-default">
        <action name="login" class="wwfy.user.LoginAction">
            <!--省略Action其他配置-->
        </action>
        <action name="logout" class="wwfy.user.LogoutAction">
            <!--省略Action其他配置-->
        </action>
    </package>
</struts>

后续我只需要通过include标签将其引入到struts.xml中即可进行配置:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
    <include file="user.xml"/>
</struts>

2.1.1 constant

constant标签用于设置一些内置常量的值,比如我们可能了解得最多的devMode。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
    <!--设置开发模式-->
    <constant name="struts.devMode" value="true"/>
    <!--设置编码形式为GB2312-->
    <constant name="struts.i18n.encoding" value="GB2312"/>
    <!--省略其他配置信息-->
</struts>

2.1.2 package

package标签管理某个模块下的所有action,可以将其类比为Java中的package。

属性 是否必需 描述
name 包名,作为其它包应用本包的标记
extends 设置本包继承其它包
namespace 设置包的命名空间
abstact 设置为抽象包

extends:当前包的继承包,默认情况下需要继承struts-default这个包。

namespace:命名空间,默认情况下是"",也可以理解为/,此时你的默认路由在根目录下,如果设置为/user,则当前package下的所有action都是在user目录下被匹配到。

2.1.3 action

action标签用于设置某个动作类,并且在此处会根据name自动的定义路由,也就是我们常常看到的xxx.action

属性名称 是否必须 功能描述
name 请求的Action名称
class Action处理类对应具体路径
method 指定Action中的方法名
converter 指定Action使用的类型转换器

name:当前action的名称,后续设置路由也是根据name来设置的,比如这里的name是login,那么后续的路由则是login.action。

class:当前action对应的类,这个类相当于MVC中的M和C,也就是Model层和Controller层,因为具体业务处理代码是在此类中体现的,并且此类也作为一个Bean类在后续调度中被使用。

method:将调用Action类的方法名,如果不指定的话默认调用的是Action的execute方法。

2.1.4 result

result标签用于控制返回的视图。

属性名称 是否必须 功能描述
name 对应Action返回逻辑视图名称,默认为success
type 返回结果类型,默认为dispatcher

name:设置返回值,当action class执行方法后返回对应值就会在此处根据name属性进行匹配,匹配上了就返回对应视图。

<result name="success">hello.jsp</result>
<result name="error">index.jsp</result>

2.1.5 interceptors

Struts2中有一个拦截器的概念,类似于WEB容器中的Filter,但又有点不一样,拦截器用于在每个请求到达真正的Action之前进行一系列的预处理,并在请求结束后进行一系列的销毁动作。

Struts2内置了一系列的拦截器,并且会根据你的Action设置对应的拦截处理的操作,但是开发者依然可以自定义拦截器,通过interceptors标签即可自定义拦截器。

<interceptors>
    <interceptor name="拦截器名" class="拦截器类"/>
    <interceptor-stack name="拦截器栈名">
        <interceptor-ref name="拦截器名">
    </interceptor-stack>
</interceptors>

2.1.6 示例

<?xml version="1.0" encoding="UTF-8" ?>  
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts  
Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd">  
<struts>  
  <package name="default" extends="struts-default">  

    <action name="product" class="com.javatpoint.Product">  
      <result name="success">welcome.jsp</result>  
    </action>  

  </package>  
</struts>

上面是一个最基础的例子,其设置了一个action,名为product,后续如果要访问实际上就是通过product.action访问它。

并且设置了class为com.javapoint.Product,这表明所有product.action的请求将交由Product#execute方法来处理(因为这里没有通过method特指方法)。

最后设置了一个result标签,此时当Product#execute返回success时则会返回welcome.jsp这个视图,在welcome.jsp中可以用Struts特有的标签来获取上下文的对象信息,用于输出定制化的界面。

(完)