Skip to content

Commit 5ac97d1

Browse files
author
HD Moore
committed
Lands rapid7#5538, adds Recog to ssh_version
2 parents 8d640a0 + 079a9d4 commit 5ac97d1

File tree

1 file changed

+48
-29
lines changed

1 file changed

+48
-29
lines changed

modules/auxiliary/scanner/ssh/ssh_version.rb

Lines changed: 48 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,68 +4,87 @@
44
##
55

66
require 'msf/core'
7-
7+
require 'recog'
88

99
class Metasploit3 < Msf::Auxiliary
10-
1110
include Msf::Exploit::Remote::Tcp
1211
include Msf::Auxiliary::Scanner
1312
include Msf::Auxiliary::Report
1413

14+
# the default timeout (in seconds) to wait, in total, for both a successful
15+
# connection to a given endpoint and for the initial protocol response
16+
# from the supposed SSH endpoint to be returned
17+
DEFAULT_TIMEOUT = 30
18+
1519
def initialize
1620
super(
1721
'Name' => 'SSH Version Scanner',
1822
'Description' => 'Detect SSH Version.',
1923
'References' =>
2024
[
21-
[ 'URL', 'http://en.wikipedia.org/wiki/SecureShell' ],
25+
[ 'URL', 'http://en.wikipedia.org/wiki/SecureShell' ]
2226
],
2327
'Author' => [ 'Daniel van Eeden <metasploit[at]myname.nl>' ],
2428
'License' => MSF_LICENSE
2529
)
2630

2731
register_options(
28-
[
29-
Opt::RPORT(22),
30-
OptInt.new('TIMEOUT', [true, 'Timeout for the SSH probe', 30])
31-
], self.class)
32+
[
33+
Opt::RPORT(22),
34+
OptInt.new('TIMEOUT', [true, 'Timeout for the SSH probe', DEFAULT_TIMEOUT])
35+
],
36+
self.class
37+
)
38+
end
39+
40+
def peer
41+
"#{rhost}:#{rport}"
3242
end
3343

34-
def to
35-
return 30 if datastore['TIMEOUT'].to_i.zero?
36-
datastore['TIMEOUT'].to_i
44+
def timeout
45+
datastore['TIMEOUT'] <= 0 ? DEFAULT_TIMEOUT : datastore['TIMEOUT']
3746
end
3847

48+
3949
def run_host(target_host)
4050
begin
41-
::Timeout.timeout(to) do
42-
51+
::Timeout.timeout(timeout) do
4352
connect
4453

45-
resp = sock.get_once(-1, 5)
54+
resp = sock.get_once(-1, timeout)
4655

47-
if (resp and resp =~ /SSH/)
48-
ver,msg = (resp.split(/[\r\n]+/))
49-
# Check to see if this is Kippo, which sends a premature
50-
# key init exchange right on top of the SSH version without
51-
# waiting for the required client identification string.
52-
if msg and msg.size >= 5
53-
extra = msg.unpack("NCCA*") # sz, pad_sz, code, data
54-
if (extra.last.size+2 == extra[0]) and extra[2] == 20
55-
ver << " (Kippo Honeypot)"
56+
if resp
57+
ident, first_message = resp.split(/[\r\n]+/)
58+
if /^SSH-\d+\.\d+-(?<banner>.*)$/ =~ ident
59+
if recog_match = Recog::Nizer.match('ssh.banner', banner)
60+
info = recog_match.to_s
61+
else
62+
info = 'UNKNOWN'
63+
print_warning("#{peer} unknown SSH banner: #{banner}")
64+
end
65+
# Check to see if this is Kippo, which sends a premature
66+
# key init exchange right on top of the SSH version without
67+
# waiting for the required client identification string.
68+
if first_message && first_message.size >= 5
69+
extra = first_message.unpack("NCCA*") # sz, pad_sz, code, data
70+
if (extra.last.size + 2 == extra[0]) && extra[2] == 20
71+
info << " (Kippo Honeypot)"
72+
end
5673
end
74+
print_status("#{peer}, SSH server version: #{ident}")
75+
report_service(host: rhost, port: rport, name: 'ssh', proto: 'tcp', info: info)
76+
else
77+
vprint_warning("#{peer} was not SSH --" \
78+
" #{resp.size} bytes beginning with #{resp[0, 12]}")
5779
end
58-
print_status("#{target_host}:#{rport}, SSH server version: #{ver}")
59-
report_service(:host => rhost, :port => rport, :name => "ssh", :proto => "tcp", :info => ver)
6080
else
61-
print_error("#{target_host}:#{rport}, SSH server version detection failed!")
81+
vprint_warning("#{peer} no response")
6282
end
63-
64-
disconnect
6583
end
66-
6784
rescue Timeout::Error
68-
print_error("#{target_host}:#{rport}, Server timed out after #{to} seconds. Skipping.")
85+
vprint_warning("#{peer} timed out after #{timeout} seconds. Skipping.")
86+
ensure
87+
disconnect
6988
end
7089
end
7190
end

0 commit comments

Comments
 (0)