diff --git a/lib/msf/core/db_manager/client.rb b/lib/msf/core/db_manager/client.rb index 10793e1c54..f1b4eb5845 100644 --- a/lib/msf/core/db_manager/client.rb +++ b/lib/msf/core/db_manager/client.rb @@ -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 diff --git a/lib/msf/core/db_manager/host.rb b/lib/msf/core/db_manager/host.rb index f9af660efb..fe59b6633e 100644 --- a/lib/msf/core/db_manager/host.rb +++ b/lib/msf/core/db_manager/host.rb @@ -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 } diff --git a/lib/msf/core/db_manager/ref.rb b/lib/msf/core/db_manager/ref.rb index ff6087d086..232c47b9ab 100644 --- a/lib/msf/core/db_manager/ref.rb +++ b/lib/msf/core/db_manager/ref.rb @@ -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 diff --git a/lib/msf/core/db_manager/service.rb b/lib/msf/core/db_manager/service.rb index b829defb18..9fdc26e7f7 100644 --- a/lib/msf/core/db_manager/service.rb +++ b/lib/msf/core/db_manager/service.rb @@ -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! diff --git a/lib/msf/core/db_manager/vuln.rb b/lib/msf/core/db_manager/vuln.rb index 9eb549fca6..b50bbd77b4 100644 --- a/lib/msf/core/db_manager/vuln.rb +++ b/lib/msf/core/db_manager/vuln.rb @@ -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 diff --git a/plugins/libnotify.rb b/plugins/libnotify.rb new file mode 100644 index 0000000000..85168df162 --- /dev/null +++ b/plugins/libnotify.rb @@ -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