关于发布的CVE-2013-2251漏洞,strust远程代码执行漏洞

(*该漏洞影响版本:Struts 2.0.0 – Struts 2.3.15)
(*该博客仅仅只是记录我工作学习时遇到的问题,仅供参考!)
(*如果,描述中可能存在错误,请多指教!)

在昨天在对我目前负责的那个项目进行日常维护的时候,系统被别人攻克,上传了一个.txt文件,他人可以直接访问这个项目下txt文件,就可以获取到txt文件内的内容。

首先,介绍下我目前维护的项目,使用的是strust2.1+hibernate3.0架构模式,也就是javaweb+SSH框架,不过为了简化,并没有添加spring框架。也并没有使用现在的springMVC模式!
至于数据库,运用的是Mysql,因为mysql的轻便,深受国内用户的喜好!服务器,使用的是tomcat,也没什么好介绍的!

接下来,我先演示我所负责的项目,是如何被攻克的!

首先,打开strust漏洞监测工具:将我目前项目网址放在action框中:

如下:

关于发布的CVE-2013-2251漏洞,strust远程代码执行漏洞_第1张图片

一般,使用SSH框架,都是由通过strust.xml文件定义的action进行控制,然后进行,验证,如果验证通过,会跳转到success.jsp,如果没有通过验证,则会回退到login.jsp。

当然,通过这个检测工具可以看到,我所负责的项目,存在strust2远程代码执行漏洞,编号S-016!

这里我上传一个test文件,结尾是.txt文件的后缀名。然后点击上传:

等工具提示上传成功之后,在访问该目录下的test.txt文件,就可以显示到这个

当时遇到这个问题,顿时头都大了,前段时间,我和别人讨论过php通过上传文件漏洞,上传一个被截断的.JPG格式的木马,获取服务器权限的一个例子。

后来我上网查了下资料,原来这个漏洞,早已在2013年7月份,就公布出来,该漏洞具体情况如下:

Bugtraq ID:61189
CVE ID:CVE-2013-2251
CNCVE ID:CNCVE-20132251

漏洞发布时间:2013-07-16
漏洞更新时间:2013-07-16

漏洞起因
输入验证错误
危险等级
高

影响系统
Apache Struts 2.0.0-2.3.15

不受影响系统

危害
远程攻击者利用漏洞以应用程序上下文执行任意代码。
CVSSv2:

攻击所需条件
攻击者必须访问Struts应用。

漏洞信息
Apache Struts框架是一个基于Java Servlets,JavaBeans, 和 JavaServer Pages (JSP)的Web应用框架的开源项目。
Apache Struts 2 DefaultActionMapper在处理短路径重定向参数前缀"action:"/"redirect:"/"redirectAction:"时存在命令执行漏洞,由于对"action:"/"redirect:"/"redirectAction:"后的URL信息使用OGNL表达式处理,远程攻击者可以利用漏洞提交特殊URL可用于执行任意Java代码。

测试方法
1,简单表达式
http://host/struts2-blank/example/X.action?action:%25{3*4}
http://host/struts2-showcase/employee/save.action?redirect:%25{3*4}
2,命令执行
http://host/struts2-blank/example/X.action?action:%25{(new+java.lang.ProcessBuilder(new+java.lang.String[]{'command','goes','here'})).start()}
http://host/struts2-showcase/employee/save.action?redirect:%25{(new+java.lang.ProcessBuilder(new+java.lang.String[]{'command','goes','here'})).start()}
http://host/struts2-showcase/employee/save.action?redirectAction:%25{(new+java.lang.ProcessBuilder(new+java.lang.String[]{'command','goes','here'})).start()}
安全建议

厂商解决方案 
Apache Struts 2.3.15.1已经修复此漏洞,建议用户下载更新:
http://struts.apache.org/

漏洞提供者
Takeshi Terada of Mitsui Bussan Secure Directions, Inc.

漏洞消息链接
http://struts.apache.org/release/2.3.x/docs/s2-016.html
http://struts.apache.org/release/2.3.x/docs/version-notes-23151.html
http://packetstormsecurity.com/files/122442/Apache-Struts-2-Open-Redirection-Command-Execution.html
文章来源:http://www.venustech.com.cn/

当然,解决办法,也很简单,要么打补丁,要么提升strust的版本,当然,这两种方法带来的工作量都是很大的,不是那么容易去做,再说以我目前的技术,很难快速的把这个问题解决掉!

后来,我发现,该漏洞是通过访问上传的文件,其后缀名是.txt,格式,如果我不让他访问这个文件,是不是可以解决掉这个问题,只要通过strust拦截器进行拦截就好。(当然,该项目中也是加入了拦截器,但是该拦截器只是拦截.jsp格式的文件,并没有将其他格式的文件,进行拦截!)

当 有了这个想法之后,接下来的一切都好解决了,对项目拦截器,进行优化就好!

首先,贴上我原本没有优化的web.xml代码:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>WebJourManage</display-name>
  <welcome-file-list>
    <welcome-file>login.html</welcome-file>
    <welcome-file>login.htm</welcome-file>
    <welcome-file>login.jsp</welcome-file>
  </welcome-file-list>
  <filter>
    <filter-name>struts2</filter-name>
    <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>struts2</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  <filter>
    <filter-name>loginauth</filter-name>
    <filter-class>LoginFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>loginauth</filter-name>
    <url-pattern>*.jsp</url-pattern>
  </filter-mapping>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
  </context-param>
</web-app>

可以看到,在这一块代码中,我只进行了对.jsp文件的拦截,并没有对其他文件进行拦截验证:

  <filter>
    <filter-name>loginauth</filter-name>
    <filter-class>LoginFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>loginauth</filter-name>
    <url-pattern>*.jsp</url-pattern>
  </filter-mapping>

至于在LoginFilter.class中,我是这样写的:

package Filter;

import javax.servlet.Filter;
 import java.io.IOException;

 import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
 import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
public class LoginFilter implements Filter {
         public void init(FilterConfig filterConfig) throws ServletException {
                 // TODO Auto-generated method stub

         }
         public void doFilter(ServletRequest request, ServletResponse response,
                        FilterChain chain) throws IOException, ServletException {
                          HttpServletRequest servletRequest = (HttpServletRequest) request;
                          HttpServletResponse servletResponse = (HttpServletResponse) response;
                          HttpSession session = servletRequest.getSession();

                          String path = servletRequest.getRequestURI();

                          String empId = (String) session.getAttribute("username");
                          if(path.indexOf("/login.jsp") > -1) {
                              chain.doFilter(servletRequest, servletResponse);
                             return;
                          }

                          if (empId == null || "".equals(empId)) {
                             servletResponse.sendRedirect("/login.jsp");
                          } else {
                             chain.doFilter(request, response);
                         }

                     }

                      @Override
                      public void destroy() {
                         // TODO Auto-generated method stub

                      }


}

这个文件会回去session中的username,即登录的用户名,如果该用户名不存在,就是跳转到login.jsp上,如果存在。(该功能就是为了验证用户是否登录。)

接下来就是在web.xml中,将

  <filter>
    <filter-name>loginauth</filter-name>
    <filter-class>LoginFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>loginauth</filter-name>
    <url-pattern>*.jsp</url-pattern>
  </filter-mapping>

这段代码改成

  <filter>
    <filter-name>loginauth</filter-name>
    <filter-class>LoginFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>loginauth</filter-name>
    <url-pattern>*</url-pattern>
  </filter-mapping>

其中:

<url-pattern>*</url-pattern>

这一块,是对所有文件进行验证!不过这样写后,还是有个问题,就是当你登录完成之后,会跳转到login.action。该login.action也被拦截,然后跳转到login.jsp上!

后来,我看了下LoginFilter.class的代码,发现这一块。

     if(path.indexOf("/login.jsp") > -1) {
         chain.doFilter(servletRequest, servletResponse);
        return;
     }

当页面为login.jsp时候,会执行:chain.doFilter(servletRequest, servletResponse);

只要在这里对login.action加入到判断语句中,就可以避免这个问题,代码如下:

     if(path.indexOf("/login.jsp") > -1||path.indexOf("/login.action") > -1) {
         chain.doFilter(servletRequest, servletResponse);
        return;
     }

就这样,问题结局了,但是该漏洞还在,文件依旧可以上传,但是如果没有登录,在访问上传的那个文件,会发现会直接跳转到login.jsp上。

总结:虽然这并不是一个很好解决这个问题的方法,但是使用访问地址重新定向到login.jsp,用一种很简单的方式,避免了服务器 提权的问题!

你可能感兴趣的:(漏洞,struts,发布,struts2.0)