免责声明:本篇文章仅用于技术交流,请勿利用文章内的相关技术从事非法测试,由于传播、利用本公众号无影安全实验室所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,公众号无影安全实验室及作者不为此承担任何责任,一旦造成后果请自行承担!如有侵权烦请告知,我们会立即删除并致歉。谢谢!
朋友们现在只对常读和星标的公众号才展示大图推送,建议大家把"无影安全实验室"设为星标,这样更新文章也能第一时间推送!
安全工具
0x01 漏洞简介
0x02 影响版本
Apache Tomcat 11.0.0-M1 - 11.0.1Apache Tomcat 10.1.0-M1 - 10.1.33Apache Tomcat 9.0.0.M1 - 9.0.97
0x03 漏洞原理分析
前置知识
条件竞争::条件竞争是指在多线程或多进程环境中,两个或多个执行线程(或进程)试图同时访问共享数据,并且至少有一个线程(或进程)试图修改数据,导致程序的输出依赖于线程(或进程)执行的顺序,这种顺序是不可预测的。条件竞争可能导致程序行为不稳定,结果不一致,甚至产生错误。TOCTOU(检查时间与使用时间):是条件竞争的一个特定类型,发生在一个程序或系统在检查了某个条件(例如文件存在性、权限等)之后,但在实际使用该条件所涉及的资源之前,该资源的状态被另一个线程、进程或用户改变的情况下。这种漏洞可能导致安全检查失败,因为实际使用资源时的状态与之前检查时的状态不一致。
原理分析:
如果readonly=false时,可以执行PUT和DELETE方法。此时去查看PUT方法实现(apache-tomcat-9.0.63-srcjavaorgapachecatalinaservletsDefaultServlet.java,这个文件是Apache Tomcat服务器中用于处理静态资源请求的默认Servlet。)
protectedvoiddoPut(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
if (readOnly) {
sendNotAllowed(req, resp);
return;
}
Stringpath= getRelativePath(req);
WebResourceresource= resources.getResource(path);
Rangerange= parseContentRange(req, resp);
if (range == null) {
// Processing error. parseContentRange() set the error code
return;
}
InputStream resourceInputStream = null;
try {
// Append data specified in ranges to existing content for this
// resource - create a temp. file on the local filesystem to
// perform this operation
// Assume just one range is specified for now
if (range == IGNORE) {
resourceInputStream = req.getInputStream();
} else {
File contentFile = executePartialPut(req, range, path);
resourceInputStream = new FileInputStream(contentFile);
}
if (resources.write(path, resourceInputStream, true)) {
if (resource.exists()) {
resp.setStatus(HttpServletResponse.SC_NO_CONTENT);
} else {
resp.setStatus(HttpServletResponse.SC_CREATED);
}
} else {
resp.sendError(HttpServletResponse.SC_CONFLICT);
}
} finally {
if (resourceInputStream != null) {
try {
resourceInputStream.close();
} catch (IOException ioe) {
// Ignore
}
}
}
}
上述代码处理HTTP PUT请求,允许客户端上传文件到服务器的指定路径。它处理了范围请求、部分更新,并确保了资源的正确写入。如果在处理过程中发生错误,它会发送适当的HTTP状态码响应给客户端。
publicWebResourcegetResource(String path) {
checkPath(path);
String webAppMount = getWebAppMount();
WebResourceRoot root = getRoot();
if (path.startsWith(webAppMount)) {
File f = file(path.substring(webAppMount.length()), false);
if (f == null) {
returnnewEmptyResource(root, path);
}
if (!f.exists()) {
returnnewEmptyResource(root, path, f);
}
if (f.isDirectory() && path.charAt(path.length() - 1) != '/') {
path = path + '/';
}
returnnewFileResource(root, path, f, isReadOnly(), getManifest());
} else {
returnnewEmptyResource(root, path);
}
}
上述代码的目的是提供一个安全的方式来访问Web应用的资源。它首先验证路径,然后根据路径获取资源,如果资源不存在或路径不合法,则返回一个空资源对象。这样可以确保对资源的访问是受控的,并且能够处理不同的情况,如文件不存在或路径错误。(apache-tomcat-9.0.63-srcjavaorgapachecatalinawebresourcesDirResourceSet.java,实现了WebResourceSet
接口,DirResourceSet
代表一个基于目录的资源集合,通常用于提供对Web应用程序目录中资源的访问。)
File resource, boolean readOnly, Manifest manifest) {
super(root,webAppPath);
this.resource = resource;
if (webAppPath.charAt(webAppPath.length() - 1) == '/') {
String realName = resource.getName() + '/';
if (webAppPath.endsWith(realName)) {
name = resource.getName();
} else {
// This is the root directory of a mounted ResourceSet
// Need to return the mounted name, not the real name
int endOfName = webAppPath.length() - 1;
name = webAppPath.substring(
webAppPath.lastIndexOf('/', endOfName - 1) + 1,
endOfName);
}
} else {
// Must be a file
name = resource.getName();
}
this.readOnly = readOnly;
this.manifest = manifest;
this.needConvert = PROPERTIES_NEED_CONVERT && name.endsWith(".properties");
}
这个构造函数初始化了一个FileResource
对象,设置了资源的路径、实际文件、名称、只读标志和是否需要转换属性文件等属性。这使得FileResource
能够正确地管理和提供对文件系统资源的访问。(apache-tomcat-9.0.63-srcjavaorgapachecatalinawebresourcesFileResource.java,这个类实现了 WebResource
接口,代表文件系统中的一个具体文件或目录,作为 Web 应用程序的一部分资源提供给客户端。)
结合上述代码可以看到如果readonly为false时,可以并发执行PUT和GET方法,但在并发执行时没有文件锁机制,无法保证资源访问的原子性和一致性,又因为处理请求存在时间窗口,如果频繁发送请求可能会导致f.exists跳过资源检查,如果在windows这种大小写不敏感的文件系统中,则会绕过Tomcat的大小写检查,将Jsp文件认为是jsp文件执行,最终造成远程命令执行。
0x04 环境搭建
基础环境
Jdk8u151:https://repo.huaweicloud.com/java/jdk/8u151-b12/Tomcat-9.0.63:https://archive.apache.org/dist/tomcat/tomcat-9/v9.0.63/bin/BurpSuiteWindows 10JDK需配置环境变量,tomcat下载解压之后需要修改apache-tomcat-9.0.63-srcconfweb.xml文件:
然后进入bin目录执行startup.bat,在浏览器访问127.0.0.1:8080即可:
0x04 漏洞复现
六、总结
漏洞原理分析如有错误,欢迎指正。
原文始发于微信公众号(无影安全实验室):Apache Tomcat 条件竞争致远程代码执行漏洞(CVE-2024-50379)
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论