2009-11-05 20:26:28 +00:00
|
|
|
|
|
|
|
require 'rexml/document'
|
2009-11-18 06:15:45 +00:00
|
|
|
require 'rex/parser/nmap_xml'
|
2009-11-05 20:26:28 +00:00
|
|
|
|
2006-05-30 15:44:48 +00:00
|
|
|
module Msf
|
|
|
|
module Ui
|
|
|
|
module Console
|
|
|
|
module CommandDispatcher
|
2009-03-28 21:42:30 +00:00
|
|
|
class Db
|
2006-05-30 15:44:48 +00:00
|
|
|
|
2006-09-17 22:07:52 +00:00
|
|
|
require 'tempfile'
|
2009-03-28 21:42:30 +00:00
|
|
|
|
|
|
|
include Msf::Ui::Console::CommandDispatcher
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2006-09-17 22:07:52 +00:00
|
|
|
#
|
|
|
|
# Constants
|
|
|
|
#
|
|
|
|
|
2006-12-10 08:21:52 +00:00
|
|
|
PWN_SHOW = 2**0
|
|
|
|
PWN_XREF = 2**1
|
|
|
|
PWN_PORT = 2**2
|
|
|
|
PWN_EXPL = 2**3
|
|
|
|
PWN_SING = 2**4
|
2008-11-18 22:01:15 +00:00
|
|
|
PWN_SLNT = 2**5
|
2009-12-03 01:36:17 +00:00
|
|
|
PWN_VERB = 2**6
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2006-05-30 15:44:48 +00:00
|
|
|
#
|
|
|
|
# The dispatcher's name.
|
|
|
|
#
|
|
|
|
def name
|
|
|
|
"Database Backend"
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Returns the hash of commands supported by this dispatcher.
|
|
|
|
#
|
|
|
|
def commands
|
2009-03-28 21:42:30 +00:00
|
|
|
base = {
|
|
|
|
"db_driver" => "Specify a database driver",
|
|
|
|
"db_connect" => "Connect to an existing database",
|
|
|
|
"db_disconnect" => "Disconnect from the current database instance",
|
|
|
|
"db_create" => "Create a brand new database",
|
|
|
|
"db_destroy" => "Drop an existing database",
|
|
|
|
}
|
|
|
|
|
|
|
|
more = {
|
2009-12-14 22:52:34 +00:00
|
|
|
"db_workspace" => "Switch between database workspaces",
|
2009-03-28 21:42:30 +00:00
|
|
|
"db_hosts" => "List all hosts in the database",
|
|
|
|
"db_services" => "List all services in the database",
|
|
|
|
"db_vulns" => "List all vulnerabilities in the database",
|
|
|
|
"db_notes" => "List all notes in the database",
|
|
|
|
"db_add_host" => "Add one or more hosts to the database",
|
|
|
|
"db_add_port" => "Add a port to host",
|
|
|
|
"db_add_note" => "Add a note to host",
|
|
|
|
"db_del_host" => "Delete one or more hosts from the database",
|
2009-04-26 14:53:37 +00:00
|
|
|
"db_del_port" => "Delete one port from the database",
|
2009-03-28 21:42:30 +00:00
|
|
|
"db_autopwn" => "Automatically exploit everything",
|
|
|
|
"db_import_amap_mlog" => "Import a THC-Amap scan results file (-o -m)",
|
|
|
|
"db_import_nessus_nbe" => "Import a Nessus scan result file (NBE)",
|
2009-09-05 04:29:53 +00:00
|
|
|
"db_import_nessus_xml" => "Import a Nessus scan result file (NESSUS)",
|
2009-03-28 21:42:30 +00:00
|
|
|
"db_import_nmap_xml" => "Import a Nmap scan results file (-oX)",
|
|
|
|
"db_nmap" => "Executes nmap and records the output automatically",
|
2006-05-30 15:44:48 +00:00
|
|
|
}
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
framework.db.active ? base.merge(more) : base
|
2006-05-30 15:44:48 +00:00
|
|
|
end
|
|
|
|
|
2009-12-14 22:52:34 +00:00
|
|
|
def cmd_db_workspace(*args)
|
|
|
|
while (arg = args.shift)
|
|
|
|
case arg
|
|
|
|
when '-h','--help'
|
|
|
|
print_line("Usage:")
|
|
|
|
print_line(" db_workspace List workspaces")
|
|
|
|
print_line(" db_workspace [name] Switch workspace")
|
|
|
|
print_line(" db_workspace -a [name] Add workspace")
|
|
|
|
print_line(" db_workspace -d [name] Delete workspace")
|
|
|
|
print_line(" db_workspace -h Show this help information")
|
|
|
|
return
|
|
|
|
when '-a','--add'
|
|
|
|
adding = true
|
|
|
|
when '-d','--del'
|
|
|
|
deleting = true
|
|
|
|
else
|
|
|
|
name = arg
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
if adding and name
|
|
|
|
# Add workspace
|
|
|
|
workspace = framework.db.add_workspace(nil, name)
|
|
|
|
print_status("Added workspace: #{workspace.name}")
|
|
|
|
framework.db.workspace = workspace
|
|
|
|
elsif deleting and name
|
|
|
|
# Delete workspace
|
|
|
|
workspace = framework.db.find_workspace(name)
|
|
|
|
if workspace.nil?
|
|
|
|
print_error("Workspace not found: #{name}")
|
|
|
|
elsif workspace.default?
|
|
|
|
print_error("Can't delete default workspace")
|
|
|
|
else
|
|
|
|
workspace.destroy
|
|
|
|
print_status("Deleted workspace: #{name}")
|
|
|
|
framework.db.workspace = framework.db.default_workspace if framework.db.workspace == workspace
|
|
|
|
end
|
|
|
|
elsif name
|
|
|
|
# Switch workspace
|
|
|
|
workspace = framework.db.find_workspace(name)
|
|
|
|
if workspace
|
|
|
|
framework.db.workspace = workspace
|
|
|
|
print_status("Workspace: #{workspace.name}")
|
|
|
|
else
|
|
|
|
print_error("Workspace not found: #{name}")
|
|
|
|
return
|
|
|
|
end
|
|
|
|
else
|
|
|
|
# List workspaces
|
|
|
|
framework.db.workspaces.each do |s|
|
|
|
|
pad = (s == framework.db.workspace) ? "* " : " "
|
|
|
|
print_line(pad + s.name)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def cmd_db_workspace_tabs(str, words)
|
|
|
|
framework.db.workspaces.map { |s| s.name } if (words & ['-a','--add']).empty?
|
|
|
|
end
|
|
|
|
|
2009-11-06 21:08:34 +00:00
|
|
|
def cmd_db_hosts(*args)
|
|
|
|
onlyup = false
|
2009-12-18 01:14:05 +00:00
|
|
|
host_search = nil
|
2009-11-06 21:08:34 +00:00
|
|
|
while (arg = args.shift)
|
|
|
|
case arg
|
|
|
|
when '-u','--up'
|
|
|
|
onlyup = true
|
|
|
|
when '-a'
|
|
|
|
hostlist = args.shift
|
|
|
|
if(!hostlist)
|
2009-12-18 01:14:05 +00:00
|
|
|
print_status("Invalid host list")
|
2009-11-06 21:08:34 +00:00
|
|
|
return
|
|
|
|
end
|
2009-12-18 01:14:05 +00:00
|
|
|
host_search = hostlist.strip().split(",")
|
2009-11-06 21:08:34 +00:00
|
|
|
when '-h','--help'
|
|
|
|
print_status("Usage: db_hosts [-h|--help] [-u|--up] [-a <addr1,addr2>]")
|
|
|
|
print_line(" -u,--up Only show hosts which are up")
|
|
|
|
print_line(" -a <addr1,addr2> Search for a list of addresses")
|
|
|
|
print_line(" -h,--help Show this help information")
|
|
|
|
return
|
|
|
|
end
|
2006-05-30 15:44:48 +00:00
|
|
|
end
|
2009-11-06 21:08:34 +00:00
|
|
|
|
2009-12-18 01:14:05 +00:00
|
|
|
columns = framework.db.hosts.columns_hash.keys.sort
|
|
|
|
columns.delete_if {|v| (v[-2,2] == "id")}
|
|
|
|
columns += ["Svcs", "Vulns", "Workspace"]
|
|
|
|
tbl = Rex::Ui::Text::Table.new({
|
|
|
|
'Header' => "Hosts",
|
|
|
|
'Columns' => columns,
|
|
|
|
})
|
|
|
|
hosts = framework.db.hosts.find(:all, :include => [:services, :vulns, :workspace], :order => :address)
|
|
|
|
hosts.each do |host|
|
2009-11-06 21:08:34 +00:00
|
|
|
next if(onlyup and host.state == "down")
|
2009-12-18 01:14:05 +00:00
|
|
|
next if(host_search != nil and host_search.index(host.address) == nil)
|
|
|
|
columns = []
|
|
|
|
host.attributes.each { |k,v|
|
|
|
|
next if k[-2,2] == "id"
|
|
|
|
columns << (v.nil? ? "" : v)
|
|
|
|
}
|
|
|
|
columns += [host.services.length, host.vulns.length, host.workspace.name]
|
|
|
|
tbl << columns
|
2009-11-06 21:08:34 +00:00
|
|
|
end
|
2009-12-18 01:14:05 +00:00
|
|
|
print_line
|
|
|
|
print_line tbl.to_s
|
2009-11-06 21:08:34 +00:00
|
|
|
end
|
2006-05-30 15:44:48 +00:00
|
|
|
|
|
|
|
def cmd_db_services(*args)
|
2009-11-06 21:08:34 +00:00
|
|
|
onlyup = false
|
2009-12-18 01:14:05 +00:00
|
|
|
host_search = nil
|
|
|
|
port_search = nil
|
|
|
|
proto_search = nil
|
|
|
|
name_search = nil
|
2009-11-06 21:08:34 +00:00
|
|
|
while (arg = args.shift)
|
|
|
|
case arg
|
|
|
|
when '-u','--up'
|
|
|
|
onlyup = true
|
|
|
|
when '-a'
|
|
|
|
hostlist = args.shift
|
|
|
|
if(!hostlist)
|
|
|
|
print_status("Invalid host list")
|
|
|
|
return
|
|
|
|
end
|
2009-12-18 01:14:05 +00:00
|
|
|
host_search = hostlist.strip().split(",")
|
2009-11-06 21:08:34 +00:00
|
|
|
when '-p'
|
|
|
|
portlist = args.shift
|
|
|
|
if(!portlist)
|
|
|
|
print_status("Invalid port list")
|
|
|
|
return
|
|
|
|
end
|
2009-12-18 01:14:05 +00:00
|
|
|
port_search = portlist.strip().split(",")
|
2009-11-06 21:08:34 +00:00
|
|
|
when '-r'
|
2009-12-18 01:14:05 +00:00
|
|
|
proto_search = args.shift
|
|
|
|
if(proto_search == nil)
|
2009-11-06 21:08:34 +00:00
|
|
|
print_status("Invalid protocol")
|
|
|
|
return
|
|
|
|
end
|
2009-12-18 01:14:05 +00:00
|
|
|
proto_search = proto_search.strip()
|
2009-11-06 21:08:34 +00:00
|
|
|
when '-n'
|
|
|
|
namelist = args.shift
|
|
|
|
if(!namelist)
|
|
|
|
print_status("Invalid name list")
|
|
|
|
return
|
|
|
|
end
|
2009-12-18 01:14:05 +00:00
|
|
|
name_search = namelist.strip().split(",")
|
2009-11-06 21:08:34 +00:00
|
|
|
|
|
|
|
when '-h','--help'
|
|
|
|
print_status("Usage: db_services [-h|--help] [-u|--up] [-a <addr1,addr2>] [-r <proto>] [-p <port1,port2>] [-n <name1,name2>]")
|
2009-11-11 00:29:44 +00:00
|
|
|
print_line(" -u,--up Only show services which are up")
|
2009-11-06 21:08:34 +00:00
|
|
|
print_line(" -r <protocol> Only show [tcp|udp] services")
|
|
|
|
print_line(" -a <addr1,addr2> Search for a list of addresses")
|
|
|
|
print_line(" -p <port1,port2> Search for a list of ports")
|
|
|
|
print_line(" -n <name1,name2> Search for a list of service names")
|
|
|
|
print_line(" -h,--help Show this help information")
|
|
|
|
return
|
|
|
|
end
|
2006-05-30 15:44:48 +00:00
|
|
|
end
|
2009-12-18 01:14:05 +00:00
|
|
|
columns = ::Msf::DBManager::Service.columns_hash.keys.sort
|
|
|
|
columns.delete_if {|v| (v[-2,2] == "id")}
|
|
|
|
columns += ["Host", "Workspace"]
|
|
|
|
tbl = Rex::Ui::Text::Table.new({
|
|
|
|
'Header' => "Services",
|
|
|
|
'Columns' => columns,
|
|
|
|
})
|
|
|
|
hosts = framework.db.hosts.find(:all, :include => [:services, :workspace], :order => :address)
|
|
|
|
hosts.each do |host|
|
|
|
|
host.services.sort{|a,b| a.port<=>b.port }.each do |svc|
|
|
|
|
next if(onlyup and svc.state == "down")
|
|
|
|
next if(proto_search and svc.proto != proto_search)
|
|
|
|
next if(host_search and host_search.index(host.address) == nil)
|
|
|
|
next if(port_search and port_search.index(svc.port.to_s) == nil)
|
|
|
|
next if(name_search and name_search.index(svc.name) == nil)
|
|
|
|
columns = []
|
|
|
|
svc.attributes.each { |k,v|
|
|
|
|
next if k[-2,2] == "id"
|
|
|
|
columns << (v.nil? ? "" : v)
|
|
|
|
}
|
|
|
|
columns += [host.address, host.workspace.name]
|
|
|
|
tbl << columns
|
|
|
|
end
|
|
|
|
end
|
|
|
|
print_line
|
|
|
|
print_line tbl.to_s
|
|
|
|
end
|
2009-11-06 21:08:34 +00:00
|
|
|
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2006-05-30 15:44:48 +00:00
|
|
|
def cmd_db_vulns(*args)
|
|
|
|
framework.db.each_vuln do |vuln|
|
2006-09-16 20:08:13 +00:00
|
|
|
reflist = vuln.refs.map { |r| r.name }
|
2009-11-25 01:44:55 +00:00
|
|
|
if(vuln.service)
|
|
|
|
print_status("Time: #{vuln.created} Vuln: host=#{vuln.host.address} port=#{vuln.service.port} proto=#{vuln.service.proto} name=#{vuln.name} refs=#{reflist.join(',')}")
|
|
|
|
else
|
|
|
|
print_status("Time: #{vuln.created} Vuln: host=#{vuln.host.address} name=#{vuln.name} refs=#{reflist.join(',')}")
|
|
|
|
end
|
2006-05-30 15:44:48 +00:00
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
end
|
2008-03-02 04:46:13 +00:00
|
|
|
|
2009-11-06 21:08:34 +00:00
|
|
|
def cmd_db_notes(*args)
|
|
|
|
hosts = nil
|
|
|
|
types = nil
|
|
|
|
while (arg = args.shift)
|
|
|
|
case arg
|
|
|
|
when '-a'
|
|
|
|
hostlist = args.shift
|
|
|
|
if(!hostlist)
|
|
|
|
print_status("Invalid host list")
|
|
|
|
return
|
|
|
|
end
|
|
|
|
hosts = hostlist.strip().split(",")
|
|
|
|
when '-t'
|
|
|
|
typelist = args.shift
|
|
|
|
if(!typelist)
|
|
|
|
print_status("Invalid host list")
|
|
|
|
return
|
|
|
|
end
|
|
|
|
types = typelist.strip().split(",")
|
|
|
|
when '-h','--help'
|
|
|
|
print_status("Usage: db_notes [-h|--help] [-a <addr1,addr2>] [-t <type1,type2>]")
|
|
|
|
print_line(" -a <addr1,addr2> Search for a list of addresses")
|
|
|
|
print_line(" -t <type1,type2> Search for a list of types")
|
|
|
|
print_line(" -h,--help Show this help information")
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2008-03-02 04:46:13 +00:00
|
|
|
end
|
2009-11-06 21:08:34 +00:00
|
|
|
framework.db.each_note do |note|
|
|
|
|
next if(hosts and hosts.index(note.host.address) == nil)
|
|
|
|
next if(types and types.index(note.ntype) == nil)
|
|
|
|
print_status("Time: #{note.created} Note: host=#{note.host.address} type=#{note.ntype} data=#{note.data}")
|
|
|
|
end
|
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2006-05-30 15:44:48 +00:00
|
|
|
def cmd_db_add_host(*args)
|
2008-12-19 07:11:08 +00:00
|
|
|
print_status("Adding #{args.length} hosts...")
|
2006-05-30 15:44:48 +00:00
|
|
|
args.each do |address|
|
2008-03-02 04:46:13 +00:00
|
|
|
host = framework.db.get_host(nil, address)
|
2008-10-27 22:47:09 +00:00
|
|
|
print_status("Time: #{host.created} Host: host=#{host.address}")
|
2006-05-30 15:44:48 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def cmd_db_add_port(*args)
|
|
|
|
if (not args or args.length < 3)
|
|
|
|
print_status("Usage: db_add_port [host] [port] [proto]")
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
host = framework.db.get_host(nil, args[0])
|
|
|
|
return if not host
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2006-05-30 15:44:48 +00:00
|
|
|
service = framework.db.get_service(nil, host, args[2].downcase, args[1].to_i)
|
|
|
|
return if not service
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2008-03-02 04:46:13 +00:00
|
|
|
print_status("Time: #{service.created} Service: host=#{service.host.address} port=#{service.port} proto=#{service.proto} state=#{service.state}")
|
2006-05-30 15:44:48 +00:00
|
|
|
end
|
2009-04-26 14:53:37 +00:00
|
|
|
|
2009-09-05 23:57:42 +00:00
|
|
|
def cmd_db_del_port(*args)
|
|
|
|
if (not args or args.length < 3)
|
|
|
|
print_status("Usage: db_del_port [host] [port] [proto]")
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
if framework.db.del_service(nil, args[0], args[2].downcase, args[1].to_i)
|
|
|
|
print_status("Service: host=#{args[0]} port=#{args[1].to_i} proto=#{args[2].downcase} deleted")
|
|
|
|
end
|
|
|
|
end
|
2006-05-30 15:44:48 +00:00
|
|
|
|
2008-03-02 04:46:13 +00:00
|
|
|
def cmd_db_add_note(*args)
|
|
|
|
if (not args or args.length < 3)
|
|
|
|
print_status("Usage: db_add_note [host] [type] [note]")
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2009-11-06 16:01:24 +00:00
|
|
|
naddr = args.shift
|
2008-03-02 04:46:13 +00:00
|
|
|
ntype = args.shift
|
|
|
|
ndata = args.join(" ")
|
|
|
|
|
|
|
|
host = framework.db.get_host(nil, naddr)
|
|
|
|
return if not host
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2008-03-02 04:46:13 +00:00
|
|
|
note = framework.db.get_note(nil, host, ntype, ndata)
|
|
|
|
return if not note
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2008-03-02 04:46:13 +00:00
|
|
|
print_status("Time: #{note.created} Note: host=#{note.host.address} type=#{note.ntype} data=#{note.data}")
|
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
|
|
|
|
2008-12-22 03:19:39 +00:00
|
|
|
def cmd_db_del_host(*args)
|
|
|
|
args.each do |address|
|
|
|
|
if framework.db.del_host(nil, address)
|
|
|
|
print_status("Host #{address} deleted")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2006-09-17 22:07:52 +00:00
|
|
|
#
|
|
|
|
# A shotgun approach to network-wide exploitation
|
|
|
|
#
|
|
|
|
def cmd_db_autopwn(*args)
|
|
|
|
|
|
|
|
stamp = Time.now.to_f
|
|
|
|
vcnt = 0
|
|
|
|
rcnt = 0
|
|
|
|
mode = 0
|
|
|
|
code = :bind
|
2008-11-18 22:01:15 +00:00
|
|
|
mjob = 5
|
|
|
|
regx = nil
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2008-11-18 22:01:15 +00:00
|
|
|
port_inc = []
|
|
|
|
port_exc = []
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2006-12-10 08:21:52 +00:00
|
|
|
targ_inc = []
|
|
|
|
targ_exc = []
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2006-09-17 22:07:52 +00:00
|
|
|
args.push("-h") if args.length == 0
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2006-09-17 22:07:52 +00:00
|
|
|
while (arg = args.shift)
|
|
|
|
case arg
|
|
|
|
when '-t'
|
|
|
|
mode |= PWN_SHOW
|
|
|
|
when '-x'
|
|
|
|
mode |= PWN_XREF
|
|
|
|
when '-p'
|
|
|
|
mode |= PWN_PORT
|
|
|
|
when '-e'
|
|
|
|
mode |= PWN_EXPL
|
|
|
|
when '-s'
|
2008-11-18 22:01:15 +00:00
|
|
|
mode |= PWN_SING
|
|
|
|
when '-q'
|
|
|
|
mode |= PWN_SLNT
|
2009-12-03 01:36:17 +00:00
|
|
|
when '-v'
|
|
|
|
mode |= PWN_VERB
|
2008-11-18 22:01:15 +00:00
|
|
|
when '-j'
|
|
|
|
mjob = args.shift.to_i
|
2006-09-17 22:07:52 +00:00
|
|
|
when '-r'
|
|
|
|
code = :conn
|
|
|
|
when '-b'
|
|
|
|
code = :bind
|
2006-12-10 08:21:52 +00:00
|
|
|
when '-I'
|
|
|
|
targ_inc << OptAddressRange.new('TEMPRANGE', [ true, '' ]).normalize(args.shift)
|
|
|
|
when '-X'
|
|
|
|
targ_exc << OptAddressRange.new('TEMPRANGE', [ true, '' ]).normalize(args.shift)
|
2008-11-18 22:01:15 +00:00
|
|
|
when '-PI'
|
2008-12-20 20:34:05 +00:00
|
|
|
port_inc = Rex::Socket.portspec_crack(args.shift)
|
2008-11-18 22:01:15 +00:00
|
|
|
when '-PX'
|
2008-12-20 20:34:05 +00:00
|
|
|
port_exc = Rex::Socket.portspec_crack(args.shift)
|
2008-11-18 22:01:15 +00:00
|
|
|
when '-m'
|
|
|
|
regx = args.shift
|
2009-10-28 18:04:50 +00:00
|
|
|
when '-h','--help'
|
2006-09-17 22:07:52 +00:00
|
|
|
print_status("Usage: db_autopwn [options]")
|
2008-11-18 22:01:15 +00:00
|
|
|
print_line("\t-h Display this help text")
|
|
|
|
print_line("\t-t Show all matching exploit modules")
|
|
|
|
print_line("\t-x Select modules based on vulnerability references")
|
|
|
|
print_line("\t-p Select modules based on open ports")
|
|
|
|
print_line("\t-e Launch exploits against all matched targets")
|
|
|
|
# print_line("\t-s Only obtain a single shell per target system (NON-FUNCTIONAL)")
|
|
|
|
print_line("\t-r Use a reverse connect shell")
|
2009-10-04 19:48:48 +00:00
|
|
|
print_line("\t-b Use a bind shell on a random port (default)")
|
2008-12-02 02:03:22 +00:00
|
|
|
print_line("\t-q Disable exploit module output")
|
2008-11-18 22:01:15 +00:00
|
|
|
print_line("\t-I [range] Only exploit hosts inside this range")
|
|
|
|
print_line("\t-X [range] Always exclude hosts inside this range")
|
|
|
|
print_line("\t-PI [range] Only exploit hosts with these ports open")
|
|
|
|
print_line("\t-PX [range] Always exclude hosts with these ports open")
|
|
|
|
print_line("\t-m [regex] Only run modules whose name matches the regex")
|
2006-09-17 22:07:52 +00:00
|
|
|
print_line("")
|
|
|
|
return
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2009-12-10 15:12:59 +00:00
|
|
|
minrank = framework.datastore['MinimumRank'] || 'manual'
|
|
|
|
if ! RankingName.values.include?(minrank)
|
2009-12-09 23:07:58 +00:00
|
|
|
print_error("MinimumRank invalid! Possible values are (#{RankingName.sort.map{|r|r[1]}.join("|")})")
|
2009-12-09 01:54:20 +00:00
|
|
|
wlog("MinimumRank invalid, ignoring", 'core', LEV_0)
|
2009-12-09 23:07:58 +00:00
|
|
|
return
|
2009-12-09 01:54:20 +00:00
|
|
|
else
|
|
|
|
minrank = RankingName.invert[minrank]
|
|
|
|
end
|
|
|
|
|
2009-12-03 01:36:17 +00:00
|
|
|
# Default to quiet mode
|
|
|
|
if (mode & PWN_VERB == 0)
|
|
|
|
mode |= PWN_SLNT
|
|
|
|
end
|
|
|
|
|
|
|
|
matches = {}
|
|
|
|
refmatches = {}
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-12-11 20:21:18 +00:00
|
|
|
# Pre-allocate a list of references and ports for all exploits
|
|
|
|
mrefs = {}
|
|
|
|
mports = {}
|
|
|
|
mservs = {}
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-12-11 20:21:18 +00:00
|
|
|
[ [framework.exploits, 'exploit' ], [ framework.auxiliary, 'auxiliary' ] ].each do |mtype|
|
|
|
|
mtype[0].each_module do |modname, mod|
|
|
|
|
o = mod.new
|
2006-09-17 22:07:52 +00:00
|
|
|
|
2009-12-11 20:21:18 +00:00
|
|
|
if(mode & PWN_XREF != 0)
|
|
|
|
o.references.each do |r|
|
2009-12-03 01:36:17 +00:00
|
|
|
next if r.ctx_id == 'URL'
|
2009-12-11 20:21:18 +00:00
|
|
|
ref = r.ctx_id + "-" + r.ctx_val
|
|
|
|
ref.upcase!
|
2009-12-03 01:36:17 +00:00
|
|
|
|
2009-12-11 20:21:18 +00:00
|
|
|
mrefs[ref] ||= {}
|
|
|
|
mrefs[ref][o.fullname] = o
|
|
|
|
end
|
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-12-11 20:21:18 +00:00
|
|
|
if(mode & PWN_PORT != 0)
|
|
|
|
if(o.datastore['RPORT'])
|
|
|
|
rport = o.datastore['RPORT']
|
|
|
|
mports[rport.to_i] ||= {}
|
|
|
|
mports[rport.to_i][o.fullname] = o
|
|
|
|
end
|
2009-12-03 01:36:17 +00:00
|
|
|
|
2009-12-11 20:21:18 +00:00
|
|
|
if(o.respond_to?('autofilter_ports'))
|
|
|
|
o.autofilter_ports.each do |rport|
|
|
|
|
mports[rport.to_i] ||= {}
|
|
|
|
mports[rport.to_i][o.fullname] = o
|
|
|
|
end
|
|
|
|
end
|
2009-12-03 01:36:17 +00:00
|
|
|
|
2009-12-11 20:21:18 +00:00
|
|
|
if(o.respond_to?('autofilter_services'))
|
|
|
|
o.autofilter_services.each do |serv|
|
|
|
|
mservs[serv] ||= {}
|
|
|
|
mservs[serv][o.fullname] = o
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2009-12-03 01:36:17 +00:00
|
|
|
|
|
|
|
|
2009-12-11 20:21:18 +00:00
|
|
|
begin
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-12-11 20:21:18 +00:00
|
|
|
framework.db.hosts.each do |host|
|
|
|
|
xhost = host.address
|
|
|
|
next if (targ_inc.length > 0 and not range_include?(targ_inc, xhost))
|
|
|
|
next if (targ_exc.length > 0 and range_include?(targ_exc, xhost))
|
2009-12-03 01:36:17 +00:00
|
|
|
|
2009-12-11 20:21:18 +00:00
|
|
|
if(mode & PWN_VERB != 0)
|
|
|
|
print_status("Scanning #{xhost} for matching exploit modules...")
|
|
|
|
end
|
2006-09-17 22:07:52 +00:00
|
|
|
|
2009-12-11 20:21:18 +00:00
|
|
|
#
|
|
|
|
# Match based on vulnerability references
|
|
|
|
#
|
|
|
|
if (mode & PWN_XREF != 0)
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-12-11 20:21:18 +00:00
|
|
|
host.vulns.each do |vuln|
|
2009-10-28 18:04:50 +00:00
|
|
|
|
2009-12-11 20:21:18 +00:00
|
|
|
# Faster to handle these here
|
|
|
|
serv = vuln.service
|
|
|
|
xport = xprot = nil
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-12-11 20:21:18 +00:00
|
|
|
if(serv)
|
|
|
|
xport = serv.port
|
|
|
|
xprot = serv.proto
|
2009-11-06 16:01:24 +00:00
|
|
|
end
|
|
|
|
|
2009-12-11 20:21:18 +00:00
|
|
|
vuln.refs.each do |ref|
|
|
|
|
mods = mrefs[ref.name.upcase] || {}
|
|
|
|
mods.each_key do |modname|
|
|
|
|
mod = mods[modname]
|
|
|
|
next if minrank and minrank > mod.rank
|
|
|
|
next if (regx and mod.fullname !~ /#{regx}/)
|
|
|
|
|
|
|
|
if(xport)
|
|
|
|
next if (port_inc.length > 0 and not port_inc.include?(serv.port.to_i))
|
|
|
|
next if (port_exc.length > 0 and port_exc.include?(serv.port.to_i))
|
|
|
|
else
|
|
|
|
if(mod.datastore['RPORT'])
|
|
|
|
next if (port_inc.length > 0 and not port_inc.include?(mod.datastore['RPORT'].to_i))
|
|
|
|
next if (port_exc.length > 0 and port_exc.include?(mod.datastore['RPORT'].to_i))
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2009-09-11 15:32:23 +00:00
|
|
|
next if (regx and e.fullname !~ /#{regx}/)
|
2009-12-03 01:36:17 +00:00
|
|
|
|
2009-12-11 20:21:18 +00:00
|
|
|
mod.datastore['RPORT'] = xport if xport
|
|
|
|
mod.datastore['RHOST'] = xhost
|
2009-12-03 15:26:30 +00:00
|
|
|
|
2009-12-11 20:21:18 +00:00
|
|
|
filtered = false
|
2009-12-03 15:26:30 +00:00
|
|
|
begin
|
2009-12-11 21:46:44 +00:00
|
|
|
::Timeout.timeout(2, ::RuntimeError) do
|
2009-12-11 20:21:18 +00:00
|
|
|
filtered = true if not mod.autofilter()
|
|
|
|
end
|
2009-12-03 15:26:30 +00:00
|
|
|
rescue ::Interrupt
|
|
|
|
raise $!
|
2009-12-11 20:21:18 +00:00
|
|
|
rescue ::Timeout::Error
|
|
|
|
filtered = true
|
2009-12-03 15:26:30 +00:00
|
|
|
rescue ::Exception
|
2009-12-11 20:21:18 +00:00
|
|
|
filtered = true
|
2009-12-03 15:26:30 +00:00
|
|
|
end
|
2009-12-11 20:21:18 +00:00
|
|
|
next if filtered
|
2009-12-03 01:36:17 +00:00
|
|
|
|
2009-12-11 20:21:18 +00:00
|
|
|
matches[[xport,xprot,xhost,mod.fullname]]=true
|
|
|
|
refmatches[[xport,xprot,xhost,mod.fullname]] ||= []
|
|
|
|
refmatches[[xport,xprot,xhost,mod.fullname]] << ref.name
|
2006-09-17 22:07:52 +00:00
|
|
|
end
|
2009-12-11 20:21:18 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2009-10-28 18:04:50 +00:00
|
|
|
|
2009-12-11 20:21:18 +00:00
|
|
|
#
|
|
|
|
# Match based on open ports
|
|
|
|
#
|
|
|
|
if (mode & PWN_PORT != 0)
|
|
|
|
host.services.each do |serv|
|
|
|
|
next if not serv.host
|
|
|
|
next if (serv.state != "open" && serv.state != "up")
|
|
|
|
|
|
|
|
xport = serv.port.to_i
|
|
|
|
xprot = serv.proto
|
|
|
|
xname = serv.name
|
|
|
|
|
|
|
|
next if xport == 0
|
|
|
|
|
|
|
|
next if (port_inc.length > 0 and not port_inc.include?(xport))
|
|
|
|
next if (port_exc.length > 0 and port_exc.include?(xport))
|
|
|
|
|
|
|
|
mods = mports[xport.to_i] || {}
|
|
|
|
|
|
|
|
mods.each_key do |modname|
|
|
|
|
mod = mods[modname]
|
|
|
|
next if minrank and minrank > mod.rank
|
|
|
|
next if (regx and mod.fullname !~ /#{regx}/)
|
|
|
|
mod.datastore['RPORT'] = xport
|
|
|
|
mod.datastore['RHOST'] = xhost
|
|
|
|
|
|
|
|
filtered = false
|
|
|
|
begin
|
2009-12-11 21:46:44 +00:00
|
|
|
::Timeout.timeout(2, ::RuntimeError) do
|
2009-12-11 20:21:18 +00:00
|
|
|
filtered = true if not mod.autofilter()
|
|
|
|
end
|
|
|
|
rescue ::Interrupt
|
|
|
|
raise $!
|
|
|
|
rescue ::Exception
|
|
|
|
filtered = true
|
|
|
|
end
|
|
|
|
|
|
|
|
next if filtered
|
|
|
|
matches[[xport,xprot,xhost,mod.fullname]]=true
|
|
|
|
end
|
|
|
|
|
|
|
|
mods = mservs[xname] || {}
|
|
|
|
mods.each_key do |modname|
|
|
|
|
mod = mods[modname]
|
|
|
|
next if minrank and minrank > mod.rank
|
|
|
|
next if (regx and mod.fullname !~ /#{regx}/)
|
|
|
|
mod.datastore['RPORT'] = xport
|
|
|
|
mod.datastore['RHOST'] = xhost
|
|
|
|
|
|
|
|
filtered = false
|
|
|
|
begin
|
2009-12-11 21:46:44 +00:00
|
|
|
::Timeout.timeout(2, ::RuntimeError) do
|
2009-12-11 20:21:18 +00:00
|
|
|
filtered = true if not mod.autofilter()
|
|
|
|
end
|
|
|
|
rescue ::Interrupt
|
|
|
|
raise $!
|
|
|
|
rescue ::Exception
|
|
|
|
filtered = true
|
2009-11-06 16:01:24 +00:00
|
|
|
end
|
2009-12-11 20:21:18 +00:00
|
|
|
|
|
|
|
next if filtered
|
|
|
|
matches[[xport,xprot,xhost,mod.fullname]]=true
|
2006-09-17 22:07:52 +00:00
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
end
|
2006-09-17 22:07:52 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2009-12-11 20:21:18 +00:00
|
|
|
rescue ::Exception => e
|
|
|
|
print_status("ERROR: #{e.class} #{e} #{e.backtrace}")
|
|
|
|
return
|
|
|
|
end
|
2006-09-17 22:07:52 +00:00
|
|
|
|
|
|
|
if (mode & PWN_SHOW != 0)
|
2009-12-03 01:36:17 +00:00
|
|
|
print_status("Analysis completed in #{(Time.now.to_f - stamp).to_i} seconds (#{vcnt} vulns / #{rcnt} refs)")
|
2009-12-03 15:26:30 +00:00
|
|
|
print_status("")
|
2009-12-03 01:36:17 +00:00
|
|
|
print_status("=" * 80)
|
|
|
|
print_status(" " * 28 + "Matching Exploit Modules")
|
|
|
|
print_status("=" * 80)
|
|
|
|
|
|
|
|
matches.each_key do |xref|
|
|
|
|
mod = nil
|
|
|
|
if ((mod = framework.modules.create(xref[3])) == nil)
|
|
|
|
print_status("Failed to initialize #{xref[3]}")
|
|
|
|
next
|
|
|
|
end
|
|
|
|
|
|
|
|
if (mode & PWN_SHOW != 0)
|
|
|
|
tport = xref[0] || mod.datastore['RPORT']
|
|
|
|
if(refmatches[xref])
|
|
|
|
print_status(" #{xref[2]}:#{tport} #{xref[3]} (#{refmatches[xref].join(", ")})")
|
|
|
|
else
|
|
|
|
print_status(" #{xref[2]}:#{tport} #{xref[3]} (port match)")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
print_status("=" * 80)
|
|
|
|
print_status("")
|
|
|
|
print_status("")
|
2006-09-17 22:07:52 +00:00
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2008-11-18 22:01:15 +00:00
|
|
|
|
2006-09-17 22:07:52 +00:00
|
|
|
idx = 0
|
|
|
|
matches.each_key do |xref|
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2006-09-17 22:07:52 +00:00
|
|
|
idx += 1
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2006-09-17 22:07:52 +00:00
|
|
|
begin
|
|
|
|
mod = nil
|
|
|
|
|
|
|
|
if ((mod = framework.modules.create(xref[3])) == nil)
|
|
|
|
print_status("Failed to initialize #{xref[3]}")
|
|
|
|
next
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# The code is just a proof-of-concept and will be expanded in the future
|
|
|
|
#
|
|
|
|
if (mode & PWN_EXPL != 0)
|
|
|
|
|
|
|
|
mod.datastore['RHOST'] = xref[2]
|
2009-12-03 01:36:17 +00:00
|
|
|
|
|
|
|
if(xref[0])
|
|
|
|
mod.datastore['RPORT'] = xref[0].to_s
|
|
|
|
end
|
2006-09-17 22:07:52 +00:00
|
|
|
|
|
|
|
if (code == :bind)
|
|
|
|
mod.datastore['LPORT'] = (rand(0x8fff) + 4000).to_s
|
2009-03-28 21:51:35 +00:00
|
|
|
if(mod.fullname =~ /\/windows\//)
|
|
|
|
mod.datastore['PAYLOAD'] = 'windows/meterpreter/bind_tcp'
|
|
|
|
else
|
|
|
|
mod.datastore['PAYLOAD'] = 'generic/shell_bind_tcp'
|
|
|
|
end
|
2006-09-17 22:07:52 +00:00
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2006-09-17 22:07:52 +00:00
|
|
|
if (code == :conn)
|
|
|
|
mod.datastore['LHOST'] = Rex::Socket.source_address(xref[2])
|
|
|
|
mod.datastore['LPORT'] = (rand(0x8fff) + 4000).to_s
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2006-09-17 22:07:52 +00:00
|
|
|
if (mod.datastore['LHOST'] == '127.0.0.1')
|
|
|
|
print_status("Failed to determine listener address for target #{xref[2]}...")
|
|
|
|
next
|
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-03-28 21:51:35 +00:00
|
|
|
if(mod.fullname =~ /\/windows\//)
|
|
|
|
mod.datastore['PAYLOAD'] = 'windows/meterpreter/reverse_tcp'
|
|
|
|
else
|
|
|
|
mod.datastore['PAYLOAD'] = 'generic/shell_reverse_tcp'
|
|
|
|
end
|
2006-09-17 22:07:52 +00:00
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
|
|
|
|
2008-11-18 22:01:15 +00:00
|
|
|
if(framework.jobs.keys.length >= mjob)
|
|
|
|
print_status("Job limit reached, waiting on modules to finish...")
|
|
|
|
while(framework.jobs.keys.length >= mjob)
|
|
|
|
select(nil, nil, nil, 0.25)
|
|
|
|
end
|
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-12-03 01:36:17 +00:00
|
|
|
print_status("(#{idx}/#{matches.length} [#{framework.sessions.length} sessions]): Launching #{xref[3]} against #{xref[2]}:#{mod.datastore['RPORT']}...")
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2006-09-17 22:07:52 +00:00
|
|
|
begin
|
2008-11-18 22:01:15 +00:00
|
|
|
inp = (mode & PWN_SLNT != 0) ? nil : driver.input
|
|
|
|
out = (mode & PWN_SLNT != 0) ? nil : driver.output
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2006-09-17 22:07:52 +00:00
|
|
|
case mod.type
|
|
|
|
when MODULE_EXPLOIT
|
|
|
|
session = mod.exploit_simple(
|
|
|
|
'Payload' => mod.datastore['PAYLOAD'],
|
2008-11-18 22:01:15 +00:00
|
|
|
'LocalInput' => inp,
|
|
|
|
'LocalOutput' => out,
|
2006-09-17 22:07:52 +00:00
|
|
|
'RunAsJob' => true)
|
|
|
|
when MODULE_AUX
|
|
|
|
session = mod.run_simple(
|
2008-11-18 22:01:15 +00:00
|
|
|
'LocalInput' => inp,
|
|
|
|
'LocalOutput' => out,
|
2009-11-06 16:01:24 +00:00
|
|
|
'RunAsJob' => true)
|
2006-09-17 22:07:52 +00:00
|
|
|
end
|
2008-11-18 22:01:15 +00:00
|
|
|
rescue ::Interrupt
|
|
|
|
raise $!
|
2006-09-17 22:07:52 +00:00
|
|
|
rescue ::Exception
|
2008-12-19 07:11:08 +00:00
|
|
|
print_status(" >> autopwn exception during launch from #{xref[3]}: #{$!} ")
|
2006-09-17 22:07:52 +00:00
|
|
|
end
|
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2008-11-18 22:01:15 +00:00
|
|
|
rescue ::Interrupt
|
|
|
|
raise $!
|
2006-09-17 22:07:52 +00:00
|
|
|
rescue ::Exception
|
2008-12-19 07:11:08 +00:00
|
|
|
print_status(" >> autopwn exception from #{xref[3]}: #{$!} #{$!.backtrace}")
|
2006-09-17 22:07:52 +00:00
|
|
|
end
|
2008-11-18 22:01:15 +00:00
|
|
|
end
|
2006-09-17 22:07:52 +00:00
|
|
|
|
2009-12-03 01:36:17 +00:00
|
|
|
|
|
|
|
while(framework.jobs.keys.length > 0)
|
|
|
|
print_status("(#{matches.length}/#{matches.length} [#{framework.sessions.length} sessions]): Waiting on #{framework.jobs.length} launched modules to finish execution...")
|
|
|
|
select(nil, nil, nil, 5.0)
|
|
|
|
end
|
|
|
|
|
|
|
|
if (mode & PWN_SHOW != 0 and mode & PWN_EXPL != 0)
|
|
|
|
print_status("The autopwn command has completed with #{framework.sessions.length} sessions")
|
|
|
|
if(framework.sessions.length > 0)
|
|
|
|
print_status("Enter sessions -i [ID] to interact with a given session ID")
|
|
|
|
print_status("")
|
|
|
|
print_status("=" * 80)
|
|
|
|
driver.run_single("sessions -l -v")
|
|
|
|
print_status("=" * 80)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
print_line("")
|
2006-09-17 22:07:52 +00:00
|
|
|
# EOM
|
|
|
|
end
|
|
|
|
|
2009-12-11 20:21:18 +00:00
|
|
|
|
2009-09-05 04:29:53 +00:00
|
|
|
#
|
|
|
|
# This holds all of the shared parsing/handling used by the
|
|
|
|
# Nessus NBE and NESSUS methods
|
|
|
|
#
|
|
|
|
def handle_nessus(addr, port, nasl, data)
|
|
|
|
p = port.match(/^([^\(]+)\((\d+)\/([^\)]+)\)/)
|
2009-11-06 16:01:24 +00:00
|
|
|
return if not p
|
2009-09-05 04:29:53 +00:00
|
|
|
|
|
|
|
host = framework.db.get_host(nil, addr)
|
|
|
|
return if not host
|
|
|
|
|
|
|
|
if host.state != Msf::HostState::Alive
|
|
|
|
framework.db.report_host_state(self, addr, Msf::HostState::Alive)
|
|
|
|
end
|
|
|
|
|
|
|
|
service = framework.db.get_service(nil, host, p[3].downcase, p[2].to_i)
|
|
|
|
name = p[1].strip
|
|
|
|
if name != "unknown"
|
|
|
|
service.name = name
|
|
|
|
service.save
|
|
|
|
end
|
|
|
|
|
|
|
|
return if not nasl
|
|
|
|
|
|
|
|
data.gsub!("\\n", "\n")
|
|
|
|
|
|
|
|
refs = {}
|
|
|
|
|
|
|
|
if (data =~ /^CVE : (.*)$/)
|
|
|
|
$1.gsub(/C(VE|AN)\-/, '').split(',').map { |r| r.strip }.each do |r|
|
|
|
|
refs[ 'CVE-' + r ] = true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
if (data =~ /^BID : (.*)$/)
|
|
|
|
$1.split(',').map { |r| r.strip }.each do |r|
|
|
|
|
refs[ 'BID-' + r ] = true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
if (data =~ /^Other references : (.*)$/)
|
|
|
|
$1.split(',').map { |r| r.strip }.each do |r|
|
|
|
|
ref_id, ref_val = r.split(':')
|
|
|
|
ref_val ? refs[ ref_id + '-' + ref_val ] = true : refs[ ref_id ] = true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
nss = 'NSS-' + nasl.to_s
|
|
|
|
|
|
|
|
vuln = framework.db.get_vuln(nil, host, service, nss, data)
|
|
|
|
|
|
|
|
rids = []
|
|
|
|
refs.keys.each do |r|
|
|
|
|
rids << framework.db.get_ref(nil, r)
|
|
|
|
end
|
|
|
|
|
|
|
|
vuln.refs << (rids - vuln.refs)
|
|
|
|
end
|
|
|
|
|
2006-09-17 22:07:52 +00:00
|
|
|
#
|
|
|
|
# Import Nessus NBE files
|
|
|
|
#
|
2006-05-30 15:44:48 +00:00
|
|
|
def cmd_db_import_nessus_nbe(*args)
|
|
|
|
if (not (args and args.length == 1))
|
2006-09-16 06:45:06 +00:00
|
|
|
print_status("Usage: db_import_nessus_nbe [nessus.nbe]")
|
2006-05-30 15:44:48 +00:00
|
|
|
return
|
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
|
|
|
if (not File.readable?(args[0]))
|
2006-05-30 15:44:48 +00:00
|
|
|
print_status("Could not read the NBE file")
|
|
|
|
return
|
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2006-05-30 15:44:48 +00:00
|
|
|
fd = File.open(args[0], 'r')
|
|
|
|
fd.each_line do |line|
|
|
|
|
r = line.split('|')
|
|
|
|
next if r[0] != 'results'
|
|
|
|
addr = r[2]
|
2009-09-05 04:29:53 +00:00
|
|
|
port = r[3]
|
2006-05-30 15:44:48 +00:00
|
|
|
nasl = r[4]
|
|
|
|
data = r[6]
|
2006-09-16 20:08:13 +00:00
|
|
|
|
2009-09-05 04:29:53 +00:00
|
|
|
handle_nessus(addr, port, nasl, data)
|
2006-05-30 15:44:48 +00:00
|
|
|
end
|
2008-11-24 22:28:22 +00:00
|
|
|
fd.close
|
2006-09-16 20:08:13 +00:00
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-09-05 04:29:53 +00:00
|
|
|
#
|
|
|
|
# Import Nessus NESSUS files
|
2009-11-06 16:01:24 +00:00
|
|
|
#
|
2009-09-05 04:29:53 +00:00
|
|
|
def cmd_db_import_nessus_xml(*args)
|
|
|
|
if (not (args and args.length == 1))
|
|
|
|
print_status("Usage: db_import_nessus_xml [nessus.nessus]")
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
if (not File.readable?(args[0]))
|
|
|
|
print_status("Could not read the NESSUS file")
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
fd = File.open(args[0], 'r')
|
|
|
|
data = fd.read
|
|
|
|
fd.close
|
|
|
|
|
2009-12-14 22:00:54 +00:00
|
|
|
if(data.index("NessusClientData_v2"))
|
|
|
|
print_status("The v2 .nessus format is not currently supported (patches welcome).")
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2009-09-05 04:29:53 +00:00
|
|
|
doc = REXML::Document.new(data)
|
|
|
|
doc.elements.each('/NessusClientData/Report/ReportHost') do |host|
|
|
|
|
addr = host.elements['HostName'].text
|
|
|
|
|
|
|
|
host.elements.each('ReportItem') do |item|
|
|
|
|
nasl = item.elements['pluginID'].text
|
|
|
|
port = item.elements['port'].text
|
|
|
|
data = item.elements['data'].text
|
|
|
|
|
|
|
|
handle_nessus(addr, port, nasl, data)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2006-09-17 22:07:52 +00:00
|
|
|
#
|
|
|
|
# Import Nmap data from a file
|
|
|
|
#
|
|
|
|
def cmd_db_import_nmap_xml(*args)
|
|
|
|
if (not (args and args.length == 1))
|
|
|
|
print_status("Usage: db_import_nmap_xml [nmap.xml]")
|
|
|
|
return
|
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-11-05 20:26:28 +00:00
|
|
|
load_nmap_xml(args[0])
|
2006-09-17 22:07:52 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Import Nmap data from a file
|
|
|
|
#
|
|
|
|
def cmd_db_nmap(*args)
|
|
|
|
if (args.length == 0)
|
|
|
|
print_status("Usage: db_nmap [nmap options]")
|
|
|
|
return
|
2006-09-16 20:08:13 +00:00
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
|
|
|
nmap =
|
|
|
|
Rex::FileUtils.find_full_path("nmap") ||
|
2007-12-31 04:05:51 +00:00
|
|
|
Rex::FileUtils.find_full_path("nmap.exe")
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2007-12-31 04:05:51 +00:00
|
|
|
if(not nmap)
|
|
|
|
print_error("The nmap executable could not be found")
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2006-09-17 22:07:52 +00:00
|
|
|
fd = Tempfile.new('dbnmap')
|
2009-11-06 17:27:28 +00:00
|
|
|
fo = Tempfile.new('dbnmap')
|
2008-09-26 05:01:18 +00:00
|
|
|
|
2009-11-06 16:43:14 +00:00
|
|
|
# When executing native Nmap in Cygwin, expand the Cygwin path to a Win32 path
|
2009-11-06 16:03:40 +00:00
|
|
|
if(Rex::Compat.is_cygwin and nmap =~ /cygdrive/)
|
2009-11-06 16:43:14 +00:00
|
|
|
# Custom function needed because cygpath breaks on 8.3 dirs
|
|
|
|
tout = Rex::Compat.cygwin_to_win32(fd.path)
|
2009-11-06 17:27:28 +00:00
|
|
|
fout = Rex::Compat.cygwin_to_win32(fo.path)
|
2009-11-06 16:43:14 +00:00
|
|
|
args.push('-oX', tout)
|
2009-11-06 17:27:28 +00:00
|
|
|
args.push('-oN', fout)
|
2009-09-04 15:04:06 +00:00
|
|
|
else
|
|
|
|
args.push('-oX', fd.path)
|
2009-11-06 17:27:28 +00:00
|
|
|
args.push('-oN', fo.path)
|
2009-09-04 15:04:06 +00:00
|
|
|
end
|
2009-11-06 17:43:13 +00:00
|
|
|
system([nmap, "nmap"], *args)
|
2009-11-06 20:15:12 +00:00
|
|
|
|
|
|
|
# Until we hide stdout above, this is pointless
|
|
|
|
# fo.each_line do |line|
|
|
|
|
# print_status("NMAP: #{line.strip}")
|
|
|
|
# end
|
2006-09-17 22:07:52 +00:00
|
|
|
|
2009-11-06 17:27:28 +00:00
|
|
|
::File.unlink(fo.path)
|
2009-11-05 20:26:28 +00:00
|
|
|
load_nmap_xml(fd.path)
|
2009-11-06 16:01:24 +00:00
|
|
|
end
|
2009-11-05 20:26:28 +00:00
|
|
|
|
|
|
|
|
2006-09-17 22:07:52 +00:00
|
|
|
#
|
|
|
|
# Process Nmap XML data
|
|
|
|
#
|
2009-11-05 20:26:28 +00:00
|
|
|
def load_nmap_xml(filename)
|
2009-11-16 19:13:33 +00:00
|
|
|
if (not File.readable?(filename) or File.size(filename) < 1)
|
2009-11-16 19:06:42 +00:00
|
|
|
print_status("Could not read the XML file")
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2009-11-18 06:15:45 +00:00
|
|
|
# Use a stream parser instead of a tree parser so we can deal with
|
|
|
|
# huge results files without running out of memory.
|
|
|
|
parser = Rex::Parser::NmapXMLStreamParser.new
|
|
|
|
|
|
|
|
# Whenever the parser pulls a host out of the nmap results, store
|
2009-11-25 01:44:55 +00:00
|
|
|
# it, along with any associated services, in the database.
|
2009-11-18 06:15:45 +00:00
|
|
|
parser.on_found_host = Proc.new { |h|
|
|
|
|
if (h["addrs"].has_key?("ipv4"))
|
2009-11-25 01:44:55 +00:00
|
|
|
addr = h["addrs"]["ipv4"]
|
2009-11-18 06:15:45 +00:00
|
|
|
elsif (h.has_key?("ipv6"))
|
|
|
|
addr = h["addrs"]["ipv6"]
|
|
|
|
else
|
|
|
|
# Don't care about addresses other than IP
|
|
|
|
return
|
|
|
|
end
|
|
|
|
host = framework.db.get_host(nil, addr)
|
|
|
|
status = (h["status"] == "up" ? Msf::HostState::Alive : Msf::HostState::Dead)
|
|
|
|
framework.db.report_host_state(self, addr, status)
|
|
|
|
|
|
|
|
# Put all the ports, regardless of state, into the db.
|
|
|
|
h["ports"].each { |p|
|
|
|
|
service = framework.db.get_service(nil, host, p["protocol"].downcase, p["portid"].to_i)
|
|
|
|
service.state = p["state"]
|
|
|
|
if p["name"] != "unknown"
|
|
|
|
service.name = p["name"]
|
|
|
|
end
|
|
|
|
service.save
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
REXML::Document.parse_stream(File.new(filename), parser)
|
2006-09-16 20:08:13 +00:00
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-01-21 02:12:10 +00:00
|
|
|
#
|
|
|
|
# Import from a THC-Amap machine-readable log file
|
|
|
|
#
|
|
|
|
def cmd_db_import_amap_mlog(*args)
|
|
|
|
if args.length == 0
|
|
|
|
print_status("Usage: db_import_amap_mlog [logfile]")
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
if not File.readable?(args[0])
|
|
|
|
print_error("Could not read the log file")
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
fd = File.open(args[0], 'r')
|
|
|
|
|
|
|
|
fd.each_line do |line|
|
|
|
|
line.sub!(/#.*/, "")
|
|
|
|
|
|
|
|
r = line.split(':')
|
|
|
|
next if r.length < 6
|
|
|
|
|
|
|
|
addr = r[0]
|
|
|
|
port = r[1].to_i
|
|
|
|
proto = r[2].downcase
|
|
|
|
status = r[3]
|
|
|
|
name = r[5]
|
|
|
|
|
|
|
|
next if status != "open"
|
|
|
|
|
|
|
|
host = framework.db.get_host(nil, addr)
|
|
|
|
next if not host
|
|
|
|
|
|
|
|
if host.state != Msf::HostState::Alive
|
|
|
|
framework.db.report_host_state(self, addr, Msf::HostState::Alive)
|
|
|
|
end
|
|
|
|
|
|
|
|
service = framework.db.get_service(nil, host, proto, port)
|
|
|
|
if not service.name and name != "unidentified"
|
|
|
|
service.name = name
|
|
|
|
service.save
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
fd.close
|
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2006-12-10 08:21:52 +00:00
|
|
|
#
|
|
|
|
# Determine if an IP address is inside a given range
|
|
|
|
#
|
|
|
|
def range_include?(ranges, addr)
|
|
|
|
|
|
|
|
ranges.each do |sets|
|
2009-10-04 19:43:06 +00:00
|
|
|
sets.split(',').each do |set|
|
2006-12-10 08:21:52 +00:00
|
|
|
rng = set.split('-').map{ |c| Rex::Socket::addr_atoi(c) }
|
|
|
|
tst = Rex::Socket::addr_atoi(addr)
|
2009-10-04 20:20:43 +00:00
|
|
|
if (not rng[1])
|
|
|
|
return tst == rng[0]
|
|
|
|
elsif (tst >= rng[0] and tst <= rng[1])
|
2006-12-10 08:21:52 +00:00
|
|
|
return true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2006-12-10 08:21:52 +00:00
|
|
|
false
|
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
#
|
|
|
|
# Database management
|
|
|
|
#
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
def db_check_driver
|
|
|
|
if(not framework.db.driver)
|
|
|
|
print_error("No database driver has been specified")
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
true
|
|
|
|
end
|
|
|
|
|
|
|
|
def cmd_db_driver(*args)
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
if(args[0])
|
2009-11-14 21:41:38 +00:00
|
|
|
if(args[0] == "-h" || args[0] == "--help")
|
2009-03-28 21:42:30 +00:00
|
|
|
print_status("Usage: db_driver [driver-name]")
|
|
|
|
return
|
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
if(framework.db.drivers.include?(args[0]))
|
|
|
|
framework.db.driver = args[0]
|
|
|
|
print_status("Using database driver #{args[0]}")
|
|
|
|
else
|
|
|
|
print_error("Invalid driver specified")
|
|
|
|
end
|
|
|
|
return
|
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
if(framework.db.driver)
|
|
|
|
print_status(" Active Driver: #{framework.db.driver}")
|
|
|
|
else
|
|
|
|
print_status("No Active Driver")
|
|
|
|
end
|
|
|
|
print_status(" Available: #{framework.db.drivers.join(", ")}")
|
2009-11-14 21:41:38 +00:00
|
|
|
print_line("")
|
|
|
|
|
|
|
|
if ! framework.db.drivers.include?('sqlite3')
|
|
|
|
print_status(" DB Support: Enable the sqlite3 driver with the following command:")
|
|
|
|
print_status(" $ gem install sqlite3-ruby")
|
|
|
|
print_line("")
|
|
|
|
end
|
|
|
|
|
|
|
|
if ! framework.db.drivers.include?('mysql')
|
|
|
|
print_status(" DB Support: Enable the mysql driver with the following command:")
|
|
|
|
print_status(" $ gem install mysql")
|
2009-12-14 23:40:21 +00:00
|
|
|
print_status(" This gem requires mysqlclient headers, which can be installed on Ubuntu with:")
|
|
|
|
print_status(" $ sudo apt-get install libmysqlclient-dev")
|
2009-11-14 21:41:38 +00:00
|
|
|
print_line("")
|
|
|
|
end
|
|
|
|
|
|
|
|
if ! framework.db.drivers.include?('postgresql')
|
|
|
|
print_status(" DB Support: Enable the postgresql driver with the following command:")
|
|
|
|
print_status(" $ gem install postgres-pr")
|
|
|
|
print_line("")
|
|
|
|
end
|
2009-03-28 21:42:30 +00:00
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
def cmd_db_driver_tabs(str, words)
|
|
|
|
return framework.db.drivers
|
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
def cmd_db_create(*args)
|
|
|
|
return if not db_check_driver
|
|
|
|
meth = "db_create_#{framework.db.driver}"
|
|
|
|
if(self.respond_to?(meth))
|
|
|
|
self.send(meth, *args)
|
|
|
|
else
|
2009-04-12 07:09:03 +00:00
|
|
|
print_error("This database driver #{framework.db.driver} is not currently supported")
|
2009-03-28 21:42:30 +00:00
|
|
|
end
|
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
def cmd_db_destroy(*args)
|
|
|
|
return if not db_check_driver
|
2009-11-14 21:41:38 +00:00
|
|
|
|
|
|
|
if(args[0] and (args[0] == "-h" || args[0] == "--help"))
|
|
|
|
print_status("Usage: db_destroy")
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
meth = "db_destroy_#{framework.db.driver}"
|
|
|
|
if(self.respond_to?(meth))
|
|
|
|
self.send(meth, *args)
|
|
|
|
else
|
2009-04-12 07:09:03 +00:00
|
|
|
print_error("This database driver #{framework.db.driver} is not currently supported")
|
2009-03-28 21:42:30 +00:00
|
|
|
end
|
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
def cmd_db_connect(*args)
|
|
|
|
return if not db_check_driver
|
|
|
|
meth = "db_connect_#{framework.db.driver}"
|
|
|
|
if(self.respond_to?(meth))
|
|
|
|
self.send(meth, *args)
|
|
|
|
else
|
2009-04-12 07:09:03 +00:00
|
|
|
print_error("This database driver #{framework.db.driver} is not currently supported")
|
2009-03-28 21:42:30 +00:00
|
|
|
end
|
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
def cmd_db_disconnect(*args)
|
|
|
|
return if not db_check_driver
|
2009-11-14 21:41:38 +00:00
|
|
|
|
|
|
|
if(args[0] and (args[0] == "-h" || args[0] == "--help"))
|
|
|
|
print_status("Usage: db_disconnect")
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
meth = "db_disconnect_#{framework.db.driver}"
|
|
|
|
if(self.respond_to?(meth))
|
|
|
|
self.send(meth, *args)
|
|
|
|
else
|
2009-04-12 07:09:03 +00:00
|
|
|
print_error("This database driver #{framework.db.driver} is not currently supported")
|
2009-03-28 21:42:30 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-11-14 21:41:38 +00:00
|
|
|
def db_find_tools(tools)
|
|
|
|
found = true
|
|
|
|
missed = []
|
|
|
|
tools.each do |name|
|
|
|
|
if(! Rex::FileUtils.find_full_path(name))
|
|
|
|
missed << name
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if(not missed.empty?)
|
|
|
|
print_error("This database command requires the following tools to be installed: #{missed.join(", ")}")
|
|
|
|
return
|
|
|
|
end
|
|
|
|
true
|
|
|
|
end
|
2009-12-10 15:12:59 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
#
|
|
|
|
# Database management: SQLite3
|
|
|
|
#
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
#
|
2009-03-29 03:40:25 +00:00
|
|
|
# Disconnect from the current SQLite3 instance
|
2009-03-28 21:42:30 +00:00
|
|
|
#
|
|
|
|
def db_disconnect_sqlite3(*args)
|
|
|
|
if (framework.db)
|
|
|
|
framework.db.disconnect()
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Connect to an existing SQLite database
|
|
|
|
#
|
|
|
|
def db_connect_sqlite3(*args)
|
|
|
|
|
2009-11-14 21:41:38 +00:00
|
|
|
if(args[0] and (args[0] == "-h" || args[0] == "--help"))
|
|
|
|
print_status("Usage: db_connect [database-file-path]")
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
info = db_parse_db_uri_sqlite3(args[0])
|
|
|
|
opts = { 'adapter' => 'sqlite3' }
|
|
|
|
|
|
|
|
opts['dbfile'] = info[:path]
|
|
|
|
|
2009-11-14 21:41:38 +00:00
|
|
|
if (not ::File.exists?(opts['dbfile']))
|
2009-04-08 03:11:12 +00:00
|
|
|
print_error("The specified database does not exist")
|
2009-03-28 21:42:30 +00:00
|
|
|
return
|
|
|
|
end
|
2009-04-08 03:11:12 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
if (not framework.db.connect(opts))
|
2009-11-14 21:41:38 +00:00
|
|
|
raise RuntimeError.new("Failed to connect to the database: #{framework.db.error}")
|
2009-03-28 21:42:30 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
print_status("Successfully connected to the database")
|
2009-11-06 16:01:24 +00:00
|
|
|
print_status("File: #{opts['dbfile']}")
|
2009-03-28 21:42:30 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Create a new SQLite database instance
|
2009-11-06 16:01:24 +00:00
|
|
|
#
|
2009-03-28 21:42:30 +00:00
|
|
|
def db_create_sqlite3(*args)
|
|
|
|
cmd_db_disconnect()
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-11-14 21:41:38 +00:00
|
|
|
if(args[0] and (args[0] == "-h" || args[0] == "--help"))
|
|
|
|
print_status("Usage: db_create [database-file-path]")
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
info = db_parse_db_uri_sqlite3(args[0])
|
|
|
|
opts = { 'adapter' => 'sqlite3' }
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
opts['dbfile'] = info[:path]
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
if (::File.exists?(opts['dbfile']))
|
|
|
|
print_status("The specified database already exists, connecting")
|
|
|
|
else
|
|
|
|
print_status("Creating a new database instance...")
|
2009-03-29 03:40:25 +00:00
|
|
|
require_library_or_gem('sqlite3')
|
2009-03-28 21:42:30 +00:00
|
|
|
end
|
2009-12-10 15:12:59 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
if (not framework.db.connect(opts))
|
2009-11-14 21:41:38 +00:00
|
|
|
raise RuntimeError.new("Failed to connect to the database: #{framework.db.error}")
|
2009-03-28 21:42:30 +00:00
|
|
|
end
|
2009-12-10 15:12:59 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
print_status("Successfully connected to the database")
|
2009-12-07 17:03:27 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
print_status("File: #{opts['dbfile']}")
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Drop an existing database
|
|
|
|
#
|
|
|
|
def db_destroy_sqlite3(*args)
|
|
|
|
cmd_db_disconnect()
|
|
|
|
info = db_parse_db_uri_sqlite3(args[0])
|
2009-04-08 03:30:18 +00:00
|
|
|
begin
|
2009-11-14 21:41:38 +00:00
|
|
|
print_status("Deleting #{info[:path]}...")
|
2009-04-08 03:30:18 +00:00
|
|
|
File.unlink(info[:path])
|
|
|
|
rescue Errno::ENOENT
|
|
|
|
print_error("The specified database does not exist")
|
|
|
|
end
|
2009-03-28 21:42:30 +00:00
|
|
|
end
|
2009-04-08 03:30:18 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
def db_parse_db_uri_sqlite3(path)
|
|
|
|
res = {}
|
|
|
|
res[:path] = path || ::File.join(Msf::Config.config_directory, 'sqlite3.db')
|
|
|
|
res
|
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
#
|
|
|
|
# Database management: MySQL
|
|
|
|
#
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
#
|
|
|
|
# Disconnect from the current MySQL instance
|
|
|
|
#
|
|
|
|
def db_disconnect_mysql(*args)
|
|
|
|
if (framework.db)
|
|
|
|
framework.db.disconnect()
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Connect to an existing MySQL database
|
|
|
|
#
|
|
|
|
def db_connect_mysql(*args)
|
2009-11-14 21:41:38 +00:00
|
|
|
if(args[0] == nil or args[0] == "-h" or args[0] == "--help")
|
|
|
|
print_status(" Usage: db_connect <user:pass>@<host:port>/<database>")
|
|
|
|
print_status("Examples:")
|
|
|
|
print_status(" db_connect user@metasploit3")
|
|
|
|
print_status(" db_connect user:pass@192.168.0.2/metasploit3")
|
|
|
|
print_status(" db_connect user:pass@192.168.0.2:1500/metasploit3")
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
info = db_parse_db_uri_mysql(args[0])
|
|
|
|
opts = { 'adapter' => 'mysql' }
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
opts['username'] = info[:user] if (info[:user])
|
|
|
|
opts['password'] = info[:pass] if (info[:pass])
|
|
|
|
opts['database'] = info[:name]
|
|
|
|
opts['host'] = info[:host] if (info[:host])
|
|
|
|
opts['port'] = info[:port] if (info[:port])
|
|
|
|
|
2009-11-14 21:41:38 +00:00
|
|
|
opts['host'] ||= 'localhost'
|
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
# This is an ugly hack for a broken MySQL adapter:
|
|
|
|
# http://dev.rubyonrails.org/ticket/3338
|
|
|
|
if (opts['host'].strip.downcase == 'localhost')
|
|
|
|
opts['host'] = Socket.gethostbyname("localhost")[3].unpack("C*").join(".")
|
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
if (not framework.db.connect(opts))
|
2009-11-14 21:41:38 +00:00
|
|
|
raise RuntimeError.new("Failed to connect to the database: #{framework.db.error}")
|
2009-03-28 21:42:30 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Create a new MySQL database instance
|
2009-11-06 16:01:24 +00:00
|
|
|
#
|
2009-03-28 21:42:30 +00:00
|
|
|
def db_create_mysql(*args)
|
|
|
|
cmd_db_disconnect()
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-11-14 21:41:38 +00:00
|
|
|
if(args[0] == nil or args[0] == "-h" or args[0] == "--help")
|
|
|
|
print_status(" Usage: db_create <user:pass>@<host:port>/<database>")
|
|
|
|
print_status("Examples:")
|
|
|
|
print_status(" db_create user@metasploit3")
|
|
|
|
print_status(" db_create user:pass@192.168.0.2/metasploit3")
|
|
|
|
print_status(" db_create user:pass@192.168.0.2:1500/metasploit3")
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
return if ! db_find_tools(%W{mysqladmin mysql})
|
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
info = db_parse_db_uri_mysql(args[0])
|
|
|
|
opts = { 'adapter' => 'mysql' }
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
argv = []
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
if (info[:user])
|
2009-11-06 16:01:24 +00:00
|
|
|
opts['username'] = info[:user]
|
2009-03-28 21:42:30 +00:00
|
|
|
argv.push('-u')
|
|
|
|
argv.push(info[:user])
|
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
if (info[:pass])
|
|
|
|
argv.push('--password=' + info[:pass])
|
2009-11-06 16:01:24 +00:00
|
|
|
opts['password'] = info[:pass]
|
2009-03-28 21:42:30 +00:00
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
if (info[:host])
|
|
|
|
opts['host'] = info[:host]
|
|
|
|
argv.push('-h')
|
|
|
|
argv.push(info[:host])
|
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
if (info[:port])
|
|
|
|
opts['port'] = info[:port]
|
|
|
|
argv.push('-P')
|
|
|
|
argv.push(info[:port])
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
# This is an ugly hack for a broken MySQL adapter:
|
|
|
|
# http://dev.rubyonrails.org/ticket/3338
|
|
|
|
if (opts['host'].strip.downcase == 'localhost')
|
|
|
|
opts['host'] = Socket.gethostbyname("localhost")[3].unpack("C*").join(".")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
argv.push('-f')
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
opts['database'] = info[:name]
|
|
|
|
|
|
|
|
cargs = argv.map{|c| "'#{c}' "}.join
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
system("mysqladmin #{cargs} drop #{info[:name]} >/dev/null 2>&1")
|
|
|
|
system("mysqladmin #{cargs} create #{info[:name]}")
|
2009-12-10 15:12:59 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
if (not framework.db.connect(opts))
|
2009-11-14 21:41:38 +00:00
|
|
|
raise RuntimeError.new("Failed to connect to the database: #{framework.db.error}")
|
2009-03-28 21:42:30 +00:00
|
|
|
end
|
|
|
|
|
2009-12-07 17:03:27 +00:00
|
|
|
print_status("Database creation complete (check for errors)")
|
2009-03-28 21:42:30 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Drop an existing database
|
|
|
|
#
|
|
|
|
def db_destroy_mysql(*args)
|
|
|
|
|
|
|
|
cmd_db_disconnect()
|
|
|
|
|
2009-11-14 21:41:38 +00:00
|
|
|
return if ! db_find_tools(%W{mysqladmin})
|
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
info = db_parse_db_uri_mysql(args[0])
|
|
|
|
argv = []
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
if (info[:user])
|
|
|
|
argv.push('-u')
|
|
|
|
argv.push(info[:user])
|
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
if (info[:pass])
|
|
|
|
argv.push('--password=' + info[:pass])
|
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
if (info[:host])
|
|
|
|
argv.push('-h')
|
|
|
|
argv.push(info[:host])
|
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
if (info[:port])
|
|
|
|
argv.push('-P')
|
|
|
|
argv.push(info[:port])
|
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
argv.push("-f")
|
|
|
|
|
|
|
|
cargs = argv.map{|c| "'#{c}' "}.join
|
|
|
|
system("mysqladmin -f #{cargs} drop #{info[:name]}")
|
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
def db_parse_db_uri_mysql(path)
|
|
|
|
res = {}
|
|
|
|
if (path)
|
|
|
|
auth, dest = path.split('@')
|
|
|
|
(dest = auth and auth = nil) if not dest
|
|
|
|
res[:user],res[:pass] = auth.split(':') if auth
|
|
|
|
targ,name = dest.split('/')
|
|
|
|
(name = targ and targ = nil) if not name
|
|
|
|
res[:host],res[:port] = targ.split(':') if targ
|
|
|
|
end
|
|
|
|
res[:name] = name || 'metasploit3'
|
|
|
|
res
|
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
#
|
|
|
|
# Database management: Postgres
|
|
|
|
#
|
|
|
|
#
|
|
|
|
# Disconnect from the current Postgres instance
|
|
|
|
#
|
2009-04-12 07:09:03 +00:00
|
|
|
def db_disconnect_postgresql(*args)
|
2009-03-28 21:42:30 +00:00
|
|
|
if (framework.db)
|
|
|
|
framework.db.disconnect()
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Connect to an existing Postgres database
|
|
|
|
#
|
2009-04-12 07:09:03 +00:00
|
|
|
def db_connect_postgresql(*args)
|
2009-11-14 21:41:38 +00:00
|
|
|
if(args[0] == nil or args[0] == "-h" or args[0] == "--help")
|
|
|
|
print_status(" Usage: db_connect <user:pass>@<host:port>/<database>")
|
|
|
|
print_status("Examples:")
|
|
|
|
print_status(" db_connect user@metasploit3")
|
|
|
|
print_status(" db_connect user:pass@192.168.0.2/metasploit3")
|
|
|
|
print_status(" db_connect user:pass@192.168.0.2:1500/metasploit3")
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2009-04-12 07:09:03 +00:00
|
|
|
info = db_parse_db_uri_postgresql(args[0])
|
2009-03-28 21:42:30 +00:00
|
|
|
opts = { 'adapter' => 'postgresql' }
|
|
|
|
|
|
|
|
opts['username'] = info[:user] if (info[:user])
|
|
|
|
opts['password'] = info[:pass] if (info[:pass])
|
|
|
|
opts['database'] = info[:name]
|
|
|
|
opts['host'] = info[:host] if (info[:host])
|
|
|
|
opts['port'] = info[:port] if (info[:port])
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-11-14 21:41:38 +00:00
|
|
|
opts['pass'] ||= ''
|
|
|
|
|
|
|
|
# Do a little legwork to find the real database socket
|
|
|
|
if(! opts['host'])
|
|
|
|
while(true)
|
|
|
|
done = false
|
|
|
|
dirs = %W{ /var/run/postgresql /tmp }
|
|
|
|
dirs.each do |dir|
|
|
|
|
if(::File.directory?(dir))
|
|
|
|
d = ::Dir.new(dir)
|
|
|
|
d.entries.grep(/^\.s\.PGSQL.(\d+)$/).each do |ent|
|
|
|
|
opts['port'] = ent.split('.')[-1].to_i
|
|
|
|
opts['host'] = dir
|
|
|
|
done = true
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
break if done
|
|
|
|
end
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# Default to loopback
|
|
|
|
if(! opts['host'])
|
|
|
|
opts['host'] = '127.0.0.1'
|
|
|
|
end
|
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
if (not framework.db.connect(opts))
|
2009-11-14 21:41:38 +00:00
|
|
|
raise RuntimeError.new("Failed to connect to the database: #{framework.db.error}")
|
2009-03-28 21:42:30 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Create a new Postgres database instance
|
2009-11-06 16:01:24 +00:00
|
|
|
#
|
2009-04-12 07:09:03 +00:00
|
|
|
def db_create_postgresql(*args)
|
2009-03-28 21:42:30 +00:00
|
|
|
cmd_db_disconnect()
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-11-14 21:41:38 +00:00
|
|
|
if(args[0] == nil or args[0] == "-h" or args[0] == "--help")
|
|
|
|
print_status(" Usage: db_create <user:pass>@<host:port>/<database>")
|
|
|
|
print_status("Examples:")
|
|
|
|
print_status(" db_create user@metasploit3")
|
|
|
|
print_status(" db_create user:pass@192.168.0.2/metasploit3")
|
|
|
|
print_status(" db_create user:pass@192.168.0.2:1500/metasploit3")
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
return if ! db_find_tools(%W{psql dropdb createdb})
|
|
|
|
|
2009-04-12 07:09:03 +00:00
|
|
|
info = db_parse_db_uri_postgresql(args[0])
|
2009-03-28 21:42:30 +00:00
|
|
|
opts = { 'adapter' => 'postgresql' }
|
|
|
|
argv = []
|
|
|
|
|
|
|
|
if (info[:user])
|
2009-11-06 16:01:24 +00:00
|
|
|
opts['username'] = info[:user]
|
2009-03-28 21:42:30 +00:00
|
|
|
argv.push('-U')
|
|
|
|
argv.push(info[:user])
|
2009-03-28 23:04:28 +00:00
|
|
|
else
|
|
|
|
opts['username'] = 'postgres'
|
|
|
|
argv.push('-U')
|
|
|
|
argv.push('postgres')
|
2009-03-28 21:42:30 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
if (info[:pass])
|
|
|
|
print()
|
|
|
|
print_status("Warning: You will need to enter the password at the prompts below")
|
|
|
|
print()
|
|
|
|
argv.push('-W')
|
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
if (info[:host])
|
|
|
|
opts['host'] = info[:host]
|
|
|
|
argv.push('-h')
|
|
|
|
argv.push(info[:host])
|
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
if (info[:port])
|
|
|
|
opts['port'] = info[:port]
|
|
|
|
argv.push('-p')
|
|
|
|
argv.push(info[:port])
|
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
opts['database'] = info[:name]
|
|
|
|
|
|
|
|
cargs = argv.map{|c| "'#{c}' "}.join
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
system("dropdb #{cargs} #{info[:name]} >/dev/null 2>&1")
|
|
|
|
system("createdb #{cargs} #{info[:name]}")
|
|
|
|
|
2009-12-11 18:54:19 +00:00
|
|
|
opts['password'] = info[:pass] || ''
|
2009-11-14 21:41:38 +00:00
|
|
|
|
|
|
|
# Do a little legwork to find the real database socket
|
|
|
|
if(! opts['host'])
|
|
|
|
while(true)
|
|
|
|
done = false
|
|
|
|
dirs = %W{ /var/run/postgresql /tmp }
|
|
|
|
dirs.each do |dir|
|
|
|
|
if(::File.directory?(dir))
|
|
|
|
d = ::Dir.new(dir)
|
|
|
|
d.entries.grep(/^\.s\.PGSQL.(\d+)$/).each do |ent|
|
|
|
|
opts['port'] = ent.split('.')[-1].to_i
|
|
|
|
opts['host'] = dir
|
|
|
|
done = true
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
break if done
|
|
|
|
end
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# Default to loopback
|
|
|
|
if(! opts['host'])
|
|
|
|
opts['host'] = '127.0.0.1'
|
|
|
|
end
|
2009-03-28 21:42:30 +00:00
|
|
|
|
|
|
|
if (not framework.db.connect(opts))
|
2009-11-14 21:41:38 +00:00
|
|
|
raise RuntimeError.new("Failed to connect to the database: #{framework.db.error}")
|
2009-03-28 21:42:30 +00:00
|
|
|
end
|
2009-12-07 17:03:27 +00:00
|
|
|
|
|
|
|
print_status("Database creation complete (check for errors)")
|
2009-03-28 21:42:30 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Drop an existing database
|
|
|
|
#
|
2009-04-12 07:09:03 +00:00
|
|
|
def db_destroy_postgresql(*args)
|
2009-03-28 21:42:30 +00:00
|
|
|
|
|
|
|
cmd_db_disconnect()
|
|
|
|
|
2009-11-14 21:41:38 +00:00
|
|
|
return if ! db_find_tools(%W{dropdb})
|
|
|
|
|
2009-04-12 07:09:03 +00:00
|
|
|
info = db_parse_db_uri_postgresql(args[0])
|
2009-03-28 21:42:30 +00:00
|
|
|
argv = []
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
if (info[:user])
|
|
|
|
argv.push('-U')
|
|
|
|
argv.push(info[:user])
|
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
if (info[:pass])
|
|
|
|
print()
|
|
|
|
print_status("Warning: You will need to enter the password at the prompts below")
|
|
|
|
print()
|
|
|
|
argv.push('-W')
|
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
if (info[:host])
|
|
|
|
argv.push('-h')
|
|
|
|
argv.push(info[:host])
|
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-03-28 21:42:30 +00:00
|
|
|
if (info[:port])
|
|
|
|
argv.push('-p')
|
|
|
|
argv.push(info[:port])
|
|
|
|
end
|
|
|
|
|
|
|
|
cargs = argv.map{|c| "'#{c}' "}.join
|
|
|
|
system("dropdb #{cargs} #{info[:name]}")
|
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2009-04-12 07:09:03 +00:00
|
|
|
def db_parse_db_uri_postgresql(path)
|
2009-03-28 21:42:30 +00:00
|
|
|
res = {}
|
|
|
|
if (path)
|
|
|
|
auth, dest = path.split('@')
|
|
|
|
(dest = auth and auth = nil) if not dest
|
|
|
|
res[:user],res[:pass] = auth.split(':') if auth
|
|
|
|
targ,name = dest.split('/')
|
|
|
|
(name = targ and targ = nil) if not name
|
|
|
|
res[:host],res[:port] = targ.split(':') if targ
|
|
|
|
end
|
|
|
|
res[:name] = name || 'metasploit3'
|
|
|
|
res
|
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|
2006-05-30 15:44:48 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2008-10-27 22:47:09 +00:00
|
|
|
end
|
2009-11-06 16:01:24 +00:00
|
|
|
|