问答
发起
提问
文章
攻防
活动
Toggle navigation
首页
(current)
问答
商城
实战攻防技术
漏洞分析与复现
NEW
活动
摸鱼办
搜索
登录
注册
Apache Tomcat 条件竞争致远程代码执行漏洞(CVE-2024-50379)
漏洞分析
Apache Tomcat的默认servlet在处理文件上传时的TOCTOU条件竞争问题。当默认servlet被配置为允许写入(即readonly初始化参数被设置为非默认值false),在不区分大小写的文件系统上,攻击者可以利用并发读取和上传同一个文件的机会,绕过Tomcat的大小写敏感性检查,导致上传的文件被错误地当作JSP文件处理,从而可能触发远程代码执行。
一、漏洞简介 ====== 关于Apache Tomcat中TOCTOU(Time-of-check Time-of-use)条件竞争漏洞,主要发生在JSP编译期间。具体来说,这个漏洞涉及到Apache Tomcat的默认servlet在处理文件上传时的TOCTOU条件竞争问题。当默认servlet被配置为允许写入(即readonly初始化参数被设置为非默认值false),在不区分大小写的文件系统上,攻击者可以利用并发读取和上传同一个文件的机会,绕过Tomcat的大小写敏感性检查,导致上传的文件被错误地当作JSP文件处理,从而可能触发远程代码执行。 二、影响版本 ====== Apache Tomcat 11.0.0-M1 - 11.0.1 Apache Tomcat 10.1.0-M1 - 10.1.33 Apache Tomcat 9.0.0.M1 - 9.0.97 三、漏洞原理分析 ======== 前置知识 ---- **条件竞争:**:条件竞争是指在多线程或多进程环境中,两个或多个执行线程(或进程)试图同时访问共享数据,并且至少有一个线程(或进程)试图修改数据,导致程序的输出依赖于线程(或进程)执行的顺序,这种顺序是不可预测的。条件竞争可能导致程序行为不稳定,结果不一致,甚至产生错误。 **TOCTOU(检查时间与使用时间)**:是条件竞争的一个特定类型,发生在一个程序或系统在检查了某个条件(例如文件存在性、权限等)之后,但在实际使用该条件所涉及的资源之前,该资源的状态被另一个线程、进程或用户改变的情况下。这种漏洞可能导致安全检查失败,因为实际使用资源时的状态与之前检查时的状态不一致。 原理分析: ----- ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/12/attach-9d02a1ff9620d72fa5c97bf45ca4a754b22975ba.png) 如果readonly=false时,可以执行PUT和DELETE方法。此时去查看PUT方法实现(apache-tomcat-9.0.63-src\\java\\org\\apache\\catalina\\servlets\\DefaultServlet.java,这个文件是Apache Tomcat服务器中用于处理静态资源请求的默认Servlet。) ```@Override protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { if (readOnly) { sendNotAllowed(req, resp); return; } String path = getRelativePath(req); WebResource resource = resources.getResource(path); Range range = 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状态码响应给客户端。 ```@Override public WebResource getResource(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) { return new EmptyResource(root, path); } if (!f.exists()) { return new EmptyResource(root, path, f); } if (f.isDirectory() && path.charAt(path.length() - 1) != '/') { path = path + '/'; } return new FileResource(root, path, f, isReadOnly(), getManifest()); } else { return new EmptyResource(root, path); } } ``` 上述代码的目的是提供一个安全的方式来访问Web应用的资源。它首先验证路径,然后根据路径获取资源,如果资源不存在或路径不合法,则返回一个空资源对象。这样可以确保对资源的访问是受控的,并且能够处理不同的情况,如文件不存在或路径错误。(apache-tomcat-9.0.63-src\\java\\org\\apache\\catalina\\webresources\\DirResourceSet.java,实现了`WebResourceSet`接口,`DirResourceSet`代表一个基于目录的资源集合,通常用于提供对Web应用程序目录中资源的访问。) ```public 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-src\\java\\org\\apache\\catalina\\webresources\\FileResource.java,这个类实现了 `WebResource` 接口,代表文件系统中的一个具体文件或目录,作为 Web 应用程序的一部分资源提供给客户端。) 结合上述代码可以看到如果readonly为false时,可以并发执行PUT和GET方法,但在并发执行时没有文件锁机制,无法保证资源访问的原子性和一致性,又因为处理请求存在时间窗口,如果频繁发送请求可能会导致f.exists跳过资源检查,如果在windows这种大小写不敏感的文件系统中,则会绕过Tomcat的大小写检查,将Jsp文件认为是jsp文件执行,最终造成远程命令执行。 四、环境搭建 ====== 基础环境 ---- 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/> BurpSuite Windows 10 JDK需配置环境变量,tomcat下载解压之后需要修改apache-tomcat-9.0.63-src\\conf\\web.xml文件: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/12/attach-ef83e55e81a44939c726acb911f78390e769f3fa.png) 然后进入bin目录执行startup.bat,在浏览器访问127.0.0.1:8080即可: ![tomcat.png](https://shs3.b.qianxin.com/attack_forum/2024/12/attach-b3870d110f29d4b51c5d25e82c804133ded14049.png) 五、漏洞复现 ====== ①使用BurpSuite访问127.0.0.1:8080时抓包,发送至intruder模块两个包,分别是上传JSP远程代码执行文件和访问读取JSP文件 ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/12/attach-89f07fdb252e8b5bccf8f2a07469a07382532a0a.png) ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/12/attach-764ecb814719af85851dede57606c6ae299895ab.png) ②均使用sniper攻击模式同时开始并发攻击,等待弹出计算机,漏洞复现完成。 ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/12/attach-ebafc1be99e916c888e72a7da53dd60115ddd885.png) 六、总结 ==== 漏洞原理分析如有错误,欢迎指正。
发表于 2025-01-13 10:03:43
阅读 ( 429 )
分类:
Web服务器
0 推荐
收藏
0 条评论
请先
登录
后评论
菜鸡小z
1 篇文章
×
发送私信
请先
登录
后发送私信
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!