cup_browsed_漏洞分析报告
0x01 漏洞披露信息
- 2024 年 9 月 26 日,安全研究员 Simone Margaritelli(@evilsocket)披露了影响CUPS 打印系统的
cups-browsed
、libscupsfilters
和libppd
组件的多个漏洞,影响 2.0.1 以下版本 https://www.evilsocket.net/2024/09/26/Attacking-UNIX-systems-via-CUPS-Part-I/ - 起因是cups 系统的cups-browsed 组件无需身份验证暴露631端口,并且通过IPP协议建立连接后自动添加远程在线的打印机。
- 打印机可以选择使用
foomatic-rip
过滤器,允许通过指令执行任意命令FoomaticRIPCommandLine
,这是一个已知(CVE-2011-2697、CVE-2011-2964)但自 2011 年以来一直未修补的问题。 - 受影响的系统包括大多数 GNU/Linux 发行版、BSD、ChromeOS 和 Solaris,其中许多系统
cups-browsed
默认启用该服务。
0x02 漏洞复现
POC链接
https://github.com/RickdeJager/cupshax
1 |
|
复现流程
kali搭建ippserver打印服务,并传递command
Debian12
受害者机器需要在浏览器中选择打印功能,然后选择kali搭建的打印机,一般来说cup-browser 会自己扫描局域网内的打印机设备,但在复现的过程中,ubuntu22.04 并没有自动扫描到,需要手动添加打印机步骤。
ubuntu22.04
0x03 漏洞成因
本漏洞涉及了cups 打印系统中的 cups-browsed(建立ipp协议连接)、libcupsfilters(获取ipp属性)、libppd(生成ppd文件)、cup-filters(调用过滤器)、foomatic-rip(转换打印格式后进行打印业务) 多个组件。
首先在 cups-browsed 会调用 libcupsfilters 库中的 cfGetPrinterAttributes5 在从打印机读取IPP属性之后,没有清除这些属性,而是在后面的调用 libppd 库中的 ppdCreatePPDFromIPP2 会创建ppd 缓冲区后生成 ppd 文件,将这些打印机IPP属性保存在 /etc/cups/ppd/ 目录中以供打印作业时调用读取。并且当用户调用打印机来进行打印作业的时候,cups系统会读取ppd 文件内的属性,并且会根据cupsfilter 提供的value 来选择对应的过滤器 foomatic-rip,foomatic-rip 会读取ppd文件中的 FoomaticRIPCommandLine 值并且调用 /bin/shell 来执行命令。
虽然漏洞的评分是9.9分,但是触发条件比较特殊,需要受害者打印文件的时候,选择恶意的打印机,才会触发嵌入在ppd文件恶意命令,执行任意命令。
0x04 漏洞分析
根据具体的CVE-2024-47076、CVE-2024-47175、CVE-2024-47176、CVE-2024-47177 来看,漏洞的核心在于CUPS组件缺乏输入验证,攻击者可以利用互联网打印协议(IPP),将需要的打印机IPP属性保存在PostScript打印机描述(PPD)文件中,而CUPS 将会使用ppd文件来描述打印机属性,在使用IPP协议进行打印时,客户端会根据PPD文件中的信息配置打印作业。如果PPD文件中的一些属性attr 被攻击者注入了恶意命令,这些被操纵的ppd文件可让攻击者在触发打印时执行任意命令。
具体来说,IPP协议是一种应用层协议,用于通过网络发送和接收打印作业,允许客户端和打印机之间通信,这些通信包括发送有关打印机状态(卡纸、墨水不足等)和任何作业状态的信息,所有主流操作系统都支持IPP协议,包括Windows、macOS、Linux。
当局域网中有一个台打印机上线并可用时,打印机会通过DNS广播有关打印机的数据包,其中包括统一资源标识符(URI),以及表明PostScript语言和设备的UUID。
在linux 系统中(目前只测试了Linux)cups 会发送IPP request(GET-Printer-Attributes)从目标打印机中获取所有的 attributes 并保存到 /etc/cups/ppd/目录中。
首先从cups-browsed 组件开始分析,cups-browsed 是cups系统的一部分,并且会监听631端口,绑定之后就会调用recvfrom()函数读取数据包并检查后解析其解析的格式为 “%x%x%1023s” ,在packet数据包中读取两个十六进制数和一个字符串。
在此之后调用found_cups_printer() 函数来通过url 找到打印机的资源。其中会调用examine_discovered_printer_record() 函数,
最后调用create_remote_printer_entry() 函数创建一个新的打印机队列,并且会创建pdd文件,对于远程打印机,创建本地打印机队列并且从读取远程的pdd文件,从而保证能够通过pdd文件来驱动远程打印机。
cfGetPrinterAttributes() 函数的原型在cups系统中的libcupsfilters 库(https://github.com/OpenPrinting/libcupsfilters/blob/master/cupsfilters/ipp.c)中,通过http套接字连接,然后调用 cupsDoRequest() 函数来获取目标打印机所有的attribute, cupsDoRequest() 函数在 https://www.cups.org/doc/cupspm.html
1 |
|
具体的请求数据包如下所示:
cups-browsed 在获取到 ipp 协议的属性之后,会调用update_cups_queues() 函数更新打印队列的信息,其中会进入到 STATUS_TO_BE_CREATED 分支中开启一个线程调用create_queue()函数来更新队列。STATUS_TO_BE_CREATED 在前面的create_remote_printer_entry() 函数中会配置打印机任务状态。
create_queue()函数在执行的过程中是获取不到ppdfile的,因此会自己调用ppdCreatePPDFromIPP2() 生成ppd文件,ppd文件是只postScript打印机描述文件,文件内的属性描述了每个打印机的功能,cups 使用ppd 文件来支持打印机特定的功能和智能过滤。
详细的数据包如下
ppdCreatePPDFromIPP2() 函数来自于libppd (https://github.com/OpenPrinting/libppd/blob/master/ppd/ppd-generator.c ),及主要的功能就是创建一个标准的 pdd 文件,并且将远程打印机提供的attr 写入到pdd文件。
生成的ppd文件存在于/etc/cups/ppd/ 目录中,临时文件在打印机任务结束之后,会自动清除。
在ppd文件中,我们可以看到 cupsFilter2 和 FoomaticRIPCommandLine 这两个是pdd 文件的属性。其中cupsFilter2 的使用手册如下所示:
program 参数的作用是调用过滤器(所有能被cups 使用的过滤器在 /usr/lib/cups/filter)来处理对待打印文件格式的转换,这里使用的是 foomatic-rip 过滤器,另外cups为了提升兼容性,cupsFilter 也是做与cupsFilter2一样的工作,同样对输入没有任何校验。
foomatic-rip 能将PostScript 和 PDF(以及其他文件格式)从标准输入转换为打印机的本机语言,这里的转换手段是通过读取ppd 中的描述来构建渲染器,进行后续的打印作业。
foomatic-rip 是如何能执行 FoomaticRIPCommandLine 命令的呢?
有关FoomaticRIPCommandLine 属性配置如下所示,这个属性定义的命令会被foomatic-rip 的渲染器执行。
花了一点时间对 foomatic-rip 源码进行审计,并且开启调试运行打印作业,完整的输出信息如下所示:
1 |
|
可以看到调用了 /bin/shell 来执行command,根据其中的Starting renderer with command
定位到了 get_renderer_handle函数,会启动exec_kid3来执行command。
在exec_kid3() 函数最终中调用 run_system_process() 函数来执行命令。执行命令的流程在process.c 文件内
1 |
|
在分析的过程中,最终通过传入 FoomaticRIPCommandLine 命令参数,然后调用shell 来进行执行,于是在CVE仓库看看是否有其他符合条件的漏洞编号,我发现存在CVE-2011-2694、CVE-2011-2697这两个漏洞都是和本篇分析的漏洞详情相似,均是将载荷写入恶意的.ppd 文件中,进而造成远程命令执行。
按照对FoomaticRIPCommandLine 修复的情况来看,仅仅是不提供这个 –ppd参数选项。
1 |
|
但实际上在cups 打印系统中,foomatic-rip组件依旧可以使用 –pdd option 来指定.ppd 文件。
0x05 缓解措施
- 禁用并卸载该
cups-browsed
服务。例如,请参阅Red Hat和Ubuntu的建议。 - 确保您的 CUPS 软件包已更新至适用于您的发行版的最新版本。
- 如果无法更新,请阻止
631
来自可能受影响的主机的 UDP 端口和 DNS-SD 流量
0x06 思考总结
那么为什么在cups系统中并没有将这个存在执行命令的参数FoomaticRIPCommandLine 给修复呢,或者说设定一些对用户输入信息的校验,按照evilsocket 的说法是,cups开发人员认为如果将这个问题修复了,那将会影响老版本打印机的使用,修复可能会破坏打印机的驱动程序。因此为了维护老版本打印机型号的使用,不得不将foomatic-rip 组件保留下来,只能建议用户在配置打印机的时候,不要去使用foomatic-rip 组件。
此外,在cup-filters库中,有研究人员提交了一个远程命令执行漏洞(CVE-2023-24805),截至目前,该漏洞仍处于” A fix is worked on currently”的状态,可见一斑。
在许多系统或产品中,当影响面广泛且供应链错综复杂时,如果某个环节出现安全漏洞,安全研究人员通常会要求开发者立即启动应急响应策略,以便及时修复并发布缓解措施。然而,对于企业、组织、开发者甚至用户来说,需要考虑的因素则更加复杂。例如,更换组件、协调修复漏洞的相关部门以及上下游供应商所涉及的成本问题,牵一发而动全身的改动代码是否产生其他代码问题,修复漏洞是否会影响产品生态中其他组件的正常维护和使用。此外,类似于 CUPS 的情况,在修复漏洞后,可能会对大量旧款、不再维护的打印机产品的使用造成影响。因此,修复漏洞的过程往往面临诸多权衡和困境,迫使各方在安全与可用性之间寻求平衡。
在网络安全领域,安全研究人员往往持有一种单向的风险观。在发现漏洞后,他们希望能获得更多的关注和响应,并普遍认为漏洞存在的风险是负面的。然而,修复这些漏洞的过程可能会影响实际用户对产品的使用体验,导致用户未能真正体会到漏洞修复所带来的安全提升。这种情况使得安全修复与用户体验之间的平衡变得复杂,往往需要在保障安全和维持良好体验之间做出权衡。
“在网络安全领域,我们常常忘记,我们的业务不是消除风险,而是管理风险”
0x07 有关参考
https://www.evilsocket.net/2024/09/26/Attacking-UNIX-systems-via-CUPS-Part-I/
https://www.cups.org/doc/spec-ppd.html#cupsFilter2
https://refspecs.linuxbase.org/LSB_3.2.0/LSB-Printing/LSB-Printing/ppdext.html
https://linux.die.net/man/1/foomatic-rip
https://github.com/jschyz/blog/issues/7
https://blog.csdn.net/limelove/article/details/121988838
https://www.cups.org/doc/network.html