Skip to content

Commit

Permalink
First commit of the smb_version module enhancements
Browse files Browse the repository at this point in the history
  • Loading branch information
zeroSteiner committed Jun 24, 2020
1 parent d3a59dc commit 7ec5696
Show file tree
Hide file tree
Showing 3 changed files with 188 additions and 133 deletions.
3 changes: 3 additions & 0 deletions modules/auxiliary/scanner/smb/smb1.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::Scanner
include Msf::Auxiliary::Report

include Msf::Module::Deprecated
deprecated(Date.new(2020, 10, 6))

# Aliases for common classes
SIMPLE = Rex::Proto::SMB::SimpleClient
XCEPT = Rex::Proto::SMB::Exceptions
Expand Down
3 changes: 3 additions & 0 deletions modules/auxiliary/scanner/smb/smb2.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::Scanner
include Msf::Auxiliary::Report

include Msf::Module::Deprecated
deprecated(Date.new(2020, 10, 6))

# Aliases for common classes
SIMPLE = Rex::Proto::SMB::SimpleClient
XCEPT = Rex::Proto::SMB::Exceptions
Expand Down
315 changes: 182 additions & 133 deletions modules/auxiliary/scanner/smb/smb_version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

class MetasploitModule < Msf::Auxiliary


# Exploit mixins should be called first
include Msf::Exploit::Remote::DCERPC
include Msf::Exploit::Remote::SMB::Client
Expand All @@ -17,11 +16,20 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::Scanner
include Msf::Auxiliary::Report

SMB2_DIALECT_STRINGS = {
'0x0202' => 'SMB 2.0.2',
'0x0210' => 'SMB 2.1',
'0x0300' => 'SMB 3.0',
'0x0302' => 'SMB 3.0.2',
'0x0311' => 'SMB 3.1.1',
'0x02ff' => 'SMB 2.???'
}

def initialize
super(
'Name' => 'SMB Version Detection',
'Description' => 'Display version information about each system',
'Author' => 'hdm',
'Author' => ['hdm', 'Spencer McIntyre'],
'License' => MSF_LICENSE
)

Expand All @@ -39,117 +47,99 @@ def smb_direct
(@smb_port == 445)
end

# Fingerprint a single host
#
def run_host(ip)
smb_ports = [445, 139]
smb_ports.each do |pnum|
@smb_port = pnum
self.simple = nil
def smb_versions
preferred_dialect = nil
supported = []
(1..3).each do |version|
begin
simple = connect(false, versions: [version])
protocol = simple.client.negotiate
rescue Rex::Proto::SMB::Exceptions::Error, RubySMB::Error::RubySMBError
next
rescue Errno::ECONNRESET
next
rescue ::Exception => e
vprint_error("#{rhost}: #{e.class} #{e}")
next
end

begin
res = smb_fingerprint()
preferred_dialect = simple.client.dialect
if simple.client.is_a? RubySMB::Client
preferred_dialect = SMB2_DIALECT_STRINGS[preferred_dialect]
end

#
# Create the note hash for smb.fingerprint
#
conf = {
:native_os => res['native_os'],
:native_lm => res['native_lm']
}
supported << version unless protocol.nil?
end

if res['os'] and res['os'] != 'Unknown'
# assume that if the server supports multiple versions, the preferred
# dialect will correspond to the latest version
{versions: supported, preferred_dialect: preferred_dialect}
end

#
# Create the note hash for fingerprint.match
#
match_conf = { }
def smb_description(res, nd_smb_fingerprint)
#
# Create the note hash for fingerprint.match
#
nd_fingerprint_match = { }

#
# Create a descriptive string for service.info
#
desc = res['os'].dup

if res['edition'].to_s.length > 0
desc << " #{res['edition']}"
nd_smb_fingerprint[:os_edition] = res['edition']
nd_fingerprint_match['os.edition'] = res['edition']
end

#
# Create a descriptive string for service.info
#
desc = res['os'].dup
if res['sp'].to_s.length > 0
desc << " #{res['sp'].downcase.gsub('service pack ', 'SP')}"
nd_smb_fingerprint[:os_sp] = res['sp']
nd_fingerprint_match['os.version'] = res['sp']
end

if res['edition'].to_s.length > 0
desc << " #{res['edition']}"
conf[:os_edition] = res['edition']
match_conf['os.edition'] = res['edition']
end
if res['build'].to_s.length > 0
desc << " (build:#{res['build']})"
nd_smb_fingerprint[:os_build] = res['build']
nd_fingerprint_match['os.build'] = res['build']
end

if res['sp'].to_s.length > 0
desc << " #{res['sp'].downcase.gsub('service pack ', 'SP')}"
conf[:os_sp] = res['sp']
match_conf['os.version'] = res['sp']
end
if res['lang'].to_s.length > 0 and res['lang'] != 'Unknown'
desc << " (language:#{res['lang']})"
nd_smb_fingerprint[:os_lang] = res['lang']
nd_fingerprint_match['os.language'] = nd_smb_fingerprint[:os_lang]
end

if res['build'].to_s.length > 0
desc << " (build:#{res['build']})"
conf[:os_build] = res['build']
match_conf['os.build'] = res['build']
end
if simple.client.default_name
desc << " (name:#{simple.client.default_name})"
nd_smb_fingerprint[:SMBName] = simple.client.default_name
nd_fingerprint_match['host.name'] = nd_smb_fingerprint[:SMBName]
end

if res['lang'].to_s.length > 0 and res['lang'] != 'Unknown'
desc << " (language:#{res['lang']})"
conf[:os_lang] = res['lang']
match_conf['os.language'] = conf[:os_lang]
end
{text: desc, fingerprint_match: nd_fingerprint_match, smb_fingerprint: nd_smb_fingerprint}
end

if simple.client.default_name
desc << " (name:#{simple.client.default_name})"
conf[:SMBName] = simple.client.default_name
match_conf['host.name'] = conf[:SMBName]
end
#
# Fingerprint a single host
#
def run_host(ip)
smb_ports = [445, 139]
smb_ports.each do |pnum|
@smb_port = pnum
self.simple = nil

if simple.client.default_domain
if simple.client.default_domain.encoding.name == "UTF-8"
desc << " (domain:#{simple.client.default_domain})"
else
# Workgroup names are in ANSI, but may contain invalid characters
# Go through each char and convert/check
temp_workgroup = simple.client.default_domain.dup
desc << " (workgroup:"
temp_workgroup.each_char do |i|
begin
desc << i.encode("UTF-8")
rescue Encoding::UndefinedConversionError => e
desc << '?'
print_error("Found incompatible (non-ANSI) character in Workgroup name. Replaced with '?'")
end
end
desc << " )"
end
conf[:SMBDomain] = simple.client.default_domain
match_conf['host.domain'] = conf[:SMBDomain]
end
begin
res = smb_fingerprint()

version_info = smb_versions
#next unless versions.length
desc = "SMB Detected (versions:#{version_info[:versions].join(', ')}) (preferred dialect:#{version_info[:preferred_dialect]})"

if simple.client.peer_require_signing
desc << " (signatures:required)"
else
desc << " (signatures:optional)"
end

print_good("Host is running #{desc}")

# Report the service with a friendly banner
report_service(
:host => ip,
:port => rport,
:proto => 'tcp',
:name => 'smb',
:info => desc
)

# Report a fingerprint.match hash for name, domain, and language
# Ignore OS fields, as those are handled via smb.fingerprint
report_note(
:host => ip,
:port => rport,
:proto => 'tcp',
:ntype => 'fingerprint.match',
:data => match_conf
)

unless simple.client.require_signing
report_vuln({
:host => ip,
:port => rport,
Expand All @@ -161,45 +151,104 @@ def run_host(ip)
]
})
end
else
desc = "#{res['native_os']} (#{res['native_lm']})"
report_service(:host => ip, :port => rport, :name => 'smb', :info => desc)
print_status("Host could not be identified: #{desc}")
end
print_status(desc)

# Report a smb.fingerprint hash of attributes for OS fingerprinting
report_note(
:host => ip,
:port => rport,
:proto => 'tcp',
:ntype => 'smb.fingerprint',
:data => conf
)

disconnect

break

rescue ::Rex::Proto::SMB::Exceptions::NoReply => e
next
rescue ::Rex::Proto::SMB::Exceptions::ErrorCode => e
next
rescue ::Rex::Proto::SMB::Exceptions::LoginError => e
# Vista has 139 open but doesnt like *SMBSERVER
if(e.to_s =~ /server refused our NetBIOS/)
next
end
#
# Create the note hash for smb.fingerprint
#
nd_smb_fingerprint = {
:native_os => res['native_os'],
:native_lm => res['native_lm']
}

if res['os'] && res['os'] != 'Unknown'
description = smb_description(res, nd_smb_fingerprint)
desc = description[:text]
nd_fingerprint_match = description[:fingerprint_match]
nd_smb_fingerprint = description[:smb_fingerprint]

if simple.client.default_domain
if simple.client.default_domain.encoding.name == "UTF-8"
desc << " (domain:#{simple.client.default_domain})"
else
# Workgroup names are in ANSI, but may contain invalid characters
# Go through each char and convert/check
temp_workgroup = simple.client.default_domain.dup
desc << " (workgroup:"
temp_workgroup.each_char do |i|
begin
desc << i.encode("UTF-8")
rescue Encoding::UndefinedConversionError => e
desc << '?'
vprint_error("Found incompatible (non-ANSI) character in Workgroup name. Replaced with '?'")
end
end
desc << ")"
end
nd_smb_fingerprint[:SMBDomain] = simple.client.default_domain
nd_fingerprint_match['host.domain'] = nd_smb_fingerprint[:SMBDomain]
end

return
rescue ::Timeout::Error
rescue ::Rex::ConnectionError
next
print_good(" Host is running #{desc}")

rescue ::Exception => e
print_error("#{rhost}: #{e.class} #{e}")
ensure
disconnect
end
# Report the service with a friendly banner
report_service(
:host => ip,
:port => rport,
:proto => 'tcp',
:name => 'smb',
:info => desc
)

# Report a fingerprint.match hash for name, domain, and language
# Ignore OS fields, as those are handled via smb.fingerprint
report_note(
:host => ip,
:port => rport,
:proto => 'tcp',
:ntype => 'fingerprint.match',
:data => nd_fingerprint_match
)
else
desc = ''
if res['native_os'] || res['native_lm']
desc = "#{res['native_os']} (#{res['native_lm']})"
report_service(:host => ip, :port => rport, :name => 'smb', :info => desc)
desc = ': ' + desc
end
print_status(" Host could not be identified#{desc}")
end

# Report a smb.fingerprint hash of attributes for OS fingerprinting
report_note(
:host => ip,
:port => rport,
:proto => 'tcp',
:ntype => 'smb.fingerprint',
:data => nd_smb_fingerprint
)

disconnect

break

rescue ::Rex::Proto::SMB::Exceptions::NoReply => e
next
rescue ::Rex::Proto::SMB::Exceptions::ErrorCode => e
next
rescue ::Rex::Proto::SMB::Exceptions::LoginError => e
# Vista has 139 open but doesnt like *SMBSERVER
next if e.to_s =~ /server refused our NetBIOS/
return
rescue ::Timeout::Error
rescue ::Rex::ConnectionError
next

rescue ::Exception => e
print_error("#{rhost}: #{e.class} #{e}")
ensure
disconnect
end
end
end
end

0 comments on commit 7ec5696

Please sign in to comment.