不安全的中间件——Tomcat

在web安全中,中间件安全也是非常重要的一部分,而中间件的安全问题主要来自两个方面:一个是中间件本身的开发缺陷导致的安全问题,另一个是开发或运维人员在使用时进行了错误的配置而导致的安全问题。Tomcat也是众所周知的,应用最广泛的中间件了,那么接下来,我们就针对Tomcat中间件进行常见的安全问题及风险进行总结归纳。 

版本管理

Tomcat是属于Apache下的一个项目分支,类似于这种的软件项目,官方一般都会同时维护多个版本分支,一般新的产品特性会被更新在最新的大版本中,对于修复bug及漏洞这种就会在旧版本的分支中进行更新,这样就允许开发或运维人员在不破坏原有的生产环境的情况下完成对当前版本软件的更新。

例如当前你使用的Tomcat版本是6.0.20,当需要进行升级更新时,在6.0版本分支中寻找新的版本(如6.0.25),升级到最新的漏洞修复版本,如果在性能、功能等其他方有新的需求时,没有必要升级到Tomcat7版本。

对于Tomcat的使用者及维护者来说,就应该密切关注Tomcat官网中对安全漏洞和新版本的发布公告(https://tomcat.apache.org/security.html)及时了解漏洞信息及新版本的更新信息,这样就能及时判断自己所使用的版本是否存在安全隐患,是否需要更新。

 

运行环境

首先我们必须保证运行Tomcat的用户权限不能是高权限,比如windows下的administrator和Linux下的root用户或用户组,建议在使用Tomcat时创建一个Tomcat专属用户,在保证不影响业务正常使用的情况下将该用户权限降至最低,此外还要根据业务需求来对应用涉及的文件目录文件夹的读取、写入及执行的权限进行详细的分配。这样一来,就能很大程度上增加攻击者的攻击成本。

 

安全配置

Example应用

Tomcat在安装部署后,在webapps默认存在一个examples目录,该目录正如其文件名一样,提供一些示例应用让使用者来了解Tomcat的特性及功能。这些样例在业务上线后并没有什么用处,建议部署tomcat后,删除其中的样例文件(ROOT, balancer,jsp-examples, servlet-examples, tomcat-docs, webdav),避免信息泄露和其他潜在的安全风险。

这些样例中的session样例(/examples/servlets/servlet/SessionExample)允许用户对session进行操纵,因为session是全局通用的,所以用户可以通过操纵session获取管理员权限,存在一定的安全风险,不过这种基本上只有在一些比较老的不安全系统中才有可能出现,利用条件比较苛刻。

我们编写3个页面来模拟一般网站身份验证的过程。

login.jsp

login1.jsp

<% 
if(request.getParameter("username") != null && request.getParameter("password")!= null) {
   String username =request.getParameter("username");     
   String password =request.getParameter("password");    
      //验证身份     
   if (username.equals("admin")&& password.equals("admin")) {       
      session.setAttribute("login","admin");         
      response.sendRedirect("index.jsp");     
   }else {      
      response.sendRedirect("login.jsp");     
   }  
} 
%>

index.jsp

<% 
if(session.getAttribute("login")!= null &&((String)session.getAttribute("login")).equals("admin")){  
   out.println("Login"); 
} else{
    response.sendRedirect("login.jsp");
}
%>

我们将写好的三个页面部署到tomcat上,我们首先访问一下index.jsp页面看看,访问之后跳转至login.jsp。

我们利用examples的session servlet功能操作一下session,将login的值改成admin,生成session。

提交成功之后我们再来访问一下index.jsp,发现不会跳转,直接限制Login,说明我们生成的session有效,通过操作session绕过了登录。

Admin管理页面

Tomcat的admin console全称是Tomcat WEB Server Administration ToolT,该模块在Tomcat 5.0.4版本之前都是默认安装的,5.0.4之后版本默认存在该目录,但是功能并不全,直接使用,从5.5版本开始作为可选模块进行安装,安装后的默认路径为/admin,与manager配置相同,在tomcat-user.xml文件中进行账号密码的配置。该模块实现了通过web方式对tomcat服务、已部署的应用程序、连接池和其他资源的管理,方便运维及开发人员的管理和操作。

登录后,在下图中的功能,可以配置虚拟目录,将服务器上的物理路径与web路径进行映射,从而可以实现对任意目录的访问。

但是需要注意的是,这里需要在tomcat配置中开启列目录,将false改为true,否则就会出现如下情形,无法利用该方式读取文件。

利用该方法进行文件读取的攻击方式现在已经几乎绝迹,也只能在一些内网中找到这样的古董系统,至于古董系统有没有开放administration tool,就要看命了!

Manager管理页面

Manager管理平台我们都很熟悉,也是最常见的,包含多个管理模块,开启后方便开发及运维人员对tomcat项目发布进行管理。Manager管理平台默认安装后是没有设置登录口令的,需要在tomcat-user.xml文件中进行配置,与上文的admin管理平台相同。

在登录manager后台时,tomcat使用的是Basic认证方式,在请求的数据包中包含一个Authorization字段,该字段的值为账号密码的base64编码,如图所示:

Tomcat manager包含4个不同的角色:

  • manager-gui:允许访问html页面接口(即URL路径为/manager/html/*)
  • manager-script:允许访问纯文本接口(即URL路径为/manager/text/*)
  • manager-jmx:允许访问JMX代理接口(即URL路径为/manager/jmxproxy/*)
  • manager-status:允许访问Tomcat只读状态页面(即URL路径为/manager/status/*)

其中manager-gui、manager-script、manager-jmx三个角色均具备manager-status角色的权限,即这三种角色权限无需再额外添加manager-status权限。实际使用中只需配置manager-gui角色通过html页面的形式访问管理平台。下面我们来分别简述一下manager的这4个角色。

manager-gui

manager-gui是最常见也是最常用的模块,我们通常访问/manager/html看到的页面就是manager-gui,不同版本之间的功能都大同小异,对于攻击者来说,最直接的方式就是通过部署应用的功能来部署war包,从而部署webshell后门应用。

manager-script

该模块下包含了所有管理功能的接口,攻击者也可以通过这个接口来对tomcat应用发起攻击。下面我们来列举几个常用的功能:

/manager/text/deploy?path=/xxx

部署web应用,需要注意的是这里部署的文件为war包,在请求时需要使用PUT方法。

/manager/text/list

查看所有部署的应用。

/manager/text/serverinfo

查看服务器信息。

详细功能,可以在tomcat的帮助文档中查看:http://{ip}:{port}/docs/manager-howto.html

manager-status

该模块访问后可以看到一些与服务器相关的信息,没有太多有实际价值的信息,也只能帮助收集到一些简单的信息。

manager-jmx

Tomcat使用JMX管理方式,在Tomcat的自带应用manager就是使用了JMX方式来管理Tomcat,以此完成Web应用的动态部署、启动、停止。在tomcat的帮助文档中,提供了下面几种方式发送请求获取相应的信息:

query命令:http://[ip]:[port]/manager/jmxproxy/?qry= 
get命令:http:// [ip]:[port]/manager/jmxproxy/?get=
set命令:http:// [ip]:[port]/manager/jmxproxy/?set=
invoke命令:http:// [ip]:[port]/manager/jmxproxy/?invoke=

访问上面的地址,我们就可以看到不同的信息,通过向不同的参数传递特定的参数,也可以获取到一些敏感信息。不加参数时查询到的是所有的MBeans的内容,加参数之后就可以查看到具体的MBeans的内容。

例如:

http://[ip]:[port]/manager/jmxproxy/?qry=*%3atype=User%2c*

该查询可以看到设置的tomcat-user.xml中配置的账号密码,甚至还可以通过set命令修改账号密码,来设置一个后门账号。

除此之外,Tomcat下还可以开启JMX Service,默认情况下Tomcat是不开启jmx service的,开启JMX Service需要对/bin目录下的Catalina.bat/Catalina.sh文件进行更改。

Catalina.bat:

set CATALINA_OPTS=-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=10001 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false

Catalina.sh:

CATALINA_OPTS="$CATALINA_OPTS-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=10001 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false

这里没有对jmx连接设置身份认证,从安全角度来说,需要设置身份认证,设置认证时,需要在配置中添加:

-Dcom.sun.management.jmxremote.password.file=path/jmxremote.password
-Dcom.sun.management.jmxremote.access.file=path/jmxremote.access

在jdk的安装目录/jre/lib/management目录下,有相应的jmxremote.access文件,将文件最后两行显示【monitorRole和controlRole】的注释取消,其中monitorRole为只拥有只读权限的角色,controlRole有更高权限:读写等。默认情况下该目录下不存在jmxremote.password 文件,我们可以将jmxremote.password.template文件改名,或者复制出来一份再改名即可,然后修改jmxremote.password文件。同样将文件最后两行显示【monitorRole和controlRole】的注释取消。然后保存。

配置后之后,我们就可以启动Tomcat,启动之后先查看一下我们配置的jmx是否正常开启。

通过java自带的jconsole来连接我们配置jmx端口。

连接之后,我们可以通过jconsole的页面看到许多的敏感信息,这些与前面的manager-jmx类似。

同样的可以通过查看MBean看到tomcat manager配置的账号密码,除此之外,还能添加账号,从而添加后门账号。

在Catalina->Valve->localhost->AccessLogValve中,可以实现对日志备份的操作,通过前面获取到的Tomcat物理路径,根据webapps目录以及从MBean中获取到的已安装的应用,可以构造出web路径。我们在进行日志备份时,需要备份到不存在的文件中,如果文件已存在,该功能不会对已存在的文件进行覆盖或追加。

AJP协议

由于tomcat的html和图片解析功能相对其他服务器如apche等较弱,所以,一般都是集成起来使用,只有jsp和servlet服务交由tomcat处理,而tomcat和其他服务器的集成,就是通过ajp协议来完成的。Web客户访问Tomcat服务器上JSP组件的两种方式如图所示。

在tomcat中有两个连接器,一个是监听在8080端口,负责建立web的HTTP连接,一个是监听在8009端口,负责Tomcat与其他HTTP服务器进行集成。配置文件server.xml中,关于AJP的配置项默认是关闭的,若需要开启,将注释符去掉,重新启动Tomcat即可。

相对而言,AJP协议的攻击利用方式较少,目前爆出的可直接利用的就是CVE-2020-1938(AJP文件包含漏洞)。

Debug模式

Tomcat默认情况下,debug模式是不开启的,如果需要开启debug时,要对/bin目录下的Catalina.bat/Catalina.sh文件进行修改: Windows下在Catalina.bat中添加:

SET CATALINA_OPTS=-server -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000

Linux下在Catalina.sh中对jpda相关的内容进行修改

修改完成后,在startup.sh文件中添加jpda,如下所示:

全部修改完成后,我们就可以启动tomcat了,此时debug模式就正常启动了。我们通过nmap对tomcat debug端口进行探测,发现该端口service信息为jdwp。

实际上Tomcat的debug模式也是调用的jvm的调试接口,正如配置文件中显示的那样,最终是通过调用jdwp来实现。

JPDA(Java Platform Debugger Architecture,Java平台调试架构) ,由Java虚拟机后端和调试平台前端组成, JPDA为Java平台上的调试器定义了一个标准的体系结构。该体系结构包括3个主要组成部分:JVM TI(Java虚拟机工具接口)、JDI(Java调试连线协议)和JDWP(Java调试接口)。

在一些低版本的jdk中会存在漏洞,可以通过jdwp来执行系统命令。所以对Tomcat的安全配置时,要关闭debug模式。

 

历史漏洞

CVE-2016-8735

漏洞说明:

该漏洞与之前Oracle发布的mxRemoteLifecycleListener反序列化漏洞(CVE-2016-3427)相关,是由于使用了JmxRemoteLifecycleListener的监听功能所导致。而在Oracle官方发布修复后,Tomcat未能及时修复更新而导致的远程代码执行。

该漏洞所造成的最根本原因是Tomcat在配置JMX做监控时使用了JmxRemoteLifecycleListener的方法。

影响版本:

漏洞利用:

这里我们使用ysoserial来进行漏洞攻击利用

CVE-2017-12615 & CVE-2017-12616

漏洞说明:

该漏洞称之为Tomcat PUT方法任意写文件漏洞,类似IIS的PUT上传漏洞。该漏洞可以利用HTTP的PUT方法直接上传webshell到目标服务器,从而获取权限。该漏洞是高危漏洞,在Tomcat的web.xml默认情况下不存在该漏洞,但是一但开发者或者运维人员手动讲web.xml中的readonly设置为false,可以通过 PUT / DELETE 进行文件操控。

CVE-2017-12616是对CVE-2017-12615的绕过,影响 7.x、8.x、9.x版本。

影响范围:

7.0.0 – 7.0.79

漏洞利用:

构造PUT上传数据包,上传时内容可以写jsp一句话木马,上传返回201时,表示上传成功,访问该文件即可。

上传绕过方法:

Windows:

1、利用/shell.jsp::$DATA的方式绕过 2、/shell.jsp%20,空格绕过 3、/shell.jsp/ , Tomcat在处理文件时会删除最后的/

Linux:

/shell.jsp/ , Tomcat在处理文件时会删除最后的/

CVE-2019-0232

漏洞说明:

该漏洞是由于Tomcat CGI将命令行参数传递给Windows程序的方式存在错误,使得CGIServlet被命令注入影响。

该漏洞的利用条件较为苛刻,需同时满足下列条件:

  1. 系统为Windows
  2. 启用了CGI Servlet(默认为关闭)
  3. 启用了enableCmdLineArguments(Tomcat 9.0.*及官方未来发布版本默认为关闭)

影响范围:

9.0.0.M1-9.0.17
8.5.0-8.5.39
7.0.0-7.0.93

漏洞利用:

CVE-2020-1938

漏洞描述:

漏洞是Tomcat AJP协议存在缺陷而导致,攻击者利用漏洞可以构造特定参数,读取服务器webapp/ROOT下的任意文件。若目标服务器同时存在文件上传功能,攻击者可进一步通过文件包含实现远程代码执行。

影响范围:

Apache Tomcat 6
Apache Tomcat 7 < 7.0.100
Apache Tomcat 8 < 8.5.51
Apache Tomcat 9 < 9.0.31

漏洞利用:

使用已公开的漏洞利用工具来进行漏洞利用。

(完)