Land #9270, Implement plugin API for hooking database events

This commit is contained in:
Brent Cook 2018-02-19 21:36:26 -06:00
commit 93689f0f0e
No known key found for this signature in database
GPG Key ID: 1FFAA0B24B708F96
6 changed files with 154 additions and 3 deletions

View File

@ -57,6 +57,14 @@ module Msf::DBManager::Client
dlog("Unknown attribute for Client: #{k}")
end
end
begin
framework.events.on_db_client(client) if client.new_record?
rescue ::Exception => e
wlog("Exception in on_db_client event handler: #{e.class}: #{e}")
wlog("Call Stack\n#{e.backtrace.join("\n")}")
end
if client && client.changed?
client.save!
end

View File

@ -120,6 +120,15 @@ module Msf::DBManager::Host
norm_host
end
def host_state_changed(host, ostate)
begin
framework.events.on_db_host_state(host, ostate)
rescue ::Exception => e
wlog("Exception in on_db_host_state event handler: #{e.class}: #{e}")
wlog("Call Stack\n#{e.backtrace.join("\n")}")
end
end
#
# Report a host's attributes such as operating system and service pack
#
@ -171,6 +180,8 @@ module Msf::DBManager::Host
host = addr
end
ostate = host.state
# Truncate the info field at the maximum field length
if opts[:info]
opts[:info] = opts[:info][0,65535]
@ -207,6 +218,15 @@ module Msf::DBManager::Host
host.comm = '' if !host.comm
host.workspace = wspace if !host.workspace
begin
framework.events.on_db_host(host) if host.new_record?
rescue ::Exception => e
wlog("Exception in on_db_host event handler: #{e.class}: #{e}")
wlog("Call Stack\n#{e.backtrace.join("\n")}")
end
host_state_changed(host, ostate) if host.state != ostate
if host.changed?
msf_import_timestamps(opts,host)
host.save!
@ -279,6 +299,8 @@ module Msf::DBManager::Host
host = addr
end
ostate = host.state
res = {}
if info['Computer']
@ -332,9 +354,8 @@ module Msf::DBManager::Host
host.comm = '' if !host.comm
host.workspace = wspace if !host.workspace
if host.changed?
host.save!
end
host.save! if host.changed?
host_state_changed(host, ostate) if host.state != ostate
host
}

View File

@ -9,6 +9,14 @@ module Msf::DBManager::Ref
::ActiveRecord::Base.connection_pool.with_connection {
ref = ::Mdm::Ref.where(name: opts[:name]).first_or_initialize
begin
framework.events.on_db_ref(ref) if ref
rescue ::Exception => e
wlog("Exception in on_db_ref event handler: #{e.class}: #{e}")
wlog("Call Stack\n#{e.backtrace.join("\n")}")
end
if ref and ref.changed?
ref.save!
end

View File

@ -89,6 +89,7 @@ module Msf::DBManager::Service
proto = opts[:proto] || Msf::DBManager::DEFAULT_SERVICE_PROTO
service = host.services.where(port: opts[:port].to_i, proto: proto).first_or_initialize
ostate = service.state
opts.each { |k,v|
if (service.attribute_names.include?(k.to_s))
service[k] = ((v and k == :name) ? v.to_s.downcase : v)
@ -99,6 +100,20 @@ module Msf::DBManager::Service
service.state ||= Msf::ServiceState::Open
service.info ||= ""
begin
framework.events.on_db_service(service) if service.new_record?
rescue ::Exception => e
wlog("Exception in on_db_service event handler: #{e.class}: #{e}")
wlog("Call Stack\n#{e.backtrace.join("\n")}")
end
begin
framework.events.on_db_service_state(service, service.port, ostate) if service.state != ostate
rescue ::Exception => e
wlog("Exception in on_db_service_state event handler: #{e.class}: #{e}")
wlog("Call Stack\n#{e.backtrace.join("\n")}")
end
if (service and service.changed?)
msf_import_timestamps(opts,service)
service.save!

View File

@ -198,6 +198,14 @@ module Msf::DBManager::Vuln
vinf[:service_id] = service.id if service
vuln = Mdm::Vuln.create(vinf)
begin
framework.events.on_db_vuln(vuln) if vuln
rescue ::Exception => e
wlog("Exception in on_db_vuln event handler: #{e.class}: #{e}")
wlog("Call Stack\n#{e.backtrace.join("\n")}")
end
end
end

91
plugins/libnotify.rb Normal file
View File

@ -0,0 +1,91 @@
###
#
# This plugin hooks all session creation and db events
# and send desktop notifications using notify-send command.
#
###
module Msf
class Plugin::EventLibnotify < Msf::Plugin
include Msf::SessionEvent
include Msf::DatabaseEvent
def initialize(framework, opts)
super
@bin = opts[:bin] || opts['bin'] || `which notify-send`.chomp
@bin_opts = opts[:opts] || opts['opts'] || '-a Metasploit'
raise 'libnotify not found' if @bin.empty?
self.framework.events.add_session_subscriber(self)
self.framework.events.add_db_subscriber(self)
end
def notify_send(urgency, title, message)
system("#{@bin} #{@bin_opts} -u #{urgency} '#{title}' '#{message}'")
end
def on_session_open(session)
notify_send('normal', 'Got Shell!',
"New Session: #{session.sid}\nIP: #{session.session_host}\nPeer: #{session.tunnel_peer}\n"\
"Platform: #{session.platform}\nType: #{session.type}")
end
def on_session_close(session, reason='')
notify_send('normal', 'Connection closed',
"Session:#{session.sid} Type:#{session.type} closed.\n#{reason}")
end
def on_session_fail(reason='')
notify_send('critical', 'Session Failure!', reason)
end
def on_db_host(host)
notify_send('normal', 'New host',
"Addess: #{host.address}\nOS: #{host.os_name}")
end
def on_db_host_state(host, ostate)
notify_send('normal', "Host #{host.address} changed",
"OS: #{host.os_name}\nNb Services: #{host.service_count}\nNb vulns: #{host.vuln_count}\n")
end
def on_db_service(service)
notify_send('normal', 'New service',
"New service: #{service.host.address}:#{service.port}")
end
def on_db_service_state(service, port, ostate)
notify_send('normal', "Service #{service.host.address}:#{service.port} changed",
"Name: #{service.name}\nState: #{service.state}\nProto: #{service.proto}\nInfo: #{service.info}")
end
def on_db_vuln(vuln)
notify_send('critical', "New vulnerability on #{vuln.host.address}:#{vuln.service ? vuln.service.port : '0'}",
"Vuln: #{vuln.name}\nInfos: #{vuln.info}")
end
def on_db_ref(ref)
notify_send('normal', 'New ref', "Reference #{ref.name} added in database.")
end
def on_db_client(client)
notify_send('critical', 'New client', "New client connected: #{client.ua_string}")
end
def cleanup
self.framework.events.remove_session_subscriber(self)
self.framework.events.remove_db_subscriber(self)
end
def name
'libnotify'
end
def desc
'Send desktop notification with libnotify on sessions & db events'
end
end
end