Concrete CMS文件上传条件竞争漏洞|CVE-2021-22968

Concrete CMS文件上传条件竞争漏洞|CVE-2021-22968

介绍

Concrete CMS 旨在为具有最少技术技能的用户提供易用性。它使用户能够直接从页面编辑站点内容。它为每个页面提供版本管理,类似于维基软件,另一种网站开发软件。Concrete5 允许用户通过页面上的嵌入式编辑器编辑图像。截至 2021 年,有超过 62,000 个使用 Concrete CMS 构建的实时网站。

在最近的一次渗透测试中,我们的团队发现了一个非常有趣的漏洞。漏洞的发现相对简单,但是将 POC 放在一起非常具有挑战性,因此这篇文章的原因。CVE-2021-22968 已分配给此问题,并在 Concrete CMS 版本 8.5.7 和 9.0.1 中修复。需要低权限用户才能利用此漏洞获取远程命令执行。

漏洞——文件上传中的竞争条件

作为受限用户,您可以从远程服务器上传文件。您输入 url,CMS 将使用 curl 下载它并将其写入本地(或写入 AWS S3 中的存储桶)。这个卷曲有 60 秒的超时,这将在以后变得相关。

Concrete CMS文件上传条件竞争漏洞|CVE-2021-22968

现在,你们中的一些人可能会尖叫“SSRF!”,这绝对是公平的,但我们将讨论这个问题以及我们如何绕过本系列第 2 部分中的所有 SSRF 缓解措施。

一些验证是在文件扩展名上完成的,例如,如果您尝试下载带有 php 扩展名的文件,您将获得:

Concrete CMS文件上传条件竞争漏洞|CVE-2021-22968

当我们检查源代码时,验证看起来很不错,但是您知道在跟踪代码时我们意识到了什么吗?验证是在文件下载到本地后完成的!因此,我们有一个竞争条件。我们的第一个竞争条件,因为正如您将看到的,我们将有 2 个竞争条件可以利用。

让我们看一下代码,看看我们的文件在哪里下载和写入:

Concrete CMS文件上传条件竞争漏洞|CVE-2021-22968

但是 $temporaryDirectory 来自哪里?有一个名为 VolatileDirectory 的特殊类,它创建一个临时目录,在每个请求结束时将其删除。

Concrete CMS文件上传条件竞争漏洞|CVE-2021-22968

如您所见,创建了一个新目录,我们的文件将写入此处。目录的名称应该是随机的,但是在实践中 $i 将始终为 0,因此我们需要检查 uniqid() 的行为,我们稍后会看一下。我们遇到的另一个问题是,在 CMS 中导入文件后,整个目录与下载的文件一起被删除:

Concrete CMS文件上传条件竞争漏洞|CVE-2021-22968

Uniqid() 行为

好的,正如我们所说,让我们检查 php 源代码中的 uniqid() 函数,看看它返回什么:

Concrete CMS文件上传条件竞争漏洞|CVE-2021-22968

这真的很简单,没有什么可害怕的。如您所见,它只是执行 gettimeofday() 返回秒和微秒。CMS 源代码中没有使用 more_entropy 参数,因此这里没有使用真正的熵,整个返回值基于秒/微秒,正如我们所知,这些是高度可预测的,我们可以对其进行暴力破解。我们只需要有足够的时间来执行此操作,因为在我们的初始测试中,执行一个请求大约需要 100 毫秒。

我们需要一个计划

所以基本上为了猜测随机目录的名称,我们需要猜测服务器将使用的秒和微秒。根据响应标头,我们可以通过将主机时间与服务器时间同步来轻松猜测第二部分。我们还应该将我们的攻击服务器放置在同一时区或 AWS 区域,尽可能靠近目标。但是一个请求大约需要 100ms 的时间来执行,因此我们需要尽可能地延长这个请求的执行时间,以便我们有时间对 volatile 目录名称进行暴力破解。有 1M 个可能的目录名称要检查,每微秒 1 个。我们怎样才能做到这一点?很简单,我们将在从远程服务器下载的 test.php 文件中添加一个 30-60 秒的 sleep()。这将基本上强制 CMS 在删除它之前将 $temporaryDir 目录在本地文件系统上保留 30-60 秒。我们有足够的时间使用 Turbo Intruder 对目录名称进行暴力破解。当我们找到现有目录时,我们会得到一个 200 HTTP 响应代码。下面是我们使用的 test.php 文件(这个 php 文件 echo-es 另一个 php 文件;并且回显的php代码会在父目录中写一个php shell):

<?php 
set_time_limit(0);
sleep(35);
echo '<?php file_put_contents("../shell.php","<?php system($_GET[c]) ;");';
echo '?>' . str_repeat("A",50000000);
flush();
ob_flush();
?>

这是攻击的所有相关时刻的图表,希望这能让事情变得更清楚。

Concrete CMS文件上传条件竞争漏洞|CVE-2021-22968

相关竞态条件的时序

  • 在 T0 时,您开始上传请求并开始搜索易失性目录名称。您有 100 万种可能性,我们设法发送了 16-17K RPS,因此您可以在大约 30 秒内轻松暴力破解 500-700K,这是 50% 的机会,效果很好。由于 Turbo Intruder 的一些问题,我们没有对 1M 的请求进行排队。
  • 在 T1,您找到了 volatile 目录名称(赢得了第一场比赛),但 test.php 尚未写入该目录中。因此,您必须开始搜索 test.php(第二个竞争条件),它总是在大约 30 秒后(从 T0 开始)写入。为此,我们在 Turbo Intruder 中将另外 500K 请求排队。
  • 在 T2(~第 30 秒) test.php 是在本地编写的,在 volatile 目录中
  • 在 T3 时,来自 T1 的排队请求之一命中 test.php 并通过执行它,我们在父目录(“/application/files/tmp”)中编写了一个永久外壳 – 我们赢得了第二场比赛
  • 在 T4 里面的 volatile dir 和 test.php 都被删除了,但是我们已经有了一个 shell 

猜到目录名后,我们会请求test.php,它会在父目录中写入一个永久的shell。这是来自 Turbo Intruder 的屏幕截图,其中包含猜测的目录名称:

Concrete CMS文件上传条件竞争漏洞|CVE-2021-22968

第二个条件竞争

通过让 test.php 执行约 30 秒以猜测目录名称,我们创建了第二个竞争条件。我们现在不知道 test.php 什么时候会被写入 CMS 文件系统,但很明显,在它完成后它自己在远程服务器上执行(休眠时间 + 几毫秒)。实际上,这意味着如果我们在第 10 秒猜到目录名称,我们将不得不在 turbo intruder 中排队另外 500K-1M 的请求,这将必须涵盖所有时间间隔,直到 test.php 被写入文件系统。最坏的情况是,您必须再发送 30 秒的足够请求。

Concrete CMS文件上传条件竞争漏洞|CVE-2021-22968

您可以在上面的屏幕截图 (tail -f access_log) 中看到,我们如何在我们之前猜测的目录名称中不断发送对 test.php 的请求。一旦找到并执行 test.php,它就会在父目录中写入一个永久的 shell。

再生能源认证

我们希望到目前为止事情已经很清楚了,这是我们的 shell,它为我们提供了 RCE 和持久性:

Concrete CMS文件上传条件竞争漏洞|CVE-2021-22968

发现此漏洞相对容易,但是将 POC 放在一起是一项非常耗时的活动。我们还必须解决一些 Turbo Intruder 问题,这些问题导致了这个问题和其他一些问题,感谢@albinowax解决了这个问题。所有代码都在这里发布。

提示

  • curl 的超时时间是 60 秒,不要在 test.php 中 sleep() 超过 60 秒
  • 如果可能,请使用 http2
  • 使用 tail -f access_log 和 tail -f error_log 监视您的请求和任何错误
  • 检查 request.txt 中的上传请求是否仍然有效
  • 上传请求默认绑定单个ip

时间线

  • 30/10/2021 报告发送给供应商
  • 08/11/2021 补丁发布(版本 8.5.7/9.0.1)
  • 15/11/2021 发表了这篇文章

from

Leave a Reply

您的电子邮箱地址不会被公开。 必填项已用*标注