massive changes to the database api. Auxiliary::Report is now just a bunch of stubs into the main DBManager, most aux modules should just work, but they haven't all been tested. introduces a get_auth_info method for pulling credentials out of the db. other db api methods should be more standardized now. cross your fingers
git-svn-id: file:///home/svn/framework3/trunk@8028 4d416f70-5f16-0410-b530-b9f4589650da
This commit is contained in:
parent
c3038d4027
commit
02eb7ab80d
|
@ -8,31 +8,6 @@ module Msf
|
|||
|
||||
module Auxiliary::Report
|
||||
|
||||
|
||||
module HttpClients
|
||||
IE = "MSIE"
|
||||
FF = "Firefox"
|
||||
SAFARI = "Safari"
|
||||
OPERA = "Opera"
|
||||
|
||||
UNKNOWN = "Unknown"
|
||||
end
|
||||
module OperatingSystems
|
||||
LINUX = "Linux"
|
||||
MAC_OSX = "MacOSX"
|
||||
WINDOWS = "Windows"
|
||||
|
||||
module WindowsVersions
|
||||
XP = "XP"
|
||||
TWOK = "2000"
|
||||
TWOK3 = "2003"
|
||||
VISTA = "Vista"
|
||||
end
|
||||
|
||||
UNKNOWN = "Unknown"
|
||||
end
|
||||
|
||||
|
||||
# Shortcut method for detecting when the DB is active
|
||||
def db
|
||||
framework.db.active
|
||||
|
@ -48,22 +23,12 @@ module Auxiliary::Report
|
|||
#
|
||||
def report_host(opts)
|
||||
return if not db
|
||||
addr = opts[:host] || return
|
||||
|
||||
framework.db.queue Proc.new {
|
||||
framework.db.report_host_state(self, addr, Msf::HostState::Alive)
|
||||
host = nil
|
||||
|
||||
opts.delete(:host)
|
||||
if (opts.length > 0)
|
||||
host = framework.db.report_host(self, addr, opts)
|
||||
end
|
||||
}
|
||||
framework.db.report_host(opts)
|
||||
end
|
||||
|
||||
def get_host(addr)
|
||||
return nil if not db
|
||||
framework.db.get_host(self, addr)
|
||||
return if not db
|
||||
framework.db.get_host(addr)
|
||||
end
|
||||
|
||||
#
|
||||
|
@ -78,17 +43,12 @@ module Auxiliary::Report
|
|||
#
|
||||
def report_client(opts={})
|
||||
return if not db
|
||||
addr = opts.delete(:host) || return
|
||||
|
||||
framework.db.queue Proc.new {
|
||||
framework.db.report_host_state(self, addr, Msf::HostState::Alive)
|
||||
cli = framework.db.report_client(self, addr, opts)
|
||||
}
|
||||
framework.db.report_client(opts)
|
||||
end
|
||||
|
||||
def get_client(addr, ua_string)
|
||||
return nil if not db
|
||||
framework.db.get_client(self, addr, ua_string)
|
||||
def get_client(opts={})
|
||||
return if not db
|
||||
framework.db.get_client(opts)
|
||||
end
|
||||
|
||||
#
|
||||
|
@ -96,114 +56,27 @@ module Auxiliary::Report
|
|||
#
|
||||
def report_service(opts={})
|
||||
return if not db
|
||||
addr = opts[:host] || return
|
||||
port = opts[:port] || return
|
||||
proto = opts[:proto] || 'tcp'
|
||||
name = opts[:name]
|
||||
state = opts[:state] || 'open'
|
||||
info = opts[:info]
|
||||
hname = opts[:host_name]
|
||||
maddr = opts[:host_mac]
|
||||
|
||||
framework.db.queue Proc.new {
|
||||
framework.db.report_host_state(self, addr, Msf::HostState::Alive)
|
||||
|
||||
serv = framework.db.report_service_state(
|
||||
self,
|
||||
addr,
|
||||
proto,
|
||||
port,
|
||||
state
|
||||
)
|
||||
|
||||
changed = false
|
||||
if(hname)
|
||||
self.host.name = hname
|
||||
changed = true
|
||||
end
|
||||
|
||||
if(maddr)
|
||||
self.host.mac = maddr
|
||||
changed = true
|
||||
end
|
||||
serv.host.save! if changed
|
||||
|
||||
|
||||
changed = false
|
||||
if (name and name.length > 1)
|
||||
serv.name = name.downcase
|
||||
changed = true
|
||||
end
|
||||
|
||||
if (info and info.length > 1)
|
||||
serv.info = info
|
||||
changed = true
|
||||
end
|
||||
|
||||
serv.save! if changed
|
||||
}
|
||||
framework.db.report_service(opts)
|
||||
end
|
||||
|
||||
def report_note(opts={})
|
||||
return if not db
|
||||
addr = opts[:host] || return
|
||||
ntype = opts[:type] || return
|
||||
data = opts[:data] || return
|
||||
|
||||
framework.db.queue Proc.new {
|
||||
host = framework.db.report_host_state(self, addr, Msf::HostState::Alive)
|
||||
note = framework.db.get_note(self, host, ntype, data)
|
||||
}
|
||||
end
|
||||
|
||||
def report_vuln_service(opts={})
|
||||
return if not db
|
||||
|
||||
framework.db.queue Proc.new {
|
||||
serv = report_service(opts)
|
||||
return if not serv
|
||||
|
||||
vname = opts[:vname]
|
||||
vdata = opts[:vdata] || ''
|
||||
|
||||
host = serv.host
|
||||
vuln = framework.db.get_vuln(self, host, serv, vname, vdata)
|
||||
|
||||
framework.db.vuln_add_refs(self, vuln, opts[:refs])
|
||||
}
|
||||
end
|
||||
|
||||
def report_vuln_host(opts={})
|
||||
return if not db
|
||||
addr = opts[:host] || return
|
||||
|
||||
framework.db.queue Proc.new {
|
||||
host = framework.db.report_host_state(self, addr, Msf::HostState::Alive)
|
||||
vname = opts[:vname]
|
||||
vdata = opts[:vdata] || ''
|
||||
|
||||
vuln = framework.db.get_vuln(self, host, nil, vname, vdata)
|
||||
|
||||
framework.db.vuln_add_refs(self, vuln, opts[:refs])
|
||||
}
|
||||
framework.db.report_note(opts)
|
||||
end
|
||||
|
||||
def report_auth_info(opts={})
|
||||
return if not db
|
||||
addr = opts[:host] || return
|
||||
data = opts[:proto] || return
|
||||
|
||||
opts[:type] = "auth_#{opts[:proto]}"
|
||||
opts[:data] =
|
||||
"AUTH #{ opts[:targ_host] || 'unknown' }:#{ opts[:targ_port] || 'unknown' } " +
|
||||
"#{opts[:user] || "<NULL>"} #{opts[:pass] || "<NULL>" } #{opts[:extra]}"
|
||||
print_status("Recording successful #{data} credentials for #{addr}")
|
||||
report_note(opts)
|
||||
framework.db.report_auth_info(opts)
|
||||
end
|
||||
|
||||
def find_note(host, ntype)
|
||||
def report_vuln_service(opts={})
|
||||
return if not db
|
||||
framework.db.find_note(host, ntype)
|
||||
framework.db.report_vuln_service(opts)
|
||||
end
|
||||
|
||||
def report_vuln_host(opts={})
|
||||
return if not db
|
||||
framework.db.report_vuln_host(opts)
|
||||
end
|
||||
|
||||
|
||||
|
|
|
@ -46,6 +46,28 @@ RankingName =
|
|||
ExcellentRanking => "excellent"
|
||||
}
|
||||
|
||||
module HttpClients
|
||||
IE = "MSIE"
|
||||
FF = "Firefox"
|
||||
SAFARI = "Safari"
|
||||
OPERA = "Opera"
|
||||
|
||||
UNKNOWN = "Unknown"
|
||||
end
|
||||
module OperatingSystems
|
||||
LINUX = "Linux"
|
||||
MAC_OSX = "MacOSX"
|
||||
WINDOWS = "Windows"
|
||||
|
||||
module WindowsVersions
|
||||
XP = "XP"
|
||||
TWOK = "2000"
|
||||
TWOK3 = "2003"
|
||||
VISTA = "Vista"
|
||||
end
|
||||
|
||||
UNKNOWN = "Unknown"
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
|
@ -65,4 +87,4 @@ LICENSES =
|
|||
BSD_LICENSE,
|
||||
ARTISTIC_LICENSE,
|
||||
UNKNOWN_LICENSE
|
||||
]
|
||||
]
|
||||
|
|
|
@ -50,47 +50,47 @@ module DatabaseEvent
|
|||
#
|
||||
# Called when an existing host's state changes
|
||||
#
|
||||
def on_db_host_state(context, host, ostate)
|
||||
def on_db_host_state(host, ostate)
|
||||
end
|
||||
|
||||
#
|
||||
# Called when an existing service's state changes
|
||||
#
|
||||
def on_db_service_state(context, host, port, ostate)
|
||||
def on_db_service_state(host, port, ostate)
|
||||
end
|
||||
|
||||
#
|
||||
# Called when a new host is added to the database. The host parameter is
|
||||
# of type Host.
|
||||
#
|
||||
def on_db_host(context, host)
|
||||
def on_db_host(host)
|
||||
end
|
||||
|
||||
#
|
||||
# Called when a new client is added to the database. The client
|
||||
# parameter is of type Client.
|
||||
#
|
||||
def on_db_client(context, client)
|
||||
def on_db_client(client)
|
||||
end
|
||||
|
||||
#
|
||||
# Called when a new service is added to the database. The service
|
||||
# parameter is of type Service.
|
||||
#
|
||||
def on_db_service(context, service)
|
||||
def on_db_service(service)
|
||||
end
|
||||
|
||||
#
|
||||
# Called when an applicable vulnerability is found for a service. The vuln
|
||||
# parameter is of type Vuln.
|
||||
#
|
||||
def on_db_vuln(context, vuln)
|
||||
def on_db_vuln(vuln)
|
||||
end
|
||||
|
||||
#
|
||||
# Called when a new reference is created.
|
||||
#
|
||||
def on_db_ref(context, ref)
|
||||
def on_db_ref(ref)
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -109,42 +109,52 @@ class DBManager
|
|||
res = Host.find(:all)
|
||||
end
|
||||
|
||||
#
|
||||
# Reports a host as being in a given state by address.
|
||||
#
|
||||
def report_host_state(mod, addr, state, context = nil)
|
||||
|
||||
# TODO: use the current thread's Comm to find the host
|
||||
comm = ''
|
||||
host = get_host(context, addr, comm)
|
||||
def default_workspace
|
||||
Workspace.default
|
||||
end
|
||||
|
||||
ostate = host.state
|
||||
host.state = state
|
||||
host.save
|
||||
|
||||
framework.events.on_db_host_state(context, host, ostate)
|
||||
return host
|
||||
def find_workspace(name)
|
||||
Workspace.find_by_name(name)
|
||||
end
|
||||
|
||||
#
|
||||
# Report a host's attributes such as operating system and service pack
|
||||
# Creates a new workspace in the database
|
||||
#
|
||||
# At the time of this writing, the opts parameter can contain:
|
||||
# :state -- one of the Msf::HostState constants
|
||||
# :os_name -- one of the Msf::Auxiliary::Report::OperatingSystems constants
|
||||
# :os_flavor -- something like "XP" or "Gentoo"
|
||||
# :os_sp -- something like "SP2"
|
||||
# :os_lang -- something like "English" or "French"
|
||||
# :arch -- one of the ARCH_* constants
|
||||
#
|
||||
# See <MSF install dir>/data/sql/*.sql for more info
|
||||
#
|
||||
def report_host(mod, addr, opts = {}, context = nil)
|
||||
def add_workspace(name)
|
||||
Workspace.find_or_create_by_name(name)
|
||||
end
|
||||
|
||||
report_host_state(mod, addr, opts[:state] || Msf::HostState::Alive)
|
||||
opts.delete(:state)
|
||||
def workspaces
|
||||
Workspace.find(:all)
|
||||
end
|
||||
|
||||
host = get_host(context, addr, '')
|
||||
|
||||
#
|
||||
# Find a host. Performs no database writes.
|
||||
#
|
||||
def get_host(opts)
|
||||
if opts.kind_of? Host
|
||||
return opts
|
||||
elsif opts.kind_of? String
|
||||
address = opts
|
||||
else
|
||||
address = opts[:addr] || opts[:address] || opts[:host] || return
|
||||
return address if address.kind_of? Host
|
||||
end
|
||||
host = workspace.hosts.find_by_address(address)
|
||||
return host
|
||||
end
|
||||
|
||||
def find_or_initialize_host(opts)
|
||||
addr = opts.delete(:host) || return
|
||||
return addr if addr.kind_of? Host
|
||||
|
||||
#if opts[:comm] and opts[:comm].length > 0
|
||||
# host = workspace.hosts.find_or_initialize_by_address_and_comm(addr, opts[:comm])
|
||||
#else
|
||||
host = workspace.hosts.find_or_initialize_by_address(addr)
|
||||
#end
|
||||
|
||||
opts.each { |k,v|
|
||||
if (host.attribute_names.include?(k.to_s))
|
||||
|
@ -153,67 +163,62 @@ class DBManager
|
|||
dlog("Unknown attribute for Host: #{k}")
|
||||
end
|
||||
}
|
||||
|
||||
host.save
|
||||
host.state = HostState::Unknown if not host.state
|
||||
host.comm = '' if not host.comm
|
||||
host.workspace = workspace if not host.workspace
|
||||
|
||||
return host
|
||||
end
|
||||
|
||||
#
|
||||
# Exactly like report_host but ensures that the returned Host has been
|
||||
# written to the database. Returns nil on error.
|
||||
#
|
||||
# Report a client running on a host.
|
||||
#
|
||||
# opts must contain :ua_string
|
||||
# opts can contain :ua_name and :ua_ver
|
||||
#
|
||||
def report_client(mod, addr, opts = {}, context = nil)
|
||||
if opts[:ua_string].nil?
|
||||
elog("report_client requires a ua_string", 'db', LEV_0, caller)
|
||||
return
|
||||
end
|
||||
# TODO: use the current thread's Comm to find the host
|
||||
comm = ''
|
||||
host = get_host(context, addr, comm)
|
||||
cli = get_client(context, host, opts[:ua_string])
|
||||
|
||||
opts.each { |k,v|
|
||||
if (cli.attribute_names.include?(k.to_s))
|
||||
cli[k] = v
|
||||
else
|
||||
dlog("Unknown attribute for Client: #{k}")
|
||||
def find_or_create_host(opts)
|
||||
host = find_or_initialize_host(opts)
|
||||
|
||||
if (host and host.changed?)
|
||||
host.created = Time.now
|
||||
task = framework.db.queue( Proc.new { host.save! } )
|
||||
task.wait
|
||||
if task.status != :done
|
||||
return nil
|
||||
end
|
||||
}
|
||||
cli.save
|
||||
return cli
|
||||
end
|
||||
|
||||
#
|
||||
# This method reports a host's service state.
|
||||
#
|
||||
def report_service_state(mod, addr, proto, port, state, context = nil)
|
||||
|
||||
# TODO: use the current thread's Comm to find the host
|
||||
comm = ''
|
||||
host = get_host(context, addr, comm)
|
||||
port = get_service(context, host, proto, port, state)
|
||||
|
||||
ostate = port.state
|
||||
port.state = state
|
||||
port.save
|
||||
|
||||
if (ostate != state)
|
||||
framework.events.on_db_service_state(context, host, port, ostate)
|
||||
end
|
||||
|
||||
return port
|
||||
end
|
||||
|
||||
def workspaces
|
||||
Workspace.find(:all)
|
||||
return host
|
||||
end
|
||||
|
||||
#
|
||||
# This method iterates the hosts table calling the supplied block with the
|
||||
# host instance of each entry.
|
||||
# Report a host's attributes such as operating system and service pack
|
||||
#
|
||||
# The opts parameter MUST contain
|
||||
# :address -- the host's ip address
|
||||
#
|
||||
# The opts parameter can contain:
|
||||
# :state -- one of the Msf::HostState constants
|
||||
# :os_name -- one of the Msf::OperatingSystems constants
|
||||
# :os_flavor -- something like "XP" or "Gentoo"
|
||||
# :os_sp -- something like "SP2"
|
||||
# :os_lang -- something like "English" or "French"
|
||||
# :arch -- one of the ARCH_* constants
|
||||
# :mac -- the host's MAC address
|
||||
#
|
||||
# Returns a Host that may not have been written to the database yet.
|
||||
# If you need to be sure that the insert succeeded, use
|
||||
# find_or_create_host.
|
||||
#
|
||||
def report_host(opts)
|
||||
host = find_or_initialize_host(opts)
|
||||
if (host.changed?)
|
||||
host.created = Time.now
|
||||
framework.db.queue( Proc.new { host.save! } )
|
||||
end
|
||||
return host
|
||||
end
|
||||
|
||||
#
|
||||
# Iterates over the hosts table calling the supplied block with the host
|
||||
# instance of each entry.
|
||||
#
|
||||
def each_host(&block)
|
||||
workspace.hosts.each do |host|
|
||||
|
@ -222,7 +227,7 @@ class DBManager
|
|||
end
|
||||
|
||||
#
|
||||
# This methods returns a list of all hosts in the database
|
||||
# Returns a list of all hosts in the database
|
||||
#
|
||||
def hosts(only_up = false, addresses = nil)
|
||||
conditions = {}
|
||||
|
@ -231,8 +236,63 @@ class DBManager
|
|||
workspace.hosts.all(:conditions => conditions, :order => :address)
|
||||
end
|
||||
|
||||
|
||||
|
||||
def find_or_initialize_service(opts)
|
||||
addr = opts.delete(:host) || return
|
||||
host = find_or_create_host({:host => addr})
|
||||
service = host.services.find_or_initialize_by_port_and_proto(opts[:port], opts[:proto])
|
||||
opts.each { |k,v|
|
||||
if (service.attribute_names.include?(k.to_s))
|
||||
service[k] = v
|
||||
else
|
||||
dlog("Unknown attribute for Service: #{k}")
|
||||
end
|
||||
}
|
||||
return service
|
||||
end
|
||||
|
||||
def find_or_create_service(opts)
|
||||
service = find_or_initialize_service(opts)
|
||||
if (service and service.changed?)
|
||||
service.created = Time.now
|
||||
task = framework.db.queue(Proc.new { service.save! })
|
||||
task.wait
|
||||
if task.status != :done
|
||||
return nil
|
||||
end
|
||||
end
|
||||
return service
|
||||
end
|
||||
|
||||
#
|
||||
# Record a service in the database.
|
||||
#
|
||||
# This method iterates the services table calling the supplied block with the
|
||||
# opts must contain
|
||||
# :port -- the port where this service listens
|
||||
# :proto -- the protocol (e.g. tcp, udp...)
|
||||
#
|
||||
# Returns a Service. Not guaranteed to have been written to the db yet.
|
||||
# If you need to be sure that the insert succeeded, use
|
||||
# find_or_create_service.
|
||||
#
|
||||
def report_service(opts)
|
||||
service = find_or_initialize_service(opts)
|
||||
if (service and service.changed?)
|
||||
service.created = Time.now
|
||||
framework.db.queue(Proc.new { service.save! })
|
||||
end
|
||||
return service
|
||||
end
|
||||
|
||||
def get_service(host, proto, port)
|
||||
host = get_host(host)
|
||||
return if not host
|
||||
return host.services.find_by_proto_and_port(proto, port)
|
||||
end
|
||||
|
||||
#
|
||||
# Iterates over the services table calling the supplied block with the
|
||||
# service instance of each entry.
|
||||
#
|
||||
def each_service(&block)
|
||||
|
@ -242,7 +302,7 @@ class DBManager
|
|||
end
|
||||
|
||||
#
|
||||
# This methods returns a list of all services in the database
|
||||
# Returns a list of all services in the database
|
||||
#
|
||||
def services(only_up = false, proto = nil, addresses = nil, ports = nil, names = nil)
|
||||
conditions = {}
|
||||
|
@ -254,6 +314,66 @@ class DBManager
|
|||
workspace.services.all(:include => :host, :conditions => conditions, :order => "hosts.address, port")
|
||||
end
|
||||
|
||||
|
||||
def get_client(opts)
|
||||
host = get_host(:host => opts[:host]) || return
|
||||
client = host.clients.find(:first, :conditions => {:ua_string => opts[:ua_string]})
|
||||
return client
|
||||
end
|
||||
|
||||
def find_or_initialize_client(opts)
|
||||
host = find_or_create_host(:host => opts.delete(:host))
|
||||
return if not host
|
||||
client = host.clients.find_or_initialize_by_ua_string(opts[:ua_string])
|
||||
opts.each { |k,v|
|
||||
if (client.attribute_names.include?(k.to_s))
|
||||
client[k] = v
|
||||
else
|
||||
dlog("Unknown attribute for Client: #{k}")
|
||||
end
|
||||
}
|
||||
return client
|
||||
end
|
||||
|
||||
def find_or_create_client(opts)
|
||||
client = find_or_initialize_client(opts)
|
||||
|
||||
if (client and client.changed?)
|
||||
client.created = Time.now
|
||||
task = framework.db.queue(Proc.new { client.save! })
|
||||
task.wait
|
||||
if task.status != :done
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
return client
|
||||
end
|
||||
|
||||
#
|
||||
# Report a client running on a host.
|
||||
#
|
||||
# opts must contain
|
||||
# :ua_string -- the value of the User-Agent header
|
||||
#
|
||||
# opts can contain
|
||||
# :ua_name -- one of the Msf::HttpClients constants
|
||||
# :ua_ver -- detected version of the given client
|
||||
#
|
||||
# Returns a Client. Not guaranteed to have been written to the database.
|
||||
# If you need to be sure that the insert succeeded, use
|
||||
# find_or_create_client.
|
||||
#
|
||||
def report_client(opts)
|
||||
client = find_or_initialize_client(opts)
|
||||
if (client and client.changed?)
|
||||
client.created = Time.now
|
||||
framework.db.queue(Proc.new { client.save! })
|
||||
end
|
||||
|
||||
return client
|
||||
end
|
||||
|
||||
#
|
||||
# This method iterates the vulns table calling the supplied block with the
|
||||
# vuln instance of each entry.
|
||||
|
@ -282,12 +402,50 @@ class DBManager
|
|||
end
|
||||
|
||||
#
|
||||
# Find a note matching this host address and note type
|
||||
# Find or create a note matching this type/data
|
||||
#
|
||||
def find_note(address, ntype)
|
||||
host = workspace.hosts.find_by_address(address)
|
||||
return nil if host.nil?
|
||||
host.notes.find_by_ntype(ntype)
|
||||
def find_or_create_note(opts)
|
||||
note = find_or_initialize_note(opts)
|
||||
if (note.changed?)
|
||||
note.created = Time.now
|
||||
task = framework.db.queue(Proc.new {note.save!})
|
||||
task.wait
|
||||
if (task.status != :done)
|
||||
return nil
|
||||
end
|
||||
end
|
||||
return note
|
||||
end
|
||||
|
||||
def find_or_initialize_note(opts)
|
||||
ntype = opts.delete(:type) || opts.delete(:ntype) || return
|
||||
data = opts[:data] || return
|
||||
|
||||
note = workspace.notes.find_or_initialize_by_ntype_and_data(ntype, data.to_yaml)
|
||||
p note
|
||||
|
||||
if opts[:host]
|
||||
if opts[:host].kind_of? Host
|
||||
host = opts[:host].dup
|
||||
else
|
||||
host = find_or_create_host({:host => opts[:host]})
|
||||
end
|
||||
note.host = host
|
||||
end
|
||||
if opts[:service] and opts[:service].kind_of? Service
|
||||
note.service = service
|
||||
end
|
||||
|
||||
return note
|
||||
end
|
||||
|
||||
def report_note(opts)
|
||||
note = find_or_initialize_note(opts)
|
||||
if (note and note.changed?)
|
||||
note.created = Time.now
|
||||
task = framework.db.queue(Proc.new {note.save!})
|
||||
end
|
||||
return note
|
||||
end
|
||||
|
||||
#
|
||||
|
@ -297,141 +455,150 @@ class DBManager
|
|||
workspace.notes
|
||||
end
|
||||
|
||||
def default_workspace
|
||||
Workspace.default
|
||||
end
|
||||
|
||||
def find_workspace(name)
|
||||
Workspace.find_by_name(name)
|
||||
end
|
||||
###
|
||||
# Specific notes
|
||||
###
|
||||
|
||||
#
|
||||
# Creates a new workspace in the database
|
||||
# opts must contain
|
||||
# :data -- a hash containing the authentication info
|
||||
#
|
||||
# opts can contain
|
||||
# :host -- an ip address or Host
|
||||
# :service -- a Service
|
||||
# :proto -- the protocol
|
||||
# :port -- the port
|
||||
#
|
||||
def add_workspace(context, name)
|
||||
Workspace.find_or_create_by_name(name)
|
||||
def report_auth_info(opts={})
|
||||
return if not framework.db.active
|
||||
host = opts.delete(:host)
|
||||
service = opts.delete(:service)
|
||||
proto = opts.delete(:proto) || "generic"
|
||||
proto = proto.downcase
|
||||
|
||||
note = {
|
||||
:ntype => "auth:#{proto}",
|
||||
:host => host,
|
||||
:service => service,
|
||||
:data => opts
|
||||
}
|
||||
|
||||
report_note(note)
|
||||
end
|
||||
|
||||
#
|
||||
# Find or create a host matching this address/comm
|
||||
#
|
||||
def get_host(context, address, comm='')
|
||||
if comm.length > 0
|
||||
host = workspace.hosts.find_by_address_and_comm(address, comm)
|
||||
def get_auth_info(opts={})
|
||||
return if not framework.db.active
|
||||
condition = ""
|
||||
condition_values = []
|
||||
if opts[:host]
|
||||
host = get_host(opts[:host])
|
||||
condition = "host_id == ?"
|
||||
condition_values = host.id
|
||||
end
|
||||
if opts[:proto]
|
||||
if condition.length > 0
|
||||
condition << " and "
|
||||
end
|
||||
condition << "ntype = ?"
|
||||
condition_values << "auth:#{opts[:proto].downcase}"
|
||||
else
|
||||
host = workspace.hosts.find_by_address(address)
|
||||
if condition.length > 0
|
||||
condition << " and "
|
||||
end
|
||||
condition << "ntype LIKE ?"
|
||||
condition_values << "auth:%"
|
||||
end
|
||||
if (not host)
|
||||
host = workspace.hosts.create(
|
||||
:address => address,
|
||||
:comm => comm,
|
||||
:state => HostState::Unknown,
|
||||
:created => Time.now)
|
||||
framework.events.on_db_host(context, host)
|
||||
end
|
||||
|
||||
return host
|
||||
conditions = [ condition ] + condition_values
|
||||
info = framework.db.notes.find(:all, :conditions => conditions )
|
||||
return info.map{|i| i.data} if info
|
||||
end
|
||||
|
||||
#
|
||||
# Find or create a client on host that matches ua_string
|
||||
#
|
||||
def get_client(context, host, ua_string, comm='')
|
||||
# Allow host to be an address to look up
|
||||
if !host.kind_of? Host
|
||||
host = get_host(context, host, comm)
|
||||
end
|
||||
return nil if host.nil?
|
||||
rec = host.clients.find_by_ua_string(ua_string)
|
||||
if (not rec)
|
||||
rec = host.clients.create(
|
||||
:ua_string => ua_string,
|
||||
:created => Time.now
|
||||
)
|
||||
framework.events.on_db_client(context, rec)
|
||||
end
|
||||
return rec
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Find or create a service matching this host/proto/port/state
|
||||
#
|
||||
def get_service(context, host, proto, port, state=ServiceState::Up)
|
||||
rec = host.services.find_by_proto_and_port(proto, port)
|
||||
if (not rec)
|
||||
rec = host.services.create(
|
||||
:proto => proto,
|
||||
:port => port,
|
||||
:state => state,
|
||||
:created => Time.now
|
||||
)
|
||||
framework.events.on_db_service(context, rec)
|
||||
#
|
||||
def find_or_initialize_vuln(opts)
|
||||
host = find_or_create_host({:host => opts[:host]}) || return
|
||||
name = opts[:name] || return
|
||||
data = opts[:data]
|
||||
|
||||
if data
|
||||
vuln = host.vulns.find_or_initialize_by_name_and_data(name, data)
|
||||
else
|
||||
vuln = host.vulns.find_or_initialize_by_name(name)
|
||||
end
|
||||
return rec
|
||||
p vuln
|
||||
|
||||
if opts[:service] and opts[:service].kind_of? Service
|
||||
vuln.service = opts[:service]
|
||||
end
|
||||
|
||||
return vuln
|
||||
end
|
||||
|
||||
#
|
||||
# Find or create a vuln matching this service/name
|
||||
#
|
||||
def get_vuln(context, host, service, name, data='')
|
||||
vuln = nil
|
||||
def find_or_create_vuln(opts)
|
||||
vuln = find_or_initialize_vuln(opts)
|
||||
if vuln and vuln.changed?
|
||||
vuln.created = Time.now
|
||||
task = framework.db.queue(Proc.new { vuln.save! })
|
||||
task.wait
|
||||
if task.status != :done
|
||||
return nil
|
||||
end
|
||||
end
|
||||
return vuln
|
||||
end
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
def report_vuln(opts)
|
||||
if vuln.changed?
|
||||
vuln.created = Time.now
|
||||
framework.db.queue(Proc.new { vuln.save! })
|
||||
end
|
||||
return vuln
|
||||
end
|
||||
|
||||
def get_vuln(host, service, name, data='')
|
||||
vuln = nil
|
||||
if (service)
|
||||
vuln = Vuln.find(:first, :conditions => [ "name = ? and service_id = ? and host_id = ?", name, service.id, host.id])
|
||||
else
|
||||
vuln = Vuln.find(:first, :conditions => [ "name = ? and host_id = ?", name, host.id])
|
||||
end
|
||||
|
||||
if (not vuln)
|
||||
vuln = Vuln.create(
|
||||
:service_id => service ? service.id : 0,
|
||||
:host_id => host.id,
|
||||
:name => name,
|
||||
:data => data,
|
||||
:created => Time.now
|
||||
)
|
||||
framework.events.on_db_vuln(context, vuln)
|
||||
end
|
||||
|
||||
return vuln
|
||||
end
|
||||
|
||||
#
|
||||
# Find or create a reference matching this name
|
||||
#
|
||||
def get_ref(context, name)
|
||||
ref = Ref.find_by_name(name)
|
||||
if (not ref)
|
||||
ref = Ref.create(
|
||||
:name => name,
|
||||
:created => Time.now
|
||||
)
|
||||
framework.events.on_db_ref(context, ref)
|
||||
def find_or_create_ref(opts)
|
||||
ref = Ref.find_or_initialize_by_name(opts[:name])
|
||||
if ref and ref.changed?
|
||||
ref.created = Time.now
|
||||
task = framework.db.queue(Proc.new { ref.save! })
|
||||
task.wait
|
||||
if task.status != :done
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
return ref
|
||||
end
|
||||
|
||||
#
|
||||
# Find or create a note matching this type/data
|
||||
#
|
||||
def get_note(context, host, ntype, data)
|
||||
rec = host.notes.find_by_ntype_and_data(ntype, data)
|
||||
if (not rec)
|
||||
rec = host.notes.create(
|
||||
:ntype => ntype,
|
||||
:data => data,
|
||||
:created => Time.now
|
||||
)
|
||||
framework.events.on_db_note(context, rec)
|
||||
end
|
||||
return rec
|
||||
def get_ref(name)
|
||||
Ref.find_by_name(name)
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Deletes a host and associated data matching this address/comm
|
||||
#
|
||||
def del_host(context, address, comm='')
|
||||
def del_host(address, comm='')
|
||||
host = workspace.hosts.find_by_address_and_comm(address, comm)
|
||||
host.destroy if host
|
||||
end
|
||||
|
@ -439,8 +606,8 @@ class DBManager
|
|||
#
|
||||
# Deletes a port and associated vulns matching this port
|
||||
#
|
||||
def del_service(context, address, proto, port, comm='')
|
||||
host = get_host(context, address, comm)
|
||||
def del_service(address, proto, port, comm='')
|
||||
host = get_host(address, comm)
|
||||
return unless host
|
||||
|
||||
host.services.find(:all, :conditions => { :proto => proto, :port => port}).destroy_all
|
||||
|
@ -467,9 +634,9 @@ class DBManager
|
|||
workspace.hosts.find_by_address(addr)
|
||||
end
|
||||
|
||||
def vuln_add_refs(context, vuln, refs)
|
||||
def vuln_add_refs(vuln, refs)
|
||||
return vuln if not refs
|
||||
rids = refs.map{|r| get_ref(context, "#{r[0]}-#{r[1]}") }
|
||||
rids = refs.map{|r| get_ref("#{r[0]}-#{r[1]}") }
|
||||
vuln.refs << rids
|
||||
vuln
|
||||
end
|
||||
|
@ -669,7 +836,7 @@ class DBManager
|
|||
:ssl => ssl,
|
||||
:selected => sel
|
||||
)
|
||||
#framework.events.on_db_target(context, rec)
|
||||
#framework.events.on_db_target(rec)
|
||||
end
|
||||
|
||||
|
||||
|
@ -690,10 +857,9 @@ class DBManager
|
|||
:body => body,
|
||||
:respcode => respcode,
|
||||
:resphead => resphead,
|
||||
:response => response,
|
||||
:created => Time.now
|
||||
:response => response
|
||||
)
|
||||
#framework.events.on_db_request(context, rec)
|
||||
#framework.events.on_db_request(rec)
|
||||
end
|
||||
|
||||
#
|
||||
|
|
|
@ -152,6 +152,7 @@ class DBManager
|
|||
rescue ::Exception => e
|
||||
self.error = e
|
||||
elog("DB.connect threw an exception: #{e}")
|
||||
dlog("Call stack: #{$@.join"\n"}", LEV_1)
|
||||
return false
|
||||
end
|
||||
|
||||
|
|
|
@ -10,8 +10,10 @@ class Host < ActiveRecord::Base
|
|||
has_many :vulns, :dependent => :destroy
|
||||
has_many :notes, :dependent => :destroy
|
||||
|
||||
has_many :service_notes, :through => :services
|
||||
|
||||
validates_uniqueness_of :address, :scope => :workspace_id
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,8 +3,13 @@ class DBManager
|
|||
|
||||
class Note < ActiveRecord::Base
|
||||
include DBSave
|
||||
|
||||
belongs_to :workspace
|
||||
belongs_to :host
|
||||
belongs_to :service
|
||||
|
||||
serialize :data
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,8 +4,9 @@ class DBManager
|
|||
class Service < ActiveRecord::Base
|
||||
include DBSave
|
||||
has_many :vulns, :dependent => :destroy
|
||||
has_many :notes, :dependent => :destroy
|
||||
belongs_to :host
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -7,11 +7,12 @@ class Workspace < ActiveRecord::Base
|
|||
DEFAULT = "default"
|
||||
|
||||
has_many :hosts, :dependent => :destroy
|
||||
has_many :notes, :dependent => :destroy
|
||||
|
||||
has_many :services, :through => :hosts
|
||||
has_many :clients, :through => :hosts
|
||||
has_many :vulns, :through => :hosts
|
||||
has_many :notes, :through => :hosts
|
||||
#has_many :notes, :through => :hosts
|
||||
|
||||
validates_uniqueness_of :name
|
||||
validates_presence_of :name
|
||||
|
@ -26,4 +27,4 @@ class Workspace < ActiveRecord::Base
|
|||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -319,16 +319,24 @@ class Db
|
|||
|
||||
end
|
||||
framework.db.each_note do |note|
|
||||
next if(hosts and hosts.index(note.host.address) == nil)
|
||||
next if(hosts and (note.host == nil or 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}")
|
||||
if (note.host and note.service)
|
||||
print_status("Time: #{note.created} Note: host=#{note.host.address} service=#{note.service.name} type=#{note.ntype} data=#{note.data}")
|
||||
elsif (note.host)
|
||||
print_status("Time: #{note.created} Note: host=#{note.host.address} type=#{note.ntype} data=#{note.data}")
|
||||
elsif (note.service)
|
||||
print_status("Time: #{note.created} Note: service=#{note.service.name} type=#{note.ntype} data=#{note.data}")
|
||||
else
|
||||
print_status("Time: #{note.created} Note: type=#{note.ntype} data=#{note.data}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def cmd_db_add_host(*args)
|
||||
print_status("Adding #{args.length} hosts...")
|
||||
args.each do |address|
|
||||
host = framework.db.get_host(nil, address)
|
||||
host = framework.db.find_or_create_host(address)
|
||||
print_status("Time: #{host.created} Host: host=#{host.address}")
|
||||
end
|
||||
end
|
||||
|
@ -339,10 +347,10 @@ class Db
|
|||
return
|
||||
end
|
||||
|
||||
host = framework.db.get_host(nil, args[0])
|
||||
host = framework.db.find_or_create_host(args[0])
|
||||
return if not host
|
||||
|
||||
service = framework.db.get_service(nil, host, args[2].downcase, args[1].to_i)
|
||||
service = framework.db.get_service(host, args[2].downcase, args[1].to_i)
|
||||
return if not service
|
||||
|
||||
print_status("Time: #{service.created} Service: host=#{service.host.address} port=#{service.port} proto=#{service.proto} state=#{service.state}")
|
||||
|
@ -369,10 +377,10 @@ class Db
|
|||
ntype = args.shift
|
||||
ndata = args.join(" ")
|
||||
|
||||
host = framework.db.get_host(nil, naddr)
|
||||
host = framework.db.find_or_create_host(naddr)
|
||||
return if not host
|
||||
|
||||
note = framework.db.get_note(nil, host, ntype, ndata)
|
||||
note = framework.db.find_or_create_note(host, ntype, ndata)
|
||||
return if not note
|
||||
|
||||
print_status("Time: #{note.created} Note: host=#{note.host.address} type=#{note.ntype} data=#{note.data}")
|
||||
|
@ -819,14 +827,14 @@ class Db
|
|||
p = port.match(/^([^\(]+)\((\d+)\/([^\)]+)\)/)
|
||||
return if not p
|
||||
|
||||
host = framework.db.get_host(nil, addr)
|
||||
host = framework.db.find_or_create_host(addr)
|
||||
return if not host
|
||||
|
||||
if host.state != Msf::HostState::Alive
|
||||
framework.db.report_host_state(self, addr, Msf::HostState::Alive)
|
||||
framework.db.report_host_state(addr, Msf::HostState::Alive)
|
||||
end
|
||||
|
||||
service = framework.db.get_service(nil, host, p[3].downcase, p[2].to_i)
|
||||
service = framework.db.get_service(host, p[3].downcase, p[2].to_i)
|
||||
name = p[1].strip
|
||||
if name != "unknown"
|
||||
service.name = name
|
||||
|
@ -860,11 +868,11 @@ class Db
|
|||
|
||||
nss = 'NSS-' + nasl.to_s
|
||||
|
||||
vuln = framework.db.get_vuln(nil, host, service, nss, data)
|
||||
vuln = framework.db.get_vuln(host, service, nss, data)
|
||||
|
||||
rids = []
|
||||
refs.keys.each do |r|
|
||||
rids << framework.db.get_ref(nil, r)
|
||||
rids << framework.db.get_ref(r)
|
||||
end
|
||||
|
||||
vuln.refs << (rids - vuln.refs)
|
||||
|
@ -1007,26 +1015,32 @@ class Db
|
|||
# Whenever the parser pulls a host out of the nmap results, store
|
||||
# it, along with any associated services, in the database.
|
||||
parser.on_found_host = Proc.new { |h|
|
||||
data = {}
|
||||
if (h["addrs"].has_key?("ipv4"))
|
||||
addr = h["addrs"]["ipv4"]
|
||||
elsif (h.has_key?("ipv6"))
|
||||
addr = h["addrs"]["ipv6"]
|
||||
data[:host] = h["addrs"]["ipv4"]
|
||||
elsif (h["addrs"].has_key?("ipv6"))
|
||||
data[:host] = h["addrs"]["ipv6"]
|
||||
else
|
||||
# Don't care about addresses other than IP
|
||||
# Can't report it if it doesn't have an 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)
|
||||
if (h["addrs"].has_key?("mac"))
|
||||
data[:mac] = h["addrs"]["mac"]
|
||||
end
|
||||
data[:state] = (h["status"] == "up" ? Msf::HostState::Alive : Msf::HostState::Dead)
|
||||
host = framework.db.find_or_create_host(data)
|
||||
|
||||
# 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"]
|
||||
data = {}
|
||||
data[:proto] = p["protocol"].downcase
|
||||
data[:port] = p["portid"].to_i
|
||||
data[:state] = p["state"]
|
||||
data[:host] = host
|
||||
if p["name"] != "unknown"
|
||||
service.name = p["name"]
|
||||
data[:name] = p["name"]
|
||||
end
|
||||
service.save
|
||||
framework.db.report_service(data)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1063,14 +1077,14 @@ class Db
|
|||
|
||||
next if status != "open"
|
||||
|
||||
host = framework.db.get_host(nil, addr)
|
||||
host = framework.db.find_or_create_host(addr)
|
||||
next if not host
|
||||
|
||||
if host.state != Msf::HostState::Alive
|
||||
framework.db.report_host_state(self, addr, Msf::HostState::Alive)
|
||||
framework.db.report_host_state(addr, Msf::HostState::Alive)
|
||||
end
|
||||
|
||||
service = framework.db.get_service(nil, host, proto, port)
|
||||
service = framework.db.get_service(host, proto, port)
|
||||
if not service.name and name != "unidentified"
|
||||
service.name = name
|
||||
service.save
|
||||
|
|
|
@ -10,11 +10,11 @@ module Exploitation
|
|||
# Provides several javascript functions for determining the OS and browser versions of a client.
|
||||
#
|
||||
# getVersion(): returns an object with the following properties
|
||||
# os_name - OS name, one of the Msf::Auxiliary::Report::OperatingSystems constants
|
||||
# os_name - OS name, one of the Msf::OperatingSystems constants
|
||||
# os_flavor - OS flavor as a string (e.g.: "XP", "2000")
|
||||
# os_sp - OS service pack (e.g.: "SP2", will be empty on non-Windows)
|
||||
# os_lang - OS language (e.g.: "en-us")
|
||||
# ua_name - Client name, one of the Msf::Auxiliary::Report::HttpClients constants
|
||||
# ua_name - Client name, one of the Msf::HttpClients constants
|
||||
# ua_version - Client version as a string (e.g.: "3.5.1", "6.0;SP2")
|
||||
# arch - Architecture, one of the ARCH_* constants
|
||||
#
|
||||
|
@ -28,8 +28,8 @@ module Exploitation
|
|||
class JavascriptOSDetect < ObfuscateJS
|
||||
|
||||
def initialize(custom_js = '', opts = {})
|
||||
clients = ::Msf::Auxiliary::Report::HttpClients
|
||||
oses = ::Msf::Auxiliary::Report::OperatingSystems
|
||||
clients = ::Msf::HttpClients
|
||||
oses = ::Msf::OperatingSystems
|
||||
@js = custom_js
|
||||
@js = <<ENDJS + @js
|
||||
/**
|
||||
|
|
|
@ -132,6 +132,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
addrs = "Addresses:(" + host[:addrs].map{|n| n[0]}.uniq.join(", ") + ")"
|
||||
end
|
||||
|
||||
report_host(:host => ip, :mac => host[:mac], :os_name => os)
|
||||
print_status("#{ip} [#{host[:name]}] OS:#{os}#{user}#{names} #{addrs} Mac:#{host[:mac]}")
|
||||
end
|
||||
end
|
||||
|
|
|
@ -64,7 +64,13 @@ class Metasploit3 < Msf::Auxiliary
|
|||
end
|
||||
|
||||
print_status(info)
|
||||
report_service(:host => ip, :port => info[0], :name => 'smb', :info => "#{res['os']} #{res['sp']} (language: #{res['lang']})")
|
||||
report_service({
|
||||
:host => ip,
|
||||
:port => info[0],
|
||||
:proto => 'tcp',
|
||||
:name => 'smb',
|
||||
:info => "#{res['os']} #{res['sp']} (language: #{res['lang']})"
|
||||
})
|
||||
case res['os']
|
||||
when /Windows/
|
||||
os = OperatingSystems::WINDOWS
|
||||
|
|
|
@ -336,7 +336,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
# build the appropriate tests for it.
|
||||
method = apo[:vuln_test].dup
|
||||
apo[:vuln_test] = ""
|
||||
apo[:ua_name] = ::Msf::Auxiliary::Report::HttpClients::IE
|
||||
apo[:ua_name] = HttpClients::IE
|
||||
if apo[:classid].kind_of?(Array) # then it's many classids
|
||||
apo[:classid].each { |clsid|
|
||||
apo[:vuln_test] << "if (testAXO('#{clsid}', '#{method}')) {\n"
|
||||
|
@ -477,7 +477,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
end
|
||||
|
||||
def build_noscript_response(cli, request)
|
||||
client_info = get_client(cli.peerhost, request['User-Agent'])
|
||||
client_info = get_client(:host => cli.peerhost, :ua_string => request['User-Agent'])
|
||||
|
||||
response = create_response()
|
||||
response['Expires'] = '0'
|
||||
|
@ -518,9 +518,9 @@ class Metasploit3 < Msf::Auxiliary
|
|||
response['Expires'] = '0'
|
||||
response['Cache-Control'] = 'must-revalidate'
|
||||
|
||||
client_info = get_client(cli.peerhost, request['User-Agent'])
|
||||
#print_status("Client info: #{client_info.inspect}")
|
||||
host_info = get_host(cli.peerhost)
|
||||
client_info = get_client(:host => host_info, :ua_string => request['User-Agent'])
|
||||
|
||||
js = ::Rex::Exploitation::ObfuscateJS.new
|
||||
# If we didn't get a client from the database, then the detection
|
||||
|
@ -710,25 +710,25 @@ class Metasploit3 < Msf::Auxiliary
|
|||
detected_version = Rex::Text.decode_base64(Rex::Text.uri_decode(detected_version))
|
||||
print_status("JavaScript Report: #{detected_version}")
|
||||
(os_name, os_flavor, os_sp, os_lang, arch, ua_name, ua_ver) = detected_version.split(':')
|
||||
report_host(
|
||||
host = framework.db.find_or_create_host({
|
||||
:host => cli.peerhost,
|
||||
:os_name => os_name,
|
||||
:os_flavor => os_flavor,
|
||||
:os_sp => os_sp,
|
||||
:os_lang => os_lang,
|
||||
:arch => arch
|
||||
)
|
||||
report_client(
|
||||
:host => cli.peerhost,
|
||||
})
|
||||
report_client({
|
||||
:host => host,
|
||||
:ua_string => request['User-Agent'],
|
||||
:ua_name => ua_name,
|
||||
:ua_ver => ua_ver
|
||||
)
|
||||
report_note(
|
||||
:host => cli.peerhost,
|
||||
})
|
||||
report_note({
|
||||
:host => host,
|
||||
:type => 'http_request',
|
||||
:data => "#{@myhost}:#{@myport} #{request.method} #{request.resource} #{os_name} #{ua_name} #{ua_ver}"
|
||||
)
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -736,9 +736,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
# This is less reliable because we're not treating different user
|
||||
# agents from the same IP as different hosts.
|
||||
if (framework.db.active)
|
||||
# There really ought to be a report_client, instead of having
|
||||
# get_client create a new one if it can't find one.
|
||||
get_client(cli.peerhost, request['User-Agent'])
|
||||
report_client(:host => cli.peerhost, :ua_string => request['User-Agent'])
|
||||
else
|
||||
warn_no_database
|
||||
@targetcache ||= {}
|
||||
|
@ -768,8 +766,9 @@ class Metasploit3 < Msf::Auxiliary
|
|||
# essentially creating an in-memory database. The upside is that it works
|
||||
# if the database is broken. The downside of course is that querying from
|
||||
# a hash is not as simple or efficient as a database.
|
||||
def get_client(host, ua)
|
||||
return super(host, ua) || @targetcache[host]
|
||||
def get_client(opts)
|
||||
host = opts[:host]
|
||||
return super || @targetcache[host]
|
||||
end
|
||||
|
||||
def build_iframe(resource)
|
||||
|
|
|
@ -23,9 +23,9 @@ class Plugin::CredCollect < Msf::Plugin
|
|||
print_error("Database not connected")
|
||||
return
|
||||
end
|
||||
framework.db.each_note do |note|
|
||||
if note.ntype == "auth_HASH"
|
||||
print_line(note.data)
|
||||
framework.db.get_auth_info(:proto=>"smb").each do |info|
|
||||
if info.kind_of? Hash and info.has_key? :hash_string
|
||||
print_line(info[:hash_string])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -35,9 +35,9 @@ class Plugin::CredCollect < Msf::Plugin
|
|||
print_error("Database not connected")
|
||||
return
|
||||
end
|
||||
framework.db.each_note do |note|
|
||||
if note.ntype == "auth_TOKEN"
|
||||
print_line("#{note.host.address} - #{note.data}")
|
||||
framework.db.get_auth_info(:proto=>"smb").each do |info|
|
||||
if info.kind_of? Hash and info.has_key? :token
|
||||
print_line(info[:host] + " - " + info[:token])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -60,28 +60,37 @@ class Plugin::CredCollect < Msf::Plugin
|
|||
|
||||
# Target infos for the db record
|
||||
addr = session.sock.peerhost
|
||||
host = self.framework.db.report_host_state(self, addr, Msf::HostState::Alive)
|
||||
host = self.framework.db.find_or_create_host(
|
||||
:host => addr,
|
||||
:state => Msf::HostState::Alive
|
||||
)
|
||||
|
||||
# Record hashes to the running db instance as auth_HASH type
|
||||
hashes.each do |user|
|
||||
hashes.each do |hash|
|
||||
data = {}
|
||||
data[:host] = host
|
||||
data[:targ_host] = host.address
|
||||
data[:proto] = 'smb'
|
||||
data[:user] = hash.user_name
|
||||
data[:hash] = hash.lanman + ":" + hash.ntlm
|
||||
data[:hash_string] = hash.hash_string
|
||||
|
||||
type = "auth_HASH"
|
||||
data = user.to_s
|
||||
|
||||
# We'll make this look like an auth note anyway
|
||||
self.framework.db.get_note(self, host, type, data)
|
||||
self.framework.db.report_auth_info(data)
|
||||
end
|
||||
|
||||
|
||||
# Record user tokens
|
||||
tokens = session.incognito.incognito_list_tokens(0).values
|
||||
# Meh, tokens come to us as a formatted string
|
||||
tokens = tokens.to_s.strip!.split("\n")
|
||||
tokens = tokens.join.strip!.split("\n")
|
||||
|
||||
tokens.each do |token|
|
||||
type = "auth_TOKEN"
|
||||
data = token
|
||||
data = {}
|
||||
data[:host] = host
|
||||
data[:targ_host] = host.address
|
||||
data[:proto] = 'smb'
|
||||
data[:token] = token
|
||||
|
||||
self.framework.db.get_note(self, host, type, data)
|
||||
self.framework.db.report_auth_info(data)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -398,66 +398,62 @@ class Plugin::Nexpose < Msf::Plugin
|
|||
end
|
||||
|
||||
def process_nexpose_data_rxml(data)
|
||||
doc = REXML::Document.new(data)
|
||||
doc.elements.each('/NexposeReport/nodes/node') do |host|
|
||||
addr = host.attributes['address']
|
||||
xhost = addr
|
||||
refs = {}
|
||||
doc = REXML::Document.new(data)
|
||||
doc.elements.each('/NexposeReport/nodes/node') do |host|
|
||||
addr = host.attributes['address']
|
||||
xhost = addr
|
||||
refs = {}
|
||||
|
||||
# os based vuln
|
||||
host.elements['tests'].elements.each('test') do |vuln|
|
||||
if vuln.attributes['status'] == 'vulnerable-exploited' or vuln.attributes['status'] == 'vulnerable-version'
|
||||
dhost = framework.db.get_host(nil, addr)
|
||||
next if not dhost
|
||||
host.elements['tests'].elements.each('test') do |vuln|
|
||||
if vuln.attributes['status'] == 'vulnerable-exploited' or vuln.attributes['status'] == 'vulnerable-version'
|
||||
dhost = framework.db.find_or_create_host(:host => addr)
|
||||
next if not dhost
|
||||
|
||||
vid = vuln.attributes['id'].to_s
|
||||
nexpose_vuln_lookup(doc,vid,refs,dhost)
|
||||
nexpose_vuln_lookup(doc,vid.upcase,refs,dhost)
|
||||
vid = vuln.attributes['id'].to_s
|
||||
nexpose_vuln_lookup(doc,vid,refs,dhost)
|
||||
nexpose_vuln_lookup(doc,vid.upcase,refs,dhost)
|
||||
end
|
||||
end
|
||||
|
||||
# skip if no endpoints
|
||||
next unless host.elements['endpoints']
|
||||
# skip if no endpoints
|
||||
next unless host.elements['endpoints']
|
||||
|
||||
# parse the ports and add the vulns
|
||||
host.elements['endpoints'].elements.each('endpoint') do |port|
|
||||
prot = port.attributes['protocol']
|
||||
pnum = port.attributes['port']
|
||||
stat = port.attributes['status']
|
||||
next if not port.elements['services']
|
||||
name = port.elements['services'].elements['service'].attributes['name'].downcase
|
||||
# parse the ports and add the vulns
|
||||
host.elements['endpoints'].elements.each('endpoint') do |port|
|
||||
prot = port.attributes['protocol']
|
||||
pnum = port.attributes['port']
|
||||
stat = port.attributes['status']
|
||||
next if not port.elements['services']
|
||||
name = port.elements['services'].elements['service'].attributes['name'].downcase
|
||||
|
||||
next if not port.elements['services'].elements['service'].elements['fingerprints']
|
||||
prod = port.elements['services'].elements['service'].elements['fingerprints'].elements['fingerprint'].attributes['product']
|
||||
vers = port.elements['services'].elements['service'].elements['fingerprints'].elements['fingerprint'].attributes['version']
|
||||
vndr = port.elements['services'].elements['service'].elements['fingerprints'].elements['fingerprint'].attributes['vendor']
|
||||
next if not port.elements['services'].elements['service'].elements['fingerprints']
|
||||
prod = port.elements['services'].elements['service'].elements['fingerprints'].elements['fingerprint'].attributes['product']
|
||||
vers = port.elements['services'].elements['service'].elements['fingerprints'].elements['fingerprint'].attributes['version']
|
||||
vndr = port.elements['services'].elements['service'].elements['fingerprints'].elements['fingerprint'].attributes['vendor']
|
||||
|
||||
next if stat != 'open'
|
||||
next if stat != 'open'
|
||||
|
||||
dhost = framework.db.get_host(nil, addr)
|
||||
next if not dhost
|
||||
dhost = framework.db.find_or_create_host(:host => addr, :state => Msf::HostState::Alive)
|
||||
next if not dhost
|
||||
|
||||
if dhost.state != Msf::HostState::Alive
|
||||
framework.db.report_host_state(self, addr, Msf::HostState::Alive)
|
||||
end
|
||||
if name != "unknown"
|
||||
service = framework.db.find_or_create_service(:host => dhost, :proto => prot.downcase, :port => pnum.to_i, :name => name)
|
||||
else
|
||||
service = framework.db.find_or_create_service(:host => dhost, :proto => prot.downcase, :port => pnum.to_i)
|
||||
end
|
||||
|
||||
service = framework.db.get_service(nil, dhost, prot.downcase, pnum.to_i)
|
||||
if name != "unknown"
|
||||
service.name = name
|
||||
service.save
|
||||
end
|
||||
|
||||
port.elements['services'].elements['service'].elements['tests'].elements.each('test') do |vuln|
|
||||
if vuln.attributes['status'] == 'vulnerable-exploited' or vuln.attributes['status'] == 'vulnerable-version'
|
||||
vid = vuln.attributes['id'].to_s
|
||||
# TODO, improve the vuln_lookup check so case of the vuln_id doesnt matter
|
||||
nexpose_vuln_lookup(doc,vid,refs,dhost,service)
|
||||
nexpose_vuln_lookup(doc,vid.upcase,refs,dhost,service)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
port.elements['services'].elements['service'].elements['tests'].elements.each('test') do |vuln|
|
||||
if vuln.attributes['status'] == 'vulnerable-exploited' or vuln.attributes['status'] == 'vulnerable-version'
|
||||
vid = vuln.attributes['id'].to_s
|
||||
# TODO, improve the vuln_lookup check so case of the vuln_id doesnt matter
|
||||
nexpose_vuln_lookup(doc,vid,refs,dhost,service)
|
||||
nexpose_vuln_lookup(doc,vid.upcase,refs,dhost,service)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# NeXpose vuln lookup
|
||||
|
@ -483,11 +479,15 @@ class Plugin::Nexpose < Msf::Plugin
|
|||
|
||||
refs[ 'NEXPOSE-' + vid.downcase ] = true
|
||||
|
||||
vuln = framework.db.get_vuln(nil, host, serv, 'NEXPOSE-' + vid.downcase, title)
|
||||
vuln = framework.db.find_or_create_vuln(
|
||||
:host => host,
|
||||
:service => serv,
|
||||
:name => 'NEXPOSE-' + vid.downcase,
|
||||
:data => title)
|
||||
|
||||
rids = []
|
||||
refs.keys.each do |r|
|
||||
rids << framework.db.get_ref(nil, r)
|
||||
rids << framework.db.find_or_create_ref(:name => r)
|
||||
end
|
||||
|
||||
vuln.refs << (rids - vuln.refs)
|
||||
|
@ -503,21 +503,20 @@ class Plugin::Nexpose < Msf::Plugin
|
|||
desc = fdesc.text.to_s.strip
|
||||
end
|
||||
|
||||
host = framework.db.get_host(nil, addr)
|
||||
host = framework.db.find_or_create_host(:host => addr, :state => Msf::HostState::Alive)
|
||||
next if not host
|
||||
|
||||
if host.state != Msf::HostState::Alive
|
||||
framework.db.report_host_state(self, addr, Msf::HostState::Alive)
|
||||
end
|
||||
|
||||
# Load vulnerabilities not associated with a service
|
||||
dev.elements.each('vulnerabilities/vulnerability') do |vuln|
|
||||
vid = vuln.attributes['id'].to_s.downcase
|
||||
rids = []
|
||||
refs = process_nexpose_data_sxml_refs(vuln)
|
||||
next if not refs
|
||||
vuln = framework.db.get_vuln(nil, host, nil, 'NEXPOSE-' + vid, vid)
|
||||
refs.each { |r| rids << framework.db.get_ref(nil, r) }
|
||||
vuln = framework.db.find_or_create_vuln(
|
||||
:host => host,
|
||||
:name => 'NEXPOSE-' + vid
|
||||
:data => vid)
|
||||
refs.each { |r| rids << framework.db.find_or_create_ref(:name => r) }
|
||||
vuln.refs << (rids - vuln.refs)
|
||||
end
|
||||
|
||||
|
@ -527,10 +526,11 @@ class Plugin::Nexpose < Msf::Plugin
|
|||
sprot = svc.attributes['protocol'].to_s.downcase
|
||||
sport = svc.attributes['port'].to_s.to_i
|
||||
|
||||
serv = framework.db.get_service(nil, host, sprot, sport)
|
||||
name = sname.split('(')[0].strip
|
||||
if(sname.downcase != '<unknown>')
|
||||
serv.name = sname.split('(')[0].strip
|
||||
serv.save
|
||||
serv = framework.db.find_or_create_service(:host => host, :proto => sprot, :port => sport, :name => name)
|
||||
else
|
||||
serv = framework.db.find_or_create_service(:host => host, :proto => sprot, :port => sport)
|
||||
end
|
||||
|
||||
# Load vulnerabilities associated with this service
|
||||
|
@ -539,11 +539,11 @@ class Plugin::Nexpose < Msf::Plugin
|
|||
rids = []
|
||||
refs = process_nexpose_data_sxml_refs(vuln)
|
||||
next if not refs
|
||||
vuln = framework.db.get_vuln(nil, host, serv, 'NEXPOSE-' + vid, vid)
|
||||
refs.each { |r| rids << framework.db.get_ref(nil, r) }
|
||||
vuln = framework.db.find_or_create_vuln(:host => host, :service => serv, :name => 'NEXPOSE-' + vid, :data => vid)
|
||||
refs.each { |r| rids << framework.db.find_or_create_ref(:name => r) }
|
||||
vuln.refs << (rids - vuln.refs)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in New Issue