PHP PEAR 15年漏洞可导致供应链攻击

admin 2022年4月3日15:07:07评论104 views字数 6025阅读20分5秒阅读模式

本文机翻自:sonarsource

PHP PEAR 15年漏洞可导致供应链攻击

介绍 

Composer 使用的主存储库 Packagist 上的包的研究之后,决定审查其对应的名为 PEAR 的包。它的使用逐渐减少,取而代之的是 Composer,但仍然是许多公司使用的 PHP 生态系统的一个组成部分。 
一年来第二次在 PHP 供应链的核心组件中发现了严重的代码漏洞。我们相信这些漏洞很容易被威胁者识别和利用,只需很少的技术专业知识,在世界范围内造成严重的破坏和安全漏洞。
已经讨论了 SolarWinds 案例,但此后大量非目标攻击成为新闻。欧盟网络安全局(ENISA)最近的一份报告研究了2021 年 1 月和 2021 年 7 月上旬报告的 24 次攻击,并强调这些攻击中有 50% 来自已知的威胁参与者,并预测 2021 年将增加四倍,因为勒索软件组加入潮流。
此类攻击对 PEAR 等开发人员工具的影响更为显著,因为它们可能会在将其部署到生产服务器之前在其计算机上运行它,从而为攻击者提供了进入公司内部网络的机会。 
据估计,从 pear.php.net 下载了大约 2.85 亿个包,其中最受欢迎的是 PEAR 客户端本身、Console_GetoptArchive_TarMail尽管 Composer 拥有更大的市场份额,但这些 PEAR 软件包每月仍能获得数千次下载。 
在本文中,我们展示了两个漏洞,它们都可以利用超过 15 年。利用第一个漏洞的攻击者可以接管任何开发人员账户并发布恶意版本,而第二个漏洞将允许攻击者获得对中央 PEAR 服务器的持久访问权限。 
在深入了解技术细节之前,请查看我们的视频,该视频展示了在我们的本地 PEAR 实例上导致任意代码执行的各个阶段:

PHP PEAR 15年漏洞可导致供应链攻击

技术细节

在本节中,我们将介绍这两个错误的技术特性,描述它们的根本原因以及如何在实际场景中利用它们。我们在本地虚拟机上执行了所有测试以避免破坏官方 PEAR 实例,并在提交f3333c2时使用了官方 Git 存储库。

pear.php.net背后的源代码可以在 GitHub 上的一个名为pearweb的项目中找到。我们的发现影响了 1.32 之前的所有pearweb实例,维护者在该版本中修复了我们发现的漏洞。 

该软件的作用是在包的名称(例如Console_Getopt)和下载包的绝对 URL(例如http://download.pear.php.net/package/Console_Getopt-1.4.3 .tgz)。它的妥协将允许更改此关联并强制包管理器从攻击者控制下的非预期来源下载包。


初始立足点:密码重置期间的弱熵

pearweb实例不允许自行注册:账户保留给愿意提议包含在官方 PEAR 存储库中的软件包的开发人员。请求账户可以使用请求账户表单完成,请求者必须提供有关其身份和他们想要分发的项目的信息。然后由 PEAR 管理员手动验证请求。 

这是一个减少滥用和最小化服务攻击面的有趣选择:不包括错误跟踪器,唯一没有账户可用的“有趣”功能是此账户请求表单、身份验证和密码重置功能。 

在 SonarCloud 上扫描此项目后,我们的引擎在名为 resetPassword() 的方法中识别出一个安全热点: 

PHP PEAR 15年漏洞可导致供应链攻击

此代码生成一个随机值,使用 MD5 对其进行哈希处理,然后将其与密码重置所需的其他详细信息一起插入数据库。在这里使用 MD5 不是问题,只要散列值足够强且唯一。

SonarCloud 规则描述中详细解释了该问题出于安全敏感原因,不应使用mt_rand() 。让我们回顾一下连接在一起的值,然后用md5()散列:

  • mt_rand(4,13) : 413之间的整数(包括边界);

  • $user:要重置的账户的用户名,攻击者知道和控制;

  • time() : 当前时间戳;

  • $pass1:攻击者知道和控制的新密码。

从攻击者的角度来看,最终值仅基于两个未知数,即mt_rand()time()的输出:第一个不能产生很多值 (10),第二个可以很容易地近似为攻击者。此外,pear.php.net的 HTTP 服务器在其响应中添加了一个 Date 标头,将其缩小到只有几个值 (< 5)。 

我们可以得出结论,攻击者可以在不到 50 次尝试中发现有效的密码重置令牌,我们开发了一个脚本来利用此弱点并确认其影响:这是介绍视频的第一步。

对于轶事,这个错误是在 2007 年 3 月首次实现此功能时引入的。 

通过对现有开发人员或管理员账户使用此漏洞,攻击者可以在其中包含恶意代码后发布现有软件包的新版本。每当有人从 PEAR 获取这些包时,它就会自动下载并执行。 


获得持久性:Archive_Tar 中的 CVE-2020-36193

在找到访问保留给已批准开发人员的功能的方法后,威胁参与者可能希望在服务器上获得远程代码执行。这样的发现将赋予他们更多的操作能力:即使前面提到的错误最终得到修复,后门将允许保持对服务器的持久访问并继续更改软件包版本。它还可以帮助他们通过修改访问日志来隐藏他们的踪迹。

鉴别

通过第一个错误获得的初始访问权限将攻击面扩展到没有账户就无法访问的新功能,并且也可能不太安全。 

在我们的测试虚拟机上部署pearweb时,我们注意到它在旧版本(1.4.7,而最后一个是 1.4.14)中提取了依赖Archive_Tar :

root@pearweb:/var/www/html/pearweb# pear list
Installed packages, channel pear.php.net:
=========================================
Package                         Version  State
Archive_Tar                     1.4.7    stable

查看这个包的变更日志条目,我们可以注意到,在Archive_Tar 1.4.12 之前,可以创建一个指向提取目录之外的绝对路径的符号链接;此错误被跟踪为 CVE-2020-36193。 

该错误类非常强大,因为它可以允许在 HTTP 服务器服务的目录中编写 PHP 文件,最终导致任意代码执行。

该库用于提取临时目录中的包内容,以使用phpDocumentor处理它们,然后发布生成的文件:

cron/apidoc-queue.php

$query = "SELECT filename FROM apidoc_queue WHERE finished = '0000-00-00 00:00:00'";
$rows = $dbh->getCol($query);
foreach ($rows as $filename) {
    $info = $pkg_handler->infoFromTgzFile($filename);
    $tar = new Archive_Tar($filename);
    // [...]
    /* Extract files into temporary directory */
    $tmpdir = PEAR_TMPDIR . "/apidoc/" . $name;
    // [...]
    $tar->extract($tmpdir);

此代码使用 cron 定期触发,并且每次发布新版本的包时都会将新记录添加到表文件名中:由于获得了初始访问权限,因此攻击者可以访问Archive_Tar::extract()此调用我们提出的第一个错误。

开发

要了解此漏洞背后的技术细节,需要一些有关 Tar 档案的背景知识。归档文件按顺序存储,每个条目都以 512 字节标题为前缀,其内容与 512 字节对齐。条目的结束用两条 512 字节的空记录来表示。文件模式、所有者和组数字标识符以及文件大小等字段使用 ASCII 数字存储为八进制数。 

PHP PEAR 15年漏洞可导致供应链攻击

这种归档格式支持将多种“对象”写入磁盘,其中包括符号链接:根据 CVE 描述,我们可以假设 bug 在于Archive_Tar提取此类条目的实现。在源代码中很容易找到它的实现:在[1]我们匹配任何类型为“符号链接”的条目,在[2]删除目标(标题条目文件名),然后最后在[3 ] 创建链接] :

存档/Tar.php

elseif ($v_header['typeflag'] == "2") {                   // [1]
if (@file_exists($v_header['filename'])) {
    @unlink($v_header['filename']);                      // [2]
}
if (!@symlink($v_header['link'], $v_header['filename'])) { // [3]
    $this->_error(
        'Unable to extract symbolic link {'
        . $v_header['filename'] . '}'
    );
    return false;
}

$v_header['link']不同,  $v_header['filename']预先使用_maliciousFilename()进行验证,以确保不存在目录遍历字符和危险的方案包装器: 

存档/Tar.php

private function _maliciousFilename($file)
{
  if (strpos($file, 'phar://') === 0) {
    return true;
  }
  if (strpos($file, '../') !== false || strpos($file, '..\') !== false) {
    return true;
  }
  return false;
}

还应该提到的是,通过始终以目标文件夹 ( $p_path ) 为前缀,绝对路径的提取是安全的:

存档/Tar.php

if (($p_path != './') && ($p_path != '/')) {
    while (substr($p_path, -1) == '/') {
          $p_path = substr($p_path, 0, strlen($p_path) - 1);
    }
    if (substr($v_header['filename'], 0, 1) == '/') {
          $v_header['filename'] = $p_path . $v_header['filename'];
    } else {
        $v_header['filename'] = $p_path . '/' . $v_header['filename'];
    }
}

正如 CVE 描述所建议的,没有在符号链接的目标上执行验证。它可以通过多种方式被利用,其中:

  • phar://方案包装器被阻止,但没有其他值,例如file ://甚至PHAR://:这些错误是 CVE-2020-28948 和 CVE-2020-28949,都在 Archive_Tar 1.4.11 中修复;

  • 创建一个目标在当前目录之外的符号链接。 

我们可以创建一个指向提取目录之外的文件夹的新链接并向其中写入文件,或者创建两个具有相同名称的条目(这种格式允许!),第一个是符号链接,第二个是符号链接要写的内容。 

我们可以通过将任意内容写入/var/www/html/pearweb/public_html/evil.php来确认此漏洞的可利用性,证明攻击者可以在服务器上执行任意代码。这是概念验证视频的第二步。 

修补

维护人员于 8 月 4 日首次发布了第一个补丁,其中他们引入了一种安全方法来在密码重置功能中生成伪随机字节。

由于 PHP 在引用不存在的变量并将它们与默认值NULL相关联时不会引发致命错误,因此该代码有一个可利用的细微缺陷。 

[1]处,将由 16 个随机字节组成的字符串分配给$random_bytes ,而在[2]处调用md5( $rand_bytes ) :第二个变量不存在($rand om _bytes$rand_bytes),此操作将总是导致空字符串的 MD5 散列(d41d8cd98f00b204e9800998ecf8427e)。 

--- a/include/users/passwordmanage.php
+++ b/include/users/passwordmanage.php
@@ -55,7 +55,12 @@ function resetPassword($user, $pass1, $pass2)
     {
         require_once 'Damblan/Mailer.php';
         $errors = array();
-        $salt = md5(mt_rand(4,13) . $user . time() . $pass1);
+        // [1]
+        $random_bytes = openssl_random_pseudo_bytes(16, $strong);
+        if ($random_bytes === false || $strong === false) {
+            $errors[] = "Could not generate a safe password token";
+            return $errors;
+        }
+        // [2]
+        $salt = md5($rand_bytes):
         PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
         $this->_dbh->query('DELETE FROM lostpassword WHERE handle=?', array($user));
         $e = $this->_dbh->query('INSERT INTO lostpassword
@@ -91,4 +96,4 @@ function resetPassword($user, $pass1, $pass2)
         }
         return $errors;
     }

我们将这个错字通知了维护人员,之后他们迅速修复了它他们还升级了正在使用的Archive_Tar版本,防止了我们提出的第二个漏洞。 

时间线

日期 行动
2021-07-30 我们将所有问题报告给 PEAR 的积极维护者。
2021-08-03 维护人员确认问题并开始处理补丁;几天后,补丁在 GitHub 上发布。
2021-09 - 2022-03 我们会定期要求更新,以确保将补丁部署在生产实例上。
2022-05-13 补丁部署在生产环境中。
2022-05-25 本文的漏洞在 Insomni'hack 上公开展示。


概括

在本文中,我们展示了两个代码漏洞,这些漏洞可能已被利用来对 PEAR 生态系统执行供应链攻击,并危及依赖它的开发人员和公司。这些漏洞已经存在了十多年,并且很难识别和利用,这引发了人们对依赖它的公司缺乏安全贡献的质疑。 

我们还建议检查您对 PEAR 的使用并考虑迁移到 Composer,其中贡献者社区更加活跃,并且可以使用相同的软件包。


原文始发于微信公众号(祺印说信安):PHP PEAR 15年漏洞可导致供应链攻击

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
未分类
admin
  • 本文由 发表于 2022年4月3日15:07:07
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   PHP PEAR 15年漏洞可导致供应链攻击https://cn-sec.com/archives/865937.html

发表评论

匿名网友 填写信息