Fixes #2444. Adds an ExploitedHost table, adds the db_exploited command, adds the report_exploit() function.
Tested with meterpreter, shell, and clientside exploit sessions. git-svn-id: file:///home/svn/framework3/trunk@10130 4d416f70-5f16-0410-b530-b9f4589650daunstable
parent
8741179e8a
commit
1db9d8eb01
|
@ -0,0 +1,16 @@
|
|||
class AddExploitedTable < ActiveRecord::Migration
|
||||
def self.up
|
||||
create_table :exploited_hosts do |t|
|
||||
t.integer :host_id, :null => false
|
||||
t.integer :service_id
|
||||
t.string :session_uuid, :limit => 8
|
||||
t.string :name, :limit => 2048
|
||||
t.string :payload, :limit => 2048
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
def self.down
|
||||
drop_table :exploited_hosts
|
||||
end
|
||||
end
|
||||
|
|
@ -453,6 +453,13 @@ class DBManager
|
|||
)
|
||||
end
|
||||
|
||||
#
|
||||
# This method returns a list of all exploited hosts in the database.
|
||||
#
|
||||
def exploited_hosts(wspace=workspace)
|
||||
wspace.exploited_hosts
|
||||
end
|
||||
|
||||
#
|
||||
# This method iterates the notes table calling the supplied block with the
|
||||
# note instance of each entry.
|
||||
|
@ -685,6 +692,12 @@ class DBManager
|
|||
end
|
||||
end
|
||||
|
||||
def each_exploited_host(wspace=workspace,&block)
|
||||
wspace.exploited_hosts.each do |eh|
|
||||
block.call(eh)
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Find or create a vuln matching this service/name
|
||||
#
|
||||
|
@ -802,6 +815,70 @@ class DBManager
|
|||
Ref.find_by_name(name)
|
||||
end
|
||||
|
||||
def report_exploit(opts={})
|
||||
return if not active
|
||||
raise ArgumentError.new("Missing required option :host") if opts[:host].nil?
|
||||
wait = opts[:wait]
|
||||
wspace = opts.delete(:workspace) || workspace
|
||||
host = nil
|
||||
addr = nil
|
||||
sname = opts.delete(:sname)
|
||||
port = opts.delete(:port)
|
||||
proto = opts.delete(:proto) || "tcp"
|
||||
name = opts.delete(:name)
|
||||
payload = opts.delete(:payload)
|
||||
session_uuid = opts.delete(:session_uuid)
|
||||
|
||||
if opts[:host].kind_of? Host
|
||||
host = opts[:host]
|
||||
else
|
||||
report_host({:workspace => wspace, :host => opts[:host]})
|
||||
addr = opts[:host]
|
||||
end
|
||||
|
||||
if opts[:service].kind_of? Service
|
||||
service = opts[:service]
|
||||
elsif port
|
||||
report_service(:host => host, :port => port, :proto => proto, :name => sname)
|
||||
service = get_service(wspace, host, proto, port)
|
||||
else
|
||||
service = nil
|
||||
end
|
||||
|
||||
ret = {}
|
||||
|
||||
task = queue(
|
||||
Proc.new {
|
||||
if host
|
||||
host.updated_at = host.created_at
|
||||
host.state = HostState::Alive
|
||||
host.save!
|
||||
else
|
||||
host = get_host(:workspace => wspace, :address => addr)
|
||||
end
|
||||
exploit_info = {
|
||||
:workspace => wspace,
|
||||
:host_id => host.id,
|
||||
:name => name,
|
||||
:payload => payload,
|
||||
}
|
||||
exploit_info[:service_id] = service.id if service
|
||||
exploit_info[:session_uuid] = session_uuid if session_uuid
|
||||
exploit_record = ExploitedHost.create(exploit_info)
|
||||
exploit_record.save!
|
||||
|
||||
ret[:exploit] = exploit_record
|
||||
}
|
||||
)
|
||||
|
||||
if wait
|
||||
return nil if task.wait() != :done
|
||||
return ret[:exploit]
|
||||
end
|
||||
return task
|
||||
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Deletes a host and associated data matching this address/comm
|
||||
|
|
|
@ -318,14 +318,32 @@ class FrameworkEventSubscriber
|
|||
# If the exploit used was multi/handler, though, we don't know what
|
||||
# it's vulnerable to, so it isn't really useful to save it.
|
||||
if session.via_exploit and session.via_exploit != "exploit/multi/handler"
|
||||
wspace = framework.db.find_workspace(session.workspace)
|
||||
host = wspace.hosts.find_by_address(address)
|
||||
port = session.exploit_datastore["RPORT"]
|
||||
service = (port ? host.services.find_by_port(port) : nil)
|
||||
mod = framework.modules.create(session.via_exploit)
|
||||
info = {
|
||||
:host => address,
|
||||
vuln_info = {
|
||||
:host => host.address,
|
||||
:name => session.via_exploit,
|
||||
:refs => mod.references,
|
||||
:workspace => framework.db.find_workspace(session.workspace)
|
||||
:workspace => wspace
|
||||
}
|
||||
framework.db.report_vuln(info)
|
||||
framework.db.report_vuln(vuln_info)
|
||||
# Exploit info is like vuln info, except it's /just/ for storing
|
||||
# successful exploits in an unserialized way. Yes, there is
|
||||
# duplication, but it makes exporting a score card about a
|
||||
# million times easier. TODO: See if vuln/exploit can get fixed up
|
||||
# to one useful table.
|
||||
exploit_info = {
|
||||
:name => session.via_exploit,
|
||||
:payload => session.via_payload,
|
||||
:workspace => wspace,
|
||||
:host => host,
|
||||
:service => service,
|
||||
:session_uuid => session.uuid
|
||||
}
|
||||
ret = framework.db.report_exploit(exploit_info)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -13,6 +13,7 @@ require 'msf/core/model/service'
|
|||
require 'msf/core/model/workspace'
|
||||
require 'msf/core/model/vuln'
|
||||
require 'msf/core/model/cred'
|
||||
require 'msf/core/model/exploited_host'
|
||||
|
||||
require 'msf/core/model/wmap_target'
|
||||
require 'msf/core/model/wmap_request'
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
module Msf
|
||||
class DBManager
|
||||
|
||||
class ExploitedHost < ActiveRecord::Base
|
||||
include DBSave
|
||||
belongs_to :host
|
||||
belongs_to :service
|
||||
belongs_to :workspace
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -13,6 +13,7 @@ class Host < ActiveRecord::Base
|
|||
|
||||
has_many :service_notes, :through => :services
|
||||
has_many :creds, :through => :services
|
||||
has_many :exploited_hosts, :dependent => :destroy
|
||||
|
||||
validates_exclusion_of :address, :in => ['127.0.0.1']
|
||||
validates_uniqueness_of :address, :scope => :workspace_id
|
||||
|
|
|
@ -6,6 +6,7 @@ class Service < ActiveRecord::Base
|
|||
has_many :vulns, :dependent => :destroy
|
||||
has_many :notes, :dependent => :destroy
|
||||
has_many :creds, :dependent => :destroy
|
||||
has_many :exploited_hosts, :dependent => :destroy
|
||||
belongs_to :host
|
||||
|
||||
serialize :info
|
||||
|
|
|
@ -17,6 +17,7 @@ class Workspace < ActiveRecord::Base
|
|||
has_many :clients, :through => :hosts
|
||||
has_many :vulns, :through => :hosts
|
||||
has_many :creds, :dependent => :destroy
|
||||
has_many :exploited_hosts, :through => :hosts
|
||||
|
||||
#has_many :notes, :through => :hosts
|
||||
|
||||
|
|
|
@ -53,6 +53,7 @@ class Db
|
|||
"db_vulns" => "List all vulnerabilities in the database",
|
||||
"db_notes" => "List all notes in the database",
|
||||
"db_creds" => "List all credentials in the database",
|
||||
"db_exploited" => "List all exploited hosts in the database",
|
||||
"db_add_host" => "Add one or more hosts to the database",
|
||||
"db_add_port" => "Add a port to a host",
|
||||
"db_add_note" => "Add a note to a host",
|
||||
|
@ -425,6 +426,52 @@ class Db
|
|||
print_status "Found #{creds_returned} credential#{creds_returned == 1 ? "" : "s"}."
|
||||
end
|
||||
|
||||
# Returns exploited hosts. Takes a similiar set of options as db_creds
|
||||
def cmd_db_exploited(*args)
|
||||
return unless active?
|
||||
if args.size > 1
|
||||
print_status "Usage: db_exploited [host=1.2.3.4/24|port=1-1024|service=ssh,smb,etc]"
|
||||
print_status " Note, only one of host, port, or service can be used at a time."
|
||||
return
|
||||
end
|
||||
search_term = nil
|
||||
search_param = nil
|
||||
exploited_returned = 0
|
||||
if args[0] =~ /^[\s]*(host|port|service)=(.*)/i
|
||||
search_term = $1.downcase
|
||||
search_param = $2.downcase
|
||||
end
|
||||
framework.db.each_exploited_host(framework.db.workspace) do |eh|
|
||||
case search_term
|
||||
when "host"
|
||||
begin
|
||||
rw = Rex::Socket::RangeWalker.new(search_param)
|
||||
next unless rw.include? eh.host.address
|
||||
rescue
|
||||
print_error "Invalid host parameter."
|
||||
break
|
||||
end
|
||||
when "port"
|
||||
if search_param =~ /([0-9]+)-([0-9]+)/
|
||||
ports = Range.new($1,$2)
|
||||
else
|
||||
ports = Range.new(search_param,search_param)
|
||||
end
|
||||
next unless ports.include? eh.service.port.to_s
|
||||
when "service"
|
||||
svcs = search_param.split(/[\s]*,[\s]*/)
|
||||
next unless svcs.include? eh.service.name
|
||||
end
|
||||
if eh.service
|
||||
print_status("Time: #{eh.updated_at} Host Info: host=#{eh.host.address} port=#{eh.service.port} proto=#{eh.service.proto} sname=#{eh.service.name} exploit=#{eh.name}")
|
||||
else
|
||||
print_status("Time: #{eh.updated_at} Host Info: host=#{eh.host.address} exploit=#{eh.name}")
|
||||
end
|
||||
exploited_returned += 1
|
||||
end
|
||||
print_status "Found #{exploited_returned} exploited host#{exploited_returned == 1 ? "" : "s"}."
|
||||
end
|
||||
|
||||
def cmd_db_notes(*args)
|
||||
return unless active?
|
||||
hosts = nil
|
||||
|
|
Loading…
Reference in New Issue