diff --git a/lib/rex/post/meterpreter/client.rb b/lib/rex/post/meterpreter/client.rb index fbc797f9fa..240039157e 100644 --- a/lib/rex/post/meterpreter/client.rb +++ b/lib/rex/post/meterpreter/client.rb @@ -194,6 +194,7 @@ class Client self.sock.extend(Rex::Socket::SslTcp) self.sock.sslsock = ssl self.sock.sslctx = ctx + self.sock.sslhash = Rex::Text.sha1_raw(ctx.cert.to_der) tag = self.sock.get_once(-1, 30) if(not tag or tag !~ /^GET \//) @@ -206,6 +207,7 @@ class Client self.sock.sslsock.close self.sock.sslsock = nil self.sock.sslctx = nil + self.sock.sslhash = nil self.sock = self.sock.fd self.sock.extend(::Rex::Socket::Tcp) end diff --git a/lib/rex/post/meterpreter/client_core.rb b/lib/rex/post/meterpreter/client_core.rb index 2749fd9d59..3fdbdb434b 100644 --- a/lib/rex/post/meterpreter/client_core.rb +++ b/lib/rex/post/meterpreter/client_core.rb @@ -258,7 +258,7 @@ class ClientCore < Extension return Rex::Text.md5(id) end - def change_transport(opts={}) + def transport_change(opts={}) unless valid_transport?(opts[:transport]) && opts[:lport] return false @@ -273,7 +273,7 @@ class ClientCore < Extension transport = VALID_TRANSPORTS[opts[:transport]] - request = Packet.create_request('core_change_transport') + request = Packet.create_request('core_transport_change') scheme = opts[:transport].split('_')[1] url = "#{scheme}://#{opts[:lhost]}:#{opts[:lport]}" @@ -322,6 +322,53 @@ class ClientCore < Extension return true end + # + # Enable the SSL certificate has verificate + # + def enable_ssl_hash_verify + # Not supported unless we have a socket with SSL enabled + return nil unless self.client.sock.type? == 'tcp-ssl' + + request = Packet.create_request('core_transport_setcerthash') + + hash = Rex::Text.sha1_raw(self.client.sock.sslctx.cert.to_der) + request.add_tlv(TLV_TYPE_TRANS_CERT_HASH, hash) + + client.send_request(request) + + return hash + end + + # + # Disable the SSL certificate has verificate + # + def disable_ssl_hash_verify + # Not supported unless we have a socket with SSL enabled + return nil unless self.client.sock.type? == 'tcp-ssl' + + request = Packet.create_request('core_transport_setcerthash') + + # send an empty request to disable it + client.send_request(request) + + return true + end + + # + # Attempt to get the SSL hash being used for verificaton (if any). + # + # @return 20-byte sha1 hash currently being used for verification. + # + def get_ssl_hash_verify + # Not supported unless we have a socket with SSL enabled + return nil unless self.client.sock.type? == 'tcp-ssl' + + request = Packet.create_request('core_transport_getcerthash') + response = client.send_request(request) + + return response.get_tlv_value(TLV_TYPE_TRANS_CERT_HASH) + end + # # Migrates the meterpreter instance to the process specified # by pid. The connection to the server remains established. diff --git a/lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb b/lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb index 779143a060..8d9e7e8e20 100644 --- a/lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb +++ b/lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb @@ -28,7 +28,6 @@ class Console::CommandDispatcher::Core self.extensions = [] self.bgjobs = [] self.bgjob_id = 0 - end @@load_opts = Rex::Parser::Arguments.new( @@ -50,7 +49,6 @@ class Console::CommandDispatcher::Core "irb" => "Drop into irb scripting mode", "use" => "Deprecated alias for 'load'", "load" => "Load one or more meterpreter extensions", - "transport" => "Change the current transport mechanism", "machine_id" => "Get the MSF ID of the machine attached to the session", "quit" => "Terminate the meterpreter session", "resource" => "Run the commands stored in a file", @@ -67,10 +65,17 @@ class Console::CommandDispatcher::Core if client.passive_service c["detach"] = "Detach the meterpreter session (for http/https)" end - # The only meterp that implements this right now is native Windows and for - # whatever reason it is not adding core_migrate to its list of commands. - # Use a dumb platform til it gets sorted. - #if client.commands.include? "core_migrate" + + # Currently we have some windows-specific core commands` + if client.platform =~ /win/ + # only support the SSL switching for HTTPS + if client.passive_service && client.sock.type? == 'tcp-ssl' + c["ssl_verify"] = "Modify the SSL certificate verification setting" + end + + c["transport"] = "Change the current transport mechanism" + end + if client.platform =~ /win/ || client.platform =~ /linux/ c["migrate"] = "Migrate the server to another process" end @@ -329,6 +334,87 @@ class Console::CommandDispatcher::Core print_good("Machine ID: #{client.core.machine_id}") end + # + # Arguments for ssl verification + # + @@ssl_verify_opts = Rex::Parser::Arguments.new( + '-e' => [ false, 'Enable SSL certificate verification' ], + '-d' => [ false, 'Disable SSL certificate verification' ], + '-q' => [ false, 'Query the statis of SSL certificate verification' ], + '-h' => [ false, 'Help menu' ]) + + # + # Help for ssl verification + # + def cmd_ssl_verify_help + print_line('Usage: ssl_verify [options]') + print_line + print_line('Change and query the current setting for SSL verification') + print_line('Only one of the following options can be used at a time') + print_line(@@ssl_verify_opts.usage) + end + + # + # Handle the SSL verification querying and setting function. + # + def cmd_ssl_verify(*args) + if ( args.length == 0 or args.include?("-h") ) + cmd_ssl_verify_help + return + end + + query = false + enable = false + disable = false + + settings = 0 + + @@ssl_verify_opts.parse(args) do |opt, idx, val| + case opt + when '-q' + query = true + settings += 1 + when '-e' + enable = true + settings += 1 + when '-d' + disable = true + settings += 1 + end + end + + # Make sure only one action has been chosen + if settings != 1 + cmd_ssl_verify_help + return + end + + if query + hash = client.core.get_ssl_hash_verify + if hash + print_good("SSL verification is enabled. SHA1 Hash: #{hash.unpack("H*")[0]}") + else + print_good("SSL verification is disabled.") + end + + elsif enable + hash = client.core.enable_ssl_hash_verify + if hash + print_good("SSL verification has been enabled. SHA1 Hash: #{hash.unpack("H*")[0]}") + else + print_error("Failed to enable SSL verification") + end + + else + if client.core.disable_ssl_hash_verify + print_good('SSL verification has been disabled') + else + print_error("Failed to disable SSL verification") + end + end + + end + # # Arguments for transport switching # @@ -347,6 +433,9 @@ class Console::CommandDispatcher::Core '-ex' => [ true, "Expiration timout (seconds) for http(s) transports (default: #{Rex::Post::Meterpreter::ClientCore::DEFAULT_SESSION_EXPIRATION})" ], '-h' => [ false, 'Help menu' ]) + # + # Display help for transport switching + # def cmd_transport_help print_line('Usage: transport [options]') print_line @@ -354,6 +443,9 @@ class Console::CommandDispatcher::Core print_line(@@transport_opts.usage) end + # + # Change the current transport setings. + # def cmd_transport(*args) if ( args.length == 0 or args.include?("-h") ) cmd_transport_help @@ -409,7 +501,7 @@ class Console::CommandDispatcher::Core end print_status("Swapping transport ...") - if client.core.change_transport(opts) + if client.core.transport_change(opts) client.shutdown_passive_dispatcher shell.stop else diff --git a/lib/rex/socket/ssl_tcp.rb b/lib/rex/socket/ssl_tcp.rb index b55c5619c7..d5ae19feac 100644 --- a/lib/rex/socket/ssl_tcp.rb +++ b/lib/rex/socket/ssl_tcp.rb @@ -368,6 +368,10 @@ begin attr_reader :ssl_negotiated_version # :nodoc: attr_accessor :sslsock, :sslctx # :nodoc: + def type? + return 'tcp-ssl' + end + protected attr_writer :peer_verified # :nodoc: @@ -377,9 +381,5 @@ protected rescue LoadError end - def type? - return 'tcp-ssl' - end - end