CVE-2024-50379-Tomcat-rce
Last Update:
CVE-2024-50379-Tomcat-rce
🤔 此漏洞有个前生 CVE-2017-12615
在 Apache Tomcat 7.0.0 - 7.0.79 范围中,如果 web.xml 文件中,readonly 被设置成 false,我们就能用 put 方法(前提是没被禁用)上传一个精心打造的 jsp 文件直接来达到上传 webshell 的目的,简单粗暴
不是本次重点,不多述
接下来是复现部分 :
环境:
首先我们需要 windows 环境,只有对大小不敏感的系统才能成功 rce
受影响的 Apache Tomcat 版本包括:
- 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()
复现:
下载有洞的版本后,我们需要先设置其中的 web.xml,在其中添加一个参数
将 readonly 指定为 false,这样才能让 defultServlet 允许上传文件到服务器
然后直接点击 startup.bat 启动,这里可能会编码错误,因为 windows 一般使用 GBK,我们需要在 logging.properties 文件中修改一下编码方式
直接双击 startup.bat 启动
卡在这也没事,直接访问本地的 8080 端口,即可
当我们尝试将一个 a.jsp 文件上传的时候,会发现 404 错误、
Tomcat 是禁止直接上传 .jsp
文件,后缀为小写的 .jsp
文件,当用户访问时,Tomcat 会交给 jspServlet 处理,而他并不处理 put 方法,导致上传失败。
所以我们需要先让文件能被 put 上去,我们选择将文件改为 a.Jsp 这样处理他的就是 defaultsevrlet,文件可以顺利上传
回应 201(即上传成功),本地也能看见
(这时候应该可以写个 webshell,用蚁剑直接连上(没试过
但显然我们可以做的更多,接下来进行 rce
这时候,如果我们的文件中有精心构造的内容,我们如何让他执行呢
(本来我是使用 yakit 开启多个线程,一个不断 put .Jsp 文件,另一个不断 GET .jsp 文件来实现条件竞争达成 rce,但是一直不成功,这里使用佬佬的 poc 完成 rce
工具作者的 github 地址:https://github.com/SleepingBag945/CVE-2024-50379
当我们访问地址时,成功弹出了计算器
工具源码分析:
自己看
主要在 main 函数中,通过开启三个线程,两个不断 put,一个 get,重复到成功
原理解释:
对于 win 来说,a.Jsp 和 a.jsp 是一个文件(这个也可以研究 windows 找源码的方法知道为什么,这里不多解释。
我们要在 GET a.jsp 时让 JspServlet 执行这个文件,这里涉及 AbstractFileResourceSet 的 file 方法
try {
// JRE 方法
canPath = file.getCanonicalPath();
} catch (IOException var6) {
}
if (canPath != null && canPath.startsWith(this.canonicalBase)) {
String absPath = this.normalize(file.getAbsolutePath());
....
if (!canPath.equals(absPath)) {
if (!canPath.equalsIgnoreCase(absPath)) {
this.logIgnoredSymlink(this.getRoot().getContext().getName(), absPath, canPath);}
return null;
} else {
return file;
}
//大概就这些
我们发现只有当 abspath=canpath 时才会返回文件,也就是才会执行代码
其中 abs path 是用户输入的路径拼接处理后的本地绝对路径
其中 can path 是 JRE 类 WinNTFileSystem JNI/cache 处理后得到的路径(如果缓存启用就会从其中获取
当我们 PUT 一个 a.Jsp 文件上去时,显然 abspath 和 canpath 都是 a.Jsp
当我们 GET a.jsp 时,如果我们已经 PUT a.Jsp,那么,abspath 会是 a.jsp canpath 会是 a.Jsp(从缓存中读),那么不通过检测,就不会返回文件而如果我们 PUT 的 a.Jsp 还没落地 那么 abspath canpath 都会是 a.jsp 这样会返回文件
但很显然不 PUT 就不会有文件,而我们查看代码可以知道,这种检查不会只有一次而是重复好几次
org.apache.catalina.webresources#getResource
cacheEntry.validateResource(useClassLoaderResources);
//在 JspServlet 后续处理的过程中,会再次抵达 AbstractFileResourceSet file 方法
//类似的过程会重复好几次
在 JspServlet 读取文件前会经过很多次的检查
所以,我们要保证在它检查的时候,我们的 abspath canpath 要一直保持 a.jsp 而在返回文件前一刻,我们的 PUT a.Jsp 文件要刚好落地,这样才能完美执行,这里就是一个条件竞争