Skip to content

Commit 75b559e

Browse files
author
Brent Cook
committed
Land rapid7#5081, meterpreter certificate hash check controls
2 parents 97e715b + 0e864e1 commit 75b559e

File tree

6 files changed

+158
-17
lines changed

6 files changed

+158
-17
lines changed

Gemfile.lock

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ PATH
99
json
1010
metasploit-concern (~> 0.3.0)
1111
metasploit-model (~> 0.29.0)
12-
meterpreter_bins (= 0.0.18)
12+
meterpreter_bins (= 0.0.21)
1313
msgpack
1414
nokogiri
1515
packetfu (= 1.1.9)
@@ -132,7 +132,7 @@ GEM
132132
pg
133133
railties (< 4.0.0)
134134
recog (~> 1.0)
135-
meterpreter_bins (0.0.18)
135+
meterpreter_bins (0.0.21)
136136
method_source (0.8.2)
137137
mime-types (1.25.1)
138138
mini_portile (0.6.2)

lib/rex/post/meterpreter/client.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ def swap_sock_plain_to_ssl
194194
self.sock.extend(Rex::Socket::SslTcp)
195195
self.sock.sslsock = ssl
196196
self.sock.sslctx = ctx
197+
self.sock.sslhash = Rex::Text.sha1_raw(ctx.cert.to_der)
197198

198199
tag = self.sock.get_once(-1, 30)
199200
if(not tag or tag !~ /^GET \//)
@@ -206,6 +207,7 @@ def swap_sock_ssl_to_plain
206207
self.sock.sslsock.close
207208
self.sock.sslsock = nil
208209
self.sock.sslctx = nil
210+
self.sock.sslhash = nil
209211
self.sock = self.sock.fd
210212
self.sock.extend(::Rex::Socket::Tcp)
211213
end

lib/rex/post/meterpreter/client_core.rb

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ def machine_id
255255
return Rex::Text.md5(id)
256256
end
257257

258-
def change_transport(opts={})
258+
def transport_change(opts={})
259259

260260
unless valid_transport?(opts[:transport]) && opts[:lport]
261261
return false
@@ -270,7 +270,7 @@ def change_transport(opts={})
270270

271271
transport = VALID_TRANSPORTS[opts[:transport]]
272272

273-
request = Packet.create_request('core_change_transport')
273+
request = Packet.create_request('core_transport_change')
274274

275275
scheme = opts[:transport].split('_')[1]
276276
url = "#{scheme}://#{opts[:lhost]}:#{opts[:lport]}"
@@ -326,6 +326,53 @@ def change_transport(opts={})
326326
return true
327327
end
328328

329+
#
330+
# Enable the SSL certificate has verificate
331+
#
332+
def enable_ssl_hash_verify
333+
# Not supported unless we have a socket with SSL enabled
334+
return nil unless self.client.sock.type? == 'tcp-ssl'
335+
336+
request = Packet.create_request('core_transport_setcerthash')
337+
338+
hash = Rex::Text.sha1_raw(self.client.sock.sslctx.cert.to_der)
339+
request.add_tlv(TLV_TYPE_TRANS_CERT_HASH, hash)
340+
341+
client.send_request(request)
342+
343+
return hash
344+
end
345+
346+
#
347+
# Disable the SSL certificate has verificate
348+
#
349+
def disable_ssl_hash_verify
350+
# Not supported unless we have a socket with SSL enabled
351+
return nil unless self.client.sock.type? == 'tcp-ssl'
352+
353+
request = Packet.create_request('core_transport_setcerthash')
354+
355+
# send an empty request to disable it
356+
client.send_request(request)
357+
358+
return true
359+
end
360+
361+
#
362+
# Attempt to get the SSL hash being used for verificaton (if any).
363+
#
364+
# @return 20-byte sha1 hash currently being used for verification.
365+
#
366+
def get_ssl_hash_verify
367+
# Not supported unless we have a socket with SSL enabled
368+
return nil unless self.client.sock.type? == 'tcp-ssl'
369+
370+
request = Packet.create_request('core_transport_getcerthash')
371+
response = client.send_request(request)
372+
373+
return response.get_tlv_value(TLV_TYPE_TRANS_CERT_HASH)
374+
end
375+
329376
#
330377
# Migrates the meterpreter instance to the process specified
331378
# by pid. The connection to the server remains established.

lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb

Lines changed: 99 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ def initialize(shell)
2828
self.extensions = []
2929
self.bgjobs = []
3030
self.bgjob_id = 0
31-
3231
end
3332

3433
@@load_opts = Rex::Parser::Arguments.new(
@@ -50,7 +49,6 @@ def commands
5049
"irb" => "Drop into irb scripting mode",
5150
"use" => "Deprecated alias for 'load'",
5251
"load" => "Load one or more meterpreter extensions",
53-
"transport" => "Change the current transport mechanism",
5452
"machine_id" => "Get the MSF ID of the machine attached to the session",
5553
"quit" => "Terminate the meterpreter session",
5654
"resource" => "Run the commands stored in a file",
@@ -67,10 +65,17 @@ def commands
6765
if client.passive_service
6866
c["detach"] = "Detach the meterpreter session (for http/https)"
6967
end
70-
# The only meterp that implements this right now is native Windows and for
71-
# whatever reason it is not adding core_migrate to its list of commands.
72-
# Use a dumb platform til it gets sorted.
73-
#if client.commands.include? "core_migrate"
68+
69+
# Currently we have some windows-specific core commands`
70+
if client.platform =~ /win/
71+
# only support the SSL switching for HTTPS
72+
if client.passive_service && client.sock.type? == 'tcp-ssl'
73+
c["ssl_verify"] = "Modify the SSL certificate verification setting"
74+
end
75+
76+
c["transport"] = "Change the current transport mechanism"
77+
end
78+
7479
if client.platform =~ /win/ || client.platform =~ /linux/
7580
c["migrate"] = "Migrate the server to another process"
7681
end
@@ -329,6 +334,87 @@ def cmd_machine_id(*args)
329334
print_good("Machine ID: #{client.core.machine_id}")
330335
end
331336

337+
#
338+
# Arguments for ssl verification
339+
#
340+
@@ssl_verify_opts = Rex::Parser::Arguments.new(
341+
'-e' => [ false, 'Enable SSL certificate verification' ],
342+
'-d' => [ false, 'Disable SSL certificate verification' ],
343+
'-q' => [ false, 'Query the statis of SSL certificate verification' ],
344+
'-h' => [ false, 'Help menu' ])
345+
346+
#
347+
# Help for ssl verification
348+
#
349+
def cmd_ssl_verify_help
350+
print_line('Usage: ssl_verify [options]')
351+
print_line
352+
print_line('Change and query the current setting for SSL verification')
353+
print_line('Only one of the following options can be used at a time')
354+
print_line(@@ssl_verify_opts.usage)
355+
end
356+
357+
#
358+
# Handle the SSL verification querying and setting function.
359+
#
360+
def cmd_ssl_verify(*args)
361+
if ( args.length == 0 or args.include?("-h") )
362+
cmd_ssl_verify_help
363+
return
364+
end
365+
366+
query = false
367+
enable = false
368+
disable = false
369+
370+
settings = 0
371+
372+
@@ssl_verify_opts.parse(args) do |opt, idx, val|
373+
case opt
374+
when '-q'
375+
query = true
376+
settings += 1
377+
when '-e'
378+
enable = true
379+
settings += 1
380+
when '-d'
381+
disable = true
382+
settings += 1
383+
end
384+
end
385+
386+
# Make sure only one action has been chosen
387+
if settings != 1
388+
cmd_ssl_verify_help
389+
return
390+
end
391+
392+
if query
393+
hash = client.core.get_ssl_hash_verify
394+
if hash
395+
print_good("SSL verification is enabled. SHA1 Hash: #{hash.unpack("H*")[0]}")
396+
else
397+
print_good("SSL verification is disabled.")
398+
end
399+
400+
elsif enable
401+
hash = client.core.enable_ssl_hash_verify
402+
if hash
403+
print_good("SSL verification has been enabled. SHA1 Hash: #{hash.unpack("H*")[0]}")
404+
else
405+
print_error("Failed to enable SSL verification")
406+
end
407+
408+
else
409+
if client.core.disable_ssl_hash_verify
410+
print_good('SSL verification has been disabled')
411+
else
412+
print_error("Failed to disable SSL verification")
413+
end
414+
end
415+
416+
end
417+
332418
#
333419
# Arguments for transport switching
334420
#
@@ -347,13 +433,19 @@ def cmd_machine_id(*args)
347433
'-ex' => [ true, "Expiration timout (seconds) for http(s) transports (default: #{Rex::Post::Meterpreter::ClientCore::DEFAULT_SESSION_EXPIRATION})" ],
348434
'-h' => [ false, 'Help menu' ])
349435

436+
#
437+
# Display help for transport switching
438+
#
350439
def cmd_transport_help
351440
print_line('Usage: transport [options]')
352441
print_line
353442
print_line('Change the current Meterpreter transport mechanism')
354443
print_line(@@transport_opts.usage)
355444
end
356445

446+
#
447+
# Change the current transport setings.
448+
#
357449
def cmd_transport(*args)
358450
if ( args.length == 0 or args.include?("-h") )
359451
cmd_transport_help
@@ -409,7 +501,7 @@ def cmd_transport(*args)
409501
end
410502

411503
print_status("Swapping transport ...")
412-
if client.core.change_transport(opts)
504+
if client.core.transport_change(opts)
413505
client.shutdown_passive_dispatcher
414506
shell.stop
415507
else

lib/rex/socket/ssl_tcp.rb

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,11 @@ def allow_nonblock?
366366

367367
attr_reader :peer_verified # :nodoc:
368368
attr_reader :ssl_negotiated_version # :nodoc:
369-
attr_accessor :sslsock, :sslctx # :nodoc:
369+
attr_accessor :sslsock, :sslctx, :sslhash # :nodoc:
370+
371+
def type?
372+
return 'tcp-ssl'
373+
end
370374

371375
protected
372376

@@ -377,9 +381,5 @@ def allow_nonblock?
377381
rescue LoadError
378382
end
379383

380-
def type?
381-
return 'tcp-ssl'
382-
end
383-
384384
end
385385

metasploit-framework.gemspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ Gem::Specification.new do |spec|
6464
# are needed when there's no database
6565
spec.add_runtime_dependency 'metasploit-model', '~> 0.29.0'
6666
# Needed for Meterpreter on Windows, soon others.
67-
spec.add_runtime_dependency 'meterpreter_bins', '0.0.18'
67+
spec.add_runtime_dependency 'meterpreter_bins', '0.0.21'
6868
# Needed by msfgui and other rpc components
6969
spec.add_runtime_dependency 'msgpack'
7070
# Needed by anemone crawler

0 commit comments

Comments
 (0)