# -*- coding: binary -*- module Msf ### # # This mixin provides a generic interface for running a TCP server of some # sort that is designed to exploit clients. Exploits that include this mixin # automatically take a passive stance. # ### module Exploit::Remote::TcpServer def initialize(info = {}) super(update_info(info, 'Stance' => Msf::Exploit::Stance::Passive)) register_options( [ OptBool.new('SSL', [ false, 'Negotiate SSL for incoming connections', false]), # SSLVersion is currently unsupported for TCP servers (only supported by clients at the moment) # OptEnum.new('SSLVersion', [ false, 'Specify the version of SSL that should be used', 'TLS1', ['SSL2', 'SSL3', 'TLS1']]), OptPath.new('SSLCert', [ false, 'Path to a custom SSL certificate (default is randomly generated)']), OptAddress.new('SRVHOST', [ true, "The local host to listen on. This must be an address on the local machine or 0.0.0.0", '0.0.0.0' ]), OptPort.new('SRVPORT', [ true, "The local port to listen on.", 8080 ]), ], Msf::Exploit::Remote::TcpServer) register_advanced_options( [ OptString.new('ListenerComm', [ false, 'The specific communication channel to use for this service']), OptBool.new('SSLCompression', [ false, 'Enable SSL/TLS-level compression', false ]) ], Msf::Exploit::Remote::TcpServer) register_evasion_options( [ OptInt.new('TCP::max_send_size', [false, 'Maximum tcp segment size. (0 = disable)', 0]), OptInt.new('TCP::send_delay', [false, 'Delays inserted before every send. (0 = disable)', 0]) ], Msf::Exploit::Remote::Tcp ) end # # This mixin overrides the exploit method so that it can initiate the # service that corresponds with what the client has requested. # def exploit start_service() print_status("Server started.") # Call the exploit primer primer # Wait on the service to stop self.service.wait end # # Primer method to call after starting service but before handling connections # def primer end # # Stops the service, if one was created. # def cleanup super if(service) stop_service() print_status("Server stopped.") end end # # Called when a client connects. # def on_client_connect(client) end # # Called when a client has data available for reading. # def on_client_data(client) end # # Called when a client has disconnected. # def on_client_close(client) end # # Starts the service. # def start_service(*args) begin comm = datastore['ListenerComm'] if comm == "local" comm = ::Rex::Socket::Comm::Local else comm = nil end self.service = Rex::Socket::TcpServer.create( 'LocalHost' => srvhost, 'LocalPort' => srvport, 'SSL' => ssl, 'SSLCert' => ssl_cert, 'SSLCompression' => ssl_compression, 'Comm' => comm, 'Context' => { 'Msf' => framework, 'MsfExploit' => self, }) self.service.on_client_connect_proc = Proc.new { |client| on_client_connect(client) } self.service.on_client_data_proc = Proc.new { |client| on_client_data(client) } self.service.on_client_close_proc = Proc.new { |client| on_client_close(client) } # Start the listening service self.service.start rescue ::Errno::EACCES => e if (srvport.to_i < 1024) print_line(" ") print_error("Could not start the TCP server: #{e}.") print_error( "This module is configured to use a privileged TCP port (#{srvport}). " + "On Unix systems, only the root user account is allowed to bind to privileged ports." + "Please run the framework as root to use this module." ) print_error( "On Microsoft Windows systems, this error is returned when a process attempts to "+ "listen on a host/port combination that is already in use. For example, Windows XP "+ "will return this error if a process attempts to bind() over the system SMB/NetBIOS services." ) print_line(" ") end raise e end end # # Stops the service. # def stop_service if (service) begin self.service.deref if self.service.kind_of?(Rex::Service) if self.service.kind_of?(Rex::Socket) self.service.close self.service.stop end if service.kind_of?(Rex::Proto::Http::Server) service.stop end self.service = nil rescue ::Exception end end end # # Returns the local host that is being listened on. # def srvhost datastore['SRVHOST'] end # # Returns the local port that is being listened on. # def srvport datastore['SRVPORT'] end # # Returns the SSL option # def ssl datastore['SSL'] end # # Returns the SSLCert option # def ssl_cert datastore['SSLCert'] end # @return [Bool] enable SSL/TLS-level compression def ssl_compression datastore['SSLCompression'] end # # Re-generates the payload, substituting the current RHOST and RPORT with # the supplied client host and port from the socket. # def regenerate_payload(cli, arch = nil, platform = nil, target = nil) ohost = datastore['RHOST'] oport = datastore['RPORT'] p = nil begin # Update the datastore with the supplied client peerhost/peerport datastore['RHOST'] = cli.peerhost datastore['RPORT'] = cli.peerport if ((p = super(arch, platform, target)) == nil) print_error("Failed to generate payload") return nil end # Allow the payload to start a new handler add_handler({ 'RHOST' => datastore['RHOST'], 'RPORT' => datastore['RPORT'] }) ensure datastore['RHOST'] = ohost datastore['RPORT'] = oport end p end protected attr_accessor :service # :nodoc: end end