0x01:漏洞简介
部分版本 Apache Tomcat 由于在验证文件路径时存在缺陷,如果 readonly 参数被设置为 false(这是一个非标准配置),并且服务器允许通过 PUT 方法上传文件,那么攻击者就可以上传含有恶意 JSP 代码的文件。通过不断的发送请求,攻击者可以利用条件竞争漏洞,使得 Tomcat 解析并执行这些恶意文件,从而实现远程代码执行。
该漏洞的利用具有以下两个前提:
-
Tomcat 启用 PUT 方法(在 Tomcat 的 default servlet 配置中将 readonly 设置为 false)。
-
Tomcat 运行在大小写不敏感的操作系统上,比如 Windows。
0x02:影响范围
-
11.0.0-M1 <= Apache Tomcat < 11.0.2
-
10.1.0-M1 <= Apache Tomcat < 10.1.34
-
9.0.0.M1 <= Apache Tomcat < 9.0.98
0x03:环境搭建
环境准备
靶机环境:Windows 7 - IP 172.16.0.102
攻击机环境:Kali Linux - IP 172.16.0.103
0x0301:靶机环境搭建
靶机:Windows 7 服务器配置概览
Java JDK 环境:openlogic-openjdk-8u432-b06-windows-x64.zip
Apache Tomcat 环境:apache-tomcat-9.0.63.zip
笔者上面提供了一个 Java JDK 的二进制安装包,解压后添加到环境变量中即可,对应的 Java 版本截图如下:
笔者还提供了一个 9.0.63 的 Apache Tomcat 安装包,也是下载后解压添加到环境变量中即可使用,其版本信息如下(安装方式参考:环境配置 - Java - Apache Tomcat 安装与配置):
除了安装上面这两个环境外,我们还需要修改一下 Apache Tomcat 的配置,将 default servlet 的 readonly 配置修改为 false,开启 Tomcat 的 PUT 功能。(漏洞的前置条件之一)
Tomcat 的配置路径在其安装路径的 /conf/web.xml
:
以记事本的方式打开它,然后搜索下面的内容:
<servlet-name>default</servlet-name>
然后在这里添加下面的配置,将 DefaultServlet 的 readonly 参数设置为 false:
<init-param>
<param-name>readonly</param-name>
<param-value>false</param-value>
</init-param>
0x0302:攻击机环境搭建
攻击机:Kali Linux 服务器配置概览
漏洞 POC - 本地存储:CVE-2024-50379 - POC.zip
漏洞 POC - 官方地址:https://github.com/SleepingBag945/CVE-2024-50379
攻击机中没有什么需要配置的东西,从上面那两个地址中挑一个,将漏洞对应的 POC 上传到靶机中即可,POC 用法如下(下面复现时候会演示):
./CVE-2024-50379 -u http://192.168.2.245:8080 -f shell.jsp -p ggsl.jsp
# -f shell.jsp => 本地要上传的文件
# -p ggsl.jsp => 保存到目标服务器上的名称(路径)
# -u => Tomcat 服务器的 url
0x04:漏洞复现
0x0401:开启靶机的 Tomcat 服务
首先来到靶机中,在命令行中输入下面的命令,运行 Tomcat 服务:
startup
然后我们在攻击机中访问靶机的 8080 端口,看看能不能看到靶机的 Tomcat 服务:
http://172.16.0.102:8080
0x0402:CVE-2024-50379 漏洞复现
此漏洞的复现十分简单,本质上是一个条件竞争漏洞。我们需要开启两个线程,一个线程不断尝试向 Tomcat 提交包含恶意代码的 JSP 脚本文件,另外一个线程不断的向 Tomcat 请求我们上传的 jsp 文件,如果请求成功的话,jsp 中的恶意代码就会被执行,攻击也就成功了。
上面这个流程很繁琐,但好在,已经有大佬帮忙写好了 POC 了(笔者上面提供的那个),至于恶意脚本,就看个人编程能力了。不过笔者在刚刚提供的那个 POC 中包含了一个测试用的恶意脚本,内容如下:
<% Runtime.getRuntime().exec("calc.exe");%>
该代码在执行后会让 Windows 电脑弹出一个计算机。
然后我们输入下面的命令,使用 CVE-2024-50379 的 POC,尝试将我们的 test.jsp 上传到目标的 Tomcat 服务器上(运行后需要等待一会):
chmod +x CVE-2024-50379_linux_amd64 # 为 POC 赋予执行权限
./CVE-2024-50379_linux_amd64 -u http://172.16.0.102:8080 -f test.jsp -p test.jsp
# -u http://172.16.0.102:8080 => 这个是我们靶机 Tomcat 的地址
# -f test.jsp => 这个是我们想要上传的文件名
# -p test.jsp => 这个是期望服务端保存的文件名,随意都行
如上,运行 POC 后等待一会显示 利用成功:http://172.16.0.102:8080/test.jsp
,就证明攻击成功了。
现在,只要我们只要一使用浏览器访问上面这个地址,靶机中就会执行 test.jsp 文件,就会弹出一个计算器(笔者这里就通过 Linux 的 curl
命令来模拟浏览器访问啦):
0x05:漏洞分析
下面我们来分析一下这个漏洞产生的原因(不涉及 Tomcat 源码,小白也可轻松看懂)。我们先来了解一下 Tomcat 上传文件的流程:
在 Tomcat 中,当用户刚上传一个 test.JSP(注意,后缀是大写的),然后在一个很短的时间对这个文件发起访问,Tomcat 会调用 getCanonicalPath 方法来获取这个文件的名称,此时返回的名称是 test.jsp。当过一小会后,再次请求该文件时,getCanonicalPath 方法就会返回 test.JSP。
以上其实就是本次漏洞产生的原因(是不是有点蒙),我知道你的疑问:
-
test.JSP 与 test.jsp 有啥差别?
Tomcat 是禁止直接上传 .jsp
文件的,因为后缀为小写的 .jsp
文件,当用户访问时,Tomcat 会交给 jspServlet 处理,它会直接执行文件中的代码。而当用户访问后缀为大写的 .JSP
文件时,Tomcat 会交给 defaultServlet 处理,defaultServlet 在处理文件时,会直接把文件内容返回给浏览器,并不会直接执行它。
然后我们再来了解一下 Tomcat defaultServlet 的 readonly 参数:该参数是用来控制 default servlet 是否允许读写的,默认情况下,readonly 值为 true,表示 default servlet 仅支持读取文件,不允许通过 HTTP 请求(如 PUT 或 DELETE)修改或删除文件。当该参数设置为 false 时,就代表允许 default servlet 进行读写操作,这意味着客户端可以通过 HTTP 请求(如 PUT 或 DELETE)上传,修改或者删除服务器上的文件。
知道了以上信息后,我们再来梳理一下这个漏洞的利用过程:
-
因为服务端配置问题,导致用户可以通过 HTTP 请求上传文件。
-
攻击者开启一个线程,不断的向服务端上传 test.JSP 文件。(上传的是大写的 JSP 哈)
-
攻击者又开启一个线程,不断的尝试请求服务端的 test.jsp 文件。
-
服务端收到请求后尝试找 test.jsp 文件,但是由于 Windows 系统大小写不敏感的特性,它找到了 test.JSP 文件(对于 Windows 系统,
abc.txt
与ABC
.txt 其实是一个文件),然后它就把 test.JSP 文件内容当成 test.jsp 文件,直接给执行了,就造成了 RCE 漏洞。
明确了上面这些后,我们再来看看这个 CVE-2024-50379 POC 的逻辑,首先来到靶机 Tomcat 的根目录看看,路径就是你 Tomcat 安装目录下的 webapps/ROOT
:
上面框出来的那两个文件就是 POC 一开始上传的文件,这里我们通过 Tomcat 访问看看:
和我们之前介绍的一样,你访问 .Jsp
这种包含大写字母的文件扩展名,经过 Tomcat 处理后会直接显示文件内容,而不会执行。上面那个就是 POC 创建的文件,其实逻辑很简单,content 变量里就是我们本地写的恶意程序经过 base64 编码后的内容,我们可以解码看看:
如上,我们可以推测,这个 POC 先将我们的恶意程序进行 Base64 编码后,保存到 content 字符串中,然后利用 CVE-2024-50379 漏洞,上传一个 .Jsp
文件,并不断访问它,终于有一次,访问成功了,它上传的这个 .Jsp
文件执行,在目标服务器中创建了一个 test.jsp,内容就是 Base64 解码后的恶意程序。
这就是为啥,我们后面即使很慢的访问 test.jsp
也能让目标执行代码的原因。从这里也可以看出来,Tomcat 处理 .Jsp
文件与 .jsp
文件还是有差别的。
0x06:修复方案
安全更新:更新 Apache Tomcat 到最新版本即可解决该漏洞。
修复缓解措施
在不影响业务的前提下将 conf/web.xml 文件中的 readOnly 参数设置为 true 或直接注释该参数。
禁用 PUT 方法并重启 Tomcat 服务以启用新的配置。