From 5e61750c89a5f42b4415be1a2bb0cb564333ac09 Mon Sep 17 00:00:00 2001 From: cn-kali-team Date: Mon, 8 Jun 2020 15:24:04 +0800 Subject: [PATCH 1/8] add Session notified to DingTalk --- plugins/session_notifier.rb | 188 ++++++++++++++++++++++-------------- 1 file changed, 114 insertions(+), 74 deletions(-) diff --git a/plugins/session_notifier.rb b/plugins/session_notifier.rb index 63977fe0d0..7cf3ab7b84 100644 --- a/plugins/session_notifier.rb +++ b/plugins/session_notifier.rb @@ -1,9 +1,12 @@ +require 'net/https' +require 'net/http' +require 'uri' module Msf class Plugin::SessionNotifier < Msf::Plugin include Msf::SessionEvent - class Exception < ::RuntimeError ; end + class Exception < ::RuntimeError; end class SessionNotifierCommandDispatcher @@ -19,6 +22,7 @@ module Msf attr_reader :smtp_from attr_reader :minimum_ip attr_reader :maximum_ip + attr_reader :dingtalk_webhook def name 'SessionNotifier' @@ -26,19 +30,20 @@ module Msf def commands { - 'set_session_smtp_address' => 'Set the SMTP address for the session notifier', - 'set_session_smtp_port' => 'Set the SMTP port for the session notifier', - 'set_session_smtp_username' => 'Set the SMTP username', - 'set_session_smtp_password' => 'Set the SMTP password', - 'set_session_smtp_from' => 'Set the from field of SMTP', - 'set_session_mobile_number' => 'Set the 10-digit mobile number you want to notify', - 'set_session_mobile_carrier' => 'Set the mobile carrier of the phone', - 'set_session_minimum_ip' => 'Set the minimum session IP range you want to be notified for', - 'set_session_maximum_ip' => 'Set the maximum session IP range you want to be notified for', + 'set_session_smtp_address' => 'Set the SMTP address for the session notifier', + 'set_session_smtp_port' => 'Set the SMTP port for the session notifier', + 'set_session_smtp_username' => 'Set the SMTP username', + 'set_session_smtp_password' => 'Set the SMTP password', + 'set_session_smtp_from' => 'Set the from field of SMTP', + 'set_session_mobile_number' => 'Set the 10-digit mobile number you want to notify', + 'set_session_mobile_carrier' => 'Set the mobile carrier of the phone', + 'set_session_minimum_ip' => 'Set the minimum session IP range you want to be notified for', + 'set_session_maximum_ip' => 'Set the maximum session IP range you want to be notified for', + 'set_session_dingtalk_webhook' => 'Set the DingTalk webhook for the session notifier', 'save_session_notifier_settings' => 'Save all the session notifier settings to framework', - 'start_session_notifier' => 'Start notifying sessions', - 'stop_session_notifier' => 'Stop notifying sessions', - 'restart_session_notifier' => 'Restart notifying sessions' + 'start_session_notifier' => 'Start notifying sessions', + 'stop_session_notifier' => 'Stop notifying sessions', + 'restart_session_notifier' => 'Restart notifying sessions' } end @@ -107,38 +112,52 @@ module Msf end end - def cmd_save_session_notifier_settings(*args) - save_settings_to_config - print_status("Session Notifier settings saved in config file.") + def cmd_set_session_dingtalk_webhook(*args) + webhook_url = args[0] + if webhook_url.blank? + @dingtalk_webhook = nil + elsif !(webhook_url =~ URI::DEFAULT_PARSER.make_regexp).nil? + @dingtalk_webhook = webhook_url + else + print_error('Invalid webhook_url') + end end - def cmd_start_session_notifier(*args) - if is_session_notifier_subscribed? + def cmd_save_session_notifier_settings(*_args) + save_settings_to_config + print_status('Session Notifier settings saved in config file.') + end + + def cmd_start_session_notifier(*_args) + if session_notifier_subscribed? print_status('You already have an active session notifier.') return end begin - validate_settings! - self.framework.events.add_session_subscriber(self) - smtp = Rex::Proto::Sms::Model::Smtp.new( - address: self.smtp_address, - port: self.smtp_port, - username: self.smtp_username, - password: self.smtp_password, - login_type: :login, - from: self.smtp_from - ) - @sms_client = Rex::Proto::Sms::Client.new(carrier: self.sms_carrier, smtp_server: smtp) - print_status("Session notification started.") + framework.events.add_session_subscriber(self) + if validate_sms_settings? + smtp = Rex::Proto::Sms::Model::Smtp.new( + address: smtp_address, + port: smtp_port, + username: smtp_username, + password: smtp_password, + login_type: :login, + from: smtp_from + ) + @sms_client = Rex::Proto::Sms::Client.new(carrier: sms_carrier, smtp_server: smtp) + print_status('Session notification started.') + elsif !dingtalk_webhook.nil? + print_status('DingTalk notification started.') + end rescue Msf::Plugin::SessionNotifier::Exception, Rex::Proto::Sms::Exception => e print_error(e.message) end end - def cmd_stop_session_notifier(*args) - self.framework.events.remove_session_subscriber(self) - print_status("Session notification stopped.") + def cmd_stop_session_notifier(*_args) + framework.events.remove_session_subscriber(self) + print_status('Session notification stopped.') end def cmd_restart_session_notifier(*args) @@ -148,7 +167,7 @@ module Msf def on_session_open(session) subject = "You have a new #{session.type} session!" - msg = "#{session.tunnel_peer} (#{session.session_host}) #{session.info ? "\"#{session.info.to_s}\"" : nil}" + msg = "#{session.tunnel_peer} (#{session.session_host}) #{session.info ? "\"#{session.info}\"" : nil}" notify_session(session, subject, msg) end @@ -158,15 +177,16 @@ module Msf config_file = Msf::Config.config_file ini = Rex::Parser::Ini.new(config_file) ini.add_group(name) unless ini[name] - ini[name]['smtp_address'] = self.smtp_address - ini[name]['smtp_port'] = self.smtp_port - ini[name]['smtp_username'] = self.smtp_username - ini[name]['smtp_password'] = self.smtp_password - ini[name]['smtp_from'] = self.smtp_from - ini[name]['sms_number'] = self.sms_number - ini[name]['sms_carrier'] = self.sms_carrier - ini[name]['minimum_ip'] = self.minimum_ip.to_s unless self.minimum_ip.blank? - ini[name]['maximum_ip'] = self.maximum_ip.to_s unless self.maximum_ip.blank? + ini[name]['smtp_address'] = smtp_address + ini[name]['smtp_port'] = smtp_port + ini[name]['smtp_username'] = smtp_username + ini[name]['smtp_password'] = smtp_password + ini[name]['smtp_from'] = smtp_from + ini[name]['sms_number'] = sms_number + ini[name]['sms_carrier'] = sms_carrier + ini[name]['minimum_ip'] = minimum_ip.to_s unless minimum_ip.blank? + ini[name]['maximum_ip'] = maximum_ip.to_s unless maximum_ip.blank? + ini[name]['dingtalk_webhook'] = dingtalk_webhook.to_s unless dingtalk_webhook.blank? ini.to_file(config_file) end @@ -175,57 +195,81 @@ module Msf ini = Rex::Parser::Ini.new(config_file) group = ini[name] if group - @sms_carrier = group['sms_carrier'].to_sym if group['sms_carrier'] - @sms_number = group['sms_number'] if group['sms_number'] - @smtp_address = group['smtp_address'] if group['smtp_address'] - @smtp_port = group['smtp_port'] if group['smtp_port'] - @smtp_username = group['smtp_username'] if group['smtp_username'] - @smtp_password = group['smtp_password'] if group['smtp_password'] - @smtp_from = group['smtp_from'] if group['smtp_from'] - @minimum_ip = IPAddr.new(group['minimum_ip']) if group['minimum_ip'] - @maximum_ip = IPAddr.new(group['maximum_ip']) if group['maximum_ip'] + @sms_carrier = group['sms_carrier'].to_sym if group['sms_carrier'] + @sms_number = group['sms_number'] if group['sms_number'] + @smtp_address = group['smtp_address'] if group['smtp_address'] + @smtp_port = group['smtp_port'] if group['smtp_port'] + @smtp_username = group['smtp_username'] if group['smtp_username'] + @smtp_password = group['smtp_password'] if group['smtp_password'] + @smtp_from = group['smtp_from'] if group['smtp_from'] + @minimum_ip = IPAddr.new(group['minimum_ip']) if group['minimum_ip'] + @maximum_ip = IPAddr.new(group['maximum_ip']) if group['maximum_ip'] + @dingtalk_webhook = group['dingtalk_webhook'] if group['dingtalk_webhook'] print_status('Session Notifier settings loaded from config file.') end end - def is_session_notifier_subscribed? - subscribers = framework.events.instance_variable_get(:@session_event_subscribers).collect { |s| s.class } + def session_notifier_subscribed? + subscribers = framework.events.instance_variable_get(:@session_event_subscribers).collect(&:class) subscribers.include?(self.class) end + def send_text_to_dingtalk(session) + # https://ding-doc.dingtalk.com/doc#/serverapi2/qf2nxq/9e91d73c + uri_parser = URI.parse(dingtalk_webhook) + markdown_text = "## You have a new #{session.type} session!\n\n" \ + "**platform** : #{session.platform}\n\n" \ + "**tunnel** : #{session.tunnel_to_s}\n\n" \ + "**arch** : #{session.arch}\n\n" \ + "**info** : > #{session.info ? session.info.to_s : nil}" + json_post_data = JSON.pretty_generate({ + msgtype: 'markdown', + markdown: { title: 'Session Notifier', text: markdown_text } + }) + http = Net::HTTP.new(uri_parser.host, uri_parser.port) + http.use_ssl = true + request = Net::HTTP::Post.new(uri_parser.request_uri) + request.content_type = 'application/json' + request.body = json_post_data + res = http.request(request) + body = JSON.parse(res.body) + print_status((body['errcode'] == 0) ? 'Session notified to DingTalk.' : 'Failed to send notification.') + end + def notify_session(session, subject, msg) - if is_in_range?(session) - @sms_client.send_text_to_phones([self.sms_number], subject, msg) - print_status("Session notified to: #{self.sms_number}") + if in_range?(session) && validate_sms_settings? + @sms_client.send_text_to_phones([sms_number], subject, msg) + print_status("Session notified to: #{sms_number}") + end + if in_range?(session) && !dingtalk_webhook.nil? + send_text_to_dingtalk(session) end end - def is_in_range?(session) + def in_range?(session) # If both blank, it means we're not setting a range. - return true if self.minimum_ip.blank? && self.maximum_ip.blank? + return true if minimum_ip.blank? && maximum_ip.blank? ip = IPAddr.new(session.session_host) - if self.minimum_ip && !self.maximum_ip + if minimum_ip && !maximum_ip # There is only a minimum IP - self.minimum_ip < ip - elsif !self.minimum_ip && self.maximum_ip + minimum_ip < ip + elsif !minimum_ip && maximum_ip # There is only a max IP - self.maximum_ip > ip + maximum_ip > ip else # Both ends are set - range = self.minimum_ip..self.maximum_ip + range = minimum_ip..maximum_ip range.include?(ip) end end - def validate_settings! - if self.smtp_address.nil? || self.smtp_port.nil? || - self.smtp_username.nil? || self.smtp_password.nil? || - self.smtp_from.nil? - raise Msf::Plugin::SessionNotifier::Exception, "All Session Notifier's settings must be configured." - end + def validate_sms_settings? + !(smtp_address.nil? || smtp_port.nil? || + smtp_username.nil? || smtp_password.nil? || + smtp_from.nil?) end end @@ -243,10 +287,6 @@ module Msf remove_console_dispatcher(name) end - def name - 'SessionNotifier' - end - def desc 'This plugin notifies you a new session via SMS.' end From 6a0e4110d8eaad92045890ecc66582854aa6ec9a Mon Sep 17 00:00:00 2001 From: cn-kali-team Date: Mon, 8 Jun 2020 17:56:29 +0800 Subject: [PATCH 2/8] Original code style --- plugins/session_notifier.rb | 62 ++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/plugins/session_notifier.rb b/plugins/session_notifier.rb index 7cf3ab7b84..4588327fd0 100644 --- a/plugins/session_notifier.rb +++ b/plugins/session_notifier.rb @@ -30,20 +30,20 @@ module Msf def commands { - 'set_session_smtp_address' => 'Set the SMTP address for the session notifier', - 'set_session_smtp_port' => 'Set the SMTP port for the session notifier', - 'set_session_smtp_username' => 'Set the SMTP username', - 'set_session_smtp_password' => 'Set the SMTP password', - 'set_session_smtp_from' => 'Set the from field of SMTP', - 'set_session_mobile_number' => 'Set the 10-digit mobile number you want to notify', - 'set_session_mobile_carrier' => 'Set the mobile carrier of the phone', - 'set_session_minimum_ip' => 'Set the minimum session IP range you want to be notified for', - 'set_session_maximum_ip' => 'Set the maximum session IP range you want to be notified for', - 'set_session_dingtalk_webhook' => 'Set the DingTalk webhook for the session notifier', + 'set_session_smtp_address' => 'Set the SMTP address for the session notifier', + 'set_session_smtp_port' => 'Set the SMTP port for the session notifier', + 'set_session_smtp_username' => 'Set the SMTP username', + 'set_session_smtp_password' => 'Set the SMTP password', + 'set_session_smtp_from' => 'Set the from field of SMTP', + 'set_session_mobile_number' => 'Set the 10-digit mobile number you want to notify', + 'set_session_mobile_carrier' => 'Set the mobile carrier of the phone', + 'set_session_minimum_ip' => 'Set the minimum session IP range you want to be notified for', + 'set_session_maximum_ip' => 'Set the maximum session IP range you want to be notified for', + 'set_session_dingtalk_webhook' => 'Set the DingTalk webhook for the session notifier', 'save_session_notifier_settings' => 'Save all the session notifier settings to framework', - 'start_session_notifier' => 'Start notifying sessions', - 'stop_session_notifier' => 'Stop notifying sessions', - 'restart_session_notifier' => 'Restart notifying sessions' + 'start_session_notifier' => 'Start notifying sessions', + 'stop_session_notifier' => 'Stop notifying sessions', + 'restart_session_notifier' => 'Restart notifying sessions' } end @@ -177,15 +177,15 @@ module Msf config_file = Msf::Config.config_file ini = Rex::Parser::Ini.new(config_file) ini.add_group(name) unless ini[name] - ini[name]['smtp_address'] = smtp_address - ini[name]['smtp_port'] = smtp_port - ini[name]['smtp_username'] = smtp_username - ini[name]['smtp_password'] = smtp_password - ini[name]['smtp_from'] = smtp_from - ini[name]['sms_number'] = sms_number - ini[name]['sms_carrier'] = sms_carrier - ini[name]['minimum_ip'] = minimum_ip.to_s unless minimum_ip.blank? - ini[name]['maximum_ip'] = maximum_ip.to_s unless maximum_ip.blank? + ini[name]['smtp_address'] = smtp_address + ini[name]['smtp_port'] = smtp_port + ini[name]['smtp_username'] = smtp_username + ini[name]['smtp_password'] = smtp_password + ini[name]['smtp_from'] = smtp_from + ini[name]['sms_number'] = sms_number + ini[name]['sms_carrier'] = sms_carrier + ini[name]['minimum_ip'] = minimum_ip.to_s unless minimum_ip.blank? + ini[name]['maximum_ip'] = maximum_ip.to_s unless maximum_ip.blank? ini[name]['dingtalk_webhook'] = dingtalk_webhook.to_s unless dingtalk_webhook.blank? ini.to_file(config_file) end @@ -195,15 +195,15 @@ module Msf ini = Rex::Parser::Ini.new(config_file) group = ini[name] if group - @sms_carrier = group['sms_carrier'].to_sym if group['sms_carrier'] - @sms_number = group['sms_number'] if group['sms_number'] - @smtp_address = group['smtp_address'] if group['smtp_address'] - @smtp_port = group['smtp_port'] if group['smtp_port'] - @smtp_username = group['smtp_username'] if group['smtp_username'] - @smtp_password = group['smtp_password'] if group['smtp_password'] - @smtp_from = group['smtp_from'] if group['smtp_from'] - @minimum_ip = IPAddr.new(group['minimum_ip']) if group['minimum_ip'] - @maximum_ip = IPAddr.new(group['maximum_ip']) if group['maximum_ip'] + @sms_carrier = group['sms_carrier'].to_sym if group['sms_carrier'] + @sms_number = group['sms_number'] if group['sms_number'] + @smtp_address = group['smtp_address'] if group['smtp_address'] + @smtp_port = group['smtp_port'] if group['smtp_port'] + @smtp_username = group['smtp_username'] if group['smtp_username'] + @smtp_password = group['smtp_password'] if group['smtp_password'] + @smtp_from = group['smtp_from'] if group['smtp_from'] + @minimum_ip = IPAddr.new(group['minimum_ip']) if group['minimum_ip'] + @maximum_ip = IPAddr.new(group['maximum_ip']) if group['maximum_ip'] @dingtalk_webhook = group['dingtalk_webhook'] if group['dingtalk_webhook'] print_status('Session Notifier settings loaded from config file.') From 32c3dd5071b304e1bb063c2c5ab55796c717dae4 Mon Sep 17 00:00:00 2001 From: cn-kali-team Date: Mon, 8 Jun 2020 18:00:46 +0800 Subject: [PATCH 3/8] Original code style --- plugins/session_notifier.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/plugins/session_notifier.rb b/plugins/session_notifier.rb index 4588327fd0..c074f528dc 100644 --- a/plugins/session_notifier.rb +++ b/plugins/session_notifier.rb @@ -195,16 +195,16 @@ module Msf ini = Rex::Parser::Ini.new(config_file) group = ini[name] if group - @sms_carrier = group['sms_carrier'].to_sym if group['sms_carrier'] - @sms_number = group['sms_number'] if group['sms_number'] - @smtp_address = group['smtp_address'] if group['smtp_address'] - @smtp_port = group['smtp_port'] if group['smtp_port'] - @smtp_username = group['smtp_username'] if group['smtp_username'] - @smtp_password = group['smtp_password'] if group['smtp_password'] - @smtp_from = group['smtp_from'] if group['smtp_from'] + @sms_carrier = group['sms_carrier'].to_sym if group['sms_carrier'] + @sms_number = group['sms_number'] if group['sms_number'] + @smtp_address = group['smtp_address'] if group['smtp_address'] + @smtp_port = group['smtp_port'] if group['smtp_port'] + @smtp_username = group['smtp_username'] if group['smtp_username'] + @smtp_password = group['smtp_password'] if group['smtp_password'] + @smtp_from = group['smtp_from'] if group['smtp_from'] @minimum_ip = IPAddr.new(group['minimum_ip']) if group['minimum_ip'] @maximum_ip = IPAddr.new(group['maximum_ip']) if group['maximum_ip'] - @dingtalk_webhook = group['dingtalk_webhook'] if group['dingtalk_webhook'] + @dingtalk_webhook = group['dingtalk_webhook'] if group['dingtalk_webhook'] print_status('Session Notifier settings loaded from config file.') end From 55c4dcd751b7817ef64ac6362587b9621813038a Mon Sep 17 00:00:00 2001 From: cn-kali-team Date: Wed, 17 Jun 2020 20:52:23 +0800 Subject: [PATCH 4/8] add keyword to help --- plugins/session_notifier.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/session_notifier.rb b/plugins/session_notifier.rb index c074f528dc..d6794ec8ad 100644 --- a/plugins/session_notifier.rb +++ b/plugins/session_notifier.rb @@ -39,7 +39,7 @@ module Msf 'set_session_mobile_carrier' => 'Set the mobile carrier of the phone', 'set_session_minimum_ip' => 'Set the minimum session IP range you want to be notified for', 'set_session_maximum_ip' => 'Set the maximum session IP range you want to be notified for', - 'set_session_dingtalk_webhook' => 'Set the DingTalk webhook for the session notifier', + 'set_session_dingtalk_webhook' => 'Set the DingTalk webhook for the session notifier (keyword: session).', 'save_session_notifier_settings' => 'Save all the session notifier settings to framework', 'start_session_notifier' => 'Start notifying sessions', 'stop_session_notifier' => 'Stop notifying sessions', From 7f63a5be06d5a584c81ec07aeeaa70546a2dcd36 Mon Sep 17 00:00:00 2001 From: cn-kali-team Date: Sat, 8 Aug 2020 22:08:02 +0800 Subject: [PATCH 5/8] add dingtalk_notifier plugins --- plugins/dingtalk_notifier.rb | 199 +++++++++++++++++++++++++++++++++++ 1 file changed, 199 insertions(+) create mode 100644 plugins/dingtalk_notifier.rb diff --git a/plugins/dingtalk_notifier.rb b/plugins/dingtalk_notifier.rb new file mode 100644 index 0000000000..7d31631cee --- /dev/null +++ b/plugins/dingtalk_notifier.rb @@ -0,0 +1,199 @@ +require 'net/https' +require 'net/http' +require 'uri' +module Msf + class Plugin::DingtalkNotifier < Msf::Plugin + + include Msf::SessionEvent + + class Exception < ::RuntimeError; end + + class DingtalkNotifierCommandDispatcher + + include Msf::Ui::Console::CommandDispatcher + attr_reader :dingtalk_webhook + attr_reader :minimum_ip_webhook + attr_reader :maximum_ip_webhook + + def name + 'DingtalkNotifier' + end + + def commands + { + 'set_dingtalk_minimum_ip' => 'Set the minimum session IP range you want to be notified for', + 'set_dingtalk_maximum_ip' => 'Set the maximum session IP range you want to be notified for', + 'set_dingtalk_webhook' => 'Set the DingTalk webhook for the session notifier (keyword: session).', + 'save_dingtalk_notifier_settings' => 'Save all the session notifier settings to framework', + 'start_dingtalk_notifier' => 'Start notifying dingtalk', + 'stop_dingtalk_notifier' => 'Stop notifying dingtalk', + 'restart_dingtalk_notifier' => 'Restart notifying dingtalk' + } + end + + def initialize(driver) + super(driver) + load_settings_from_config + end + + def cmd_set_dingtalk_minimum_ip(*args) + ip = args[0] + if ip.blank? + @minimum_ip_webhook = nil + elsif Rex::Socket.dotted_ip?(ip) + @minimum_ip_webhook = IPAddr.new(ip) + else + print_error('Invalid IP format') + end + end + + def cmd_set_dingtalk_maximum_ip(*args) + ip = args[0] + if ip.blank? + @maximum_ip_webhook = nil + elsif Rex::Socket.self.dotted_ip?(ip) + @maximum_ip_webhook = IPAddr.new(ip) + else + print_error('Invalid IP format') + end + end + + def cmd_set_dingtalk_webhook(*args) + webhook_url = args[0] + if webhook_url.blank? + @dingtalk_webhook = nil + elsif !(webhook_url =~ URI::DEFAULT_PARSER.make_regexp).nil? + @dingtalk_webhook = webhook_url + else + print_error('Invalid webhook_url') + end + end + + def cmd_save_dingtalk_notifier_settings(*_args) + save_settings_to_config + print_status('Dingtalk Notifier settings saved in config file.') + end + + def cmd_start_dingtalk_notifier(*_args) + if session_notifier_subscribed? + print_status('You already have an active dingtalk notifier.') + return + end + + begin + framework.events.add_session_subscriber(self) + if !dingtalk_webhook.nil? + print_status('DingTalk notification started.') + end + rescue Msf::Plugin::DingtalkNotifier::Exception => e + print_error(e.message) + end + end + + def cmd_stop_dingtalk_notifier(*_args) + framework.events.remove_session_subscriber(self) + print_status('DingTalk notification stopped.') + end + + def cmd_restart_dingtalk_notifier(*args) + cmd_stop_dingtalk_notifier(args) + cmd_start_dingtalk_notifier(args) + end + + def on_session_open(session) + notify_session(session) + end + + private + + def save_settings_to_config + config_file = Msf::Config.config_file + ini = Rex::Parser::Ini.new(config_file) + ini.add_group(name) unless ini[name] + ini[name]['dingtalk_webhook'] = dingtalk_webhook.to_s unless dingtalk_webhook.blank? + ini.to_file(config_file) + end + + def load_settings_from_config + config_file = Msf::Config.config_file + ini = Rex::Parser::Ini.new(config_file) + group = ini[name] + if group + @dingtalk_webhook = group['dingtalk_webhook'] if group['dingtalk_webhook'] + print_status('Session Notifier settings loaded from config file.') + end + end + + def session_notifier_subscribed? + subscribers = framework.events.instance_variable_get(:@session_event_subscribers).collect(&:class) + subscribers.include?(self.class) + end + + def send_text_to_dingtalk(session) + # https://ding-doc.dingtalk.com/doc#/serverapi2/qf2nxq/9e91d73c + uri_parser = URI.parse(dingtalk_webhook) + markdown_text = "## You have a new #{session.type} session!\n\n" \ + "**platform** : #{session.platform}\n\n" \ + "**tunnel** : #{session.tunnel_to_s}\n\n" \ + "**arch** : #{session.arch}\n\n" \ + "**info** : > #{session.info ? session.info.to_s : nil}" + json_post_data = JSON.pretty_generate({ + msgtype: 'markdown', + markdown: { title: 'Session Notifier', text: markdown_text } + }) + http = Net::HTTP.new(uri_parser.host, uri_parser.port) + http.use_ssl = true + request = Net::HTTP::Post.new(uri_parser.request_uri) + request.content_type = 'application/json' + request.body = json_post_data + res = http.request(request) + body = JSON.parse(res.body) + print_status((body['errcode'] == 0) ? 'Session notified to DingTalk.' : 'Failed to send notification.') + end + + def notify_session(session) + if in_range?(session) && !dingtalk_webhook.nil? + send_text_to_dingtalk(session) + end + end + + def in_range?(session) + # If both blank, it means we're not setting a range. + return true if minimum_ip_webhook.blank? && maximum_ip_webhook.blank? + + ip = IPAddr.new(session.session_host) + + if minimum_ip_webhook && !maximum_ip_webhook + # There is only a minimum IP + minimum_ip_webhook < ip + elsif !minimum_ip_webhook && maximum_ip_webhook + # There is only a max IP + maximum_ip_webhook > ip + else + # Both ends are set + range = minimum_ip_webhook..maximum_ip_webhook + range.include?(ip) + end + end + + end + + def name + 'DingtalkNotifier' + end + + def initialize(framework, opts) + super + add_console_dispatcher(DingtalkNotifierCommandDispatcher) + end + + def cleanup + remove_console_dispatcher(name) + end + + def desc + 'This plugin notifies you a new session via webhook.' + end + + end +end From 0a3d3074a5d3b0d5add743e19ca5d5c100d9bf44 Mon Sep 17 00:00:00 2001 From: cn-kali-team Date: Sat, 8 Aug 2020 22:08:20 +0800 Subject: [PATCH 6/8] remove dingtalk code --- plugins/session_notifier.rb | 164 ++++++++++++++---------------------- 1 file changed, 62 insertions(+), 102 deletions(-) diff --git a/plugins/session_notifier.rb b/plugins/session_notifier.rb index d6794ec8ad..8cbce4c611 100644 --- a/plugins/session_notifier.rb +++ b/plugins/session_notifier.rb @@ -1,12 +1,9 @@ -require 'net/https' -require 'net/http' -require 'uri' module Msf class Plugin::SessionNotifier < Msf::Plugin include Msf::SessionEvent - class Exception < ::RuntimeError; end + class Exception < ::RuntimeError ; end class SessionNotifierCommandDispatcher @@ -22,7 +19,6 @@ module Msf attr_reader :smtp_from attr_reader :minimum_ip attr_reader :maximum_ip - attr_reader :dingtalk_webhook def name 'SessionNotifier' @@ -39,7 +35,6 @@ module Msf 'set_session_mobile_carrier' => 'Set the mobile carrier of the phone', 'set_session_minimum_ip' => 'Set the minimum session IP range you want to be notified for', 'set_session_maximum_ip' => 'Set the maximum session IP range you want to be notified for', - 'set_session_dingtalk_webhook' => 'Set the DingTalk webhook for the session notifier (keyword: session).', 'save_session_notifier_settings' => 'Save all the session notifier settings to framework', 'start_session_notifier' => 'Start notifying sessions', 'stop_session_notifier' => 'Stop notifying sessions', @@ -112,52 +107,38 @@ module Msf end end - def cmd_set_session_dingtalk_webhook(*args) - webhook_url = args[0] - if webhook_url.blank? - @dingtalk_webhook = nil - elsif !(webhook_url =~ URI::DEFAULT_PARSER.make_regexp).nil? - @dingtalk_webhook = webhook_url - else - print_error('Invalid webhook_url') - end - end - - def cmd_save_session_notifier_settings(*_args) + def cmd_save_session_notifier_settings(*args) save_settings_to_config - print_status('Session Notifier settings saved in config file.') + print_status("Session Notifier settings saved in config file.") end - def cmd_start_session_notifier(*_args) - if session_notifier_subscribed? + def cmd_start_session_notifier(*args) + if is_session_notifier_subscribed? print_status('You already have an active session notifier.') return end begin - framework.events.add_session_subscriber(self) - if validate_sms_settings? - smtp = Rex::Proto::Sms::Model::Smtp.new( - address: smtp_address, - port: smtp_port, - username: smtp_username, - password: smtp_password, - login_type: :login, - from: smtp_from - ) - @sms_client = Rex::Proto::Sms::Client.new(carrier: sms_carrier, smtp_server: smtp) - print_status('Session notification started.') - elsif !dingtalk_webhook.nil? - print_status('DingTalk notification started.') - end + validate_settings! + self.framework.events.add_session_subscriber(self) + smtp = Rex::Proto::Sms::Model::Smtp.new( + address: self.smtp_address, + port: self.smtp_port, + username: self.smtp_username, + password: self.smtp_password, + login_type: :login, + from: self.smtp_from + ) + @sms_client = Rex::Proto::Sms::Client.new(carrier: self.sms_carrier, smtp_server: smtp) + print_status("Session notification started.") rescue Msf::Plugin::SessionNotifier::Exception, Rex::Proto::Sms::Exception => e print_error(e.message) end end - def cmd_stop_session_notifier(*_args) - framework.events.remove_session_subscriber(self) - print_status('Session notification stopped.') + def cmd_stop_session_notifier(*args) + self.framework.events.remove_session_subscriber(self) + print_status("Session notification stopped.") end def cmd_restart_session_notifier(*args) @@ -167,7 +148,7 @@ module Msf def on_session_open(session) subject = "You have a new #{session.type} session!" - msg = "#{session.tunnel_peer} (#{session.session_host}) #{session.info ? "\"#{session.info}\"" : nil}" + msg = "#{session.tunnel_peer} (#{session.session_host}) #{session.info ? "\"#{session.info.to_s}\"" : nil}" notify_session(session, subject, msg) end @@ -177,16 +158,15 @@ module Msf config_file = Msf::Config.config_file ini = Rex::Parser::Ini.new(config_file) ini.add_group(name) unless ini[name] - ini[name]['smtp_address'] = smtp_address - ini[name]['smtp_port'] = smtp_port - ini[name]['smtp_username'] = smtp_username - ini[name]['smtp_password'] = smtp_password - ini[name]['smtp_from'] = smtp_from - ini[name]['sms_number'] = sms_number - ini[name]['sms_carrier'] = sms_carrier - ini[name]['minimum_ip'] = minimum_ip.to_s unless minimum_ip.blank? - ini[name]['maximum_ip'] = maximum_ip.to_s unless maximum_ip.blank? - ini[name]['dingtalk_webhook'] = dingtalk_webhook.to_s unless dingtalk_webhook.blank? + ini[name]['smtp_address'] = self.smtp_address + ini[name]['smtp_port'] = self.smtp_port + ini[name]['smtp_username'] = self.smtp_username + ini[name]['smtp_password'] = self.smtp_password + ini[name]['smtp_from'] = self.smtp_from + ini[name]['sms_number'] = self.sms_number + ini[name]['sms_carrier'] = self.sms_carrier + ini[name]['minimum_ip'] = self.minimum_ip.to_s unless self.minimum_ip.blank? + ini[name]['maximum_ip'] = self.maximum_ip.to_s unless self.maximum_ip.blank? ini.to_file(config_file) end @@ -195,81 +175,57 @@ module Msf ini = Rex::Parser::Ini.new(config_file) group = ini[name] if group - @sms_carrier = group['sms_carrier'].to_sym if group['sms_carrier'] - @sms_number = group['sms_number'] if group['sms_number'] - @smtp_address = group['smtp_address'] if group['smtp_address'] - @smtp_port = group['smtp_port'] if group['smtp_port'] - @smtp_username = group['smtp_username'] if group['smtp_username'] - @smtp_password = group['smtp_password'] if group['smtp_password'] - @smtp_from = group['smtp_from'] if group['smtp_from'] - @minimum_ip = IPAddr.new(group['minimum_ip']) if group['minimum_ip'] - @maximum_ip = IPAddr.new(group['maximum_ip']) if group['maximum_ip'] - @dingtalk_webhook = group['dingtalk_webhook'] if group['dingtalk_webhook'] + @sms_carrier = group['sms_carrier'].to_sym if group['sms_carrier'] + @sms_number = group['sms_number'] if group['sms_number'] + @smtp_address = group['smtp_address'] if group['smtp_address'] + @smtp_port = group['smtp_port'] if group['smtp_port'] + @smtp_username = group['smtp_username'] if group['smtp_username'] + @smtp_password = group['smtp_password'] if group['smtp_password'] + @smtp_from = group['smtp_from'] if group['smtp_from'] + @minimum_ip = IPAddr.new(group['minimum_ip']) if group['minimum_ip'] + @maximum_ip = IPAddr.new(group['maximum_ip']) if group['maximum_ip'] print_status('Session Notifier settings loaded from config file.') end end - def session_notifier_subscribed? - subscribers = framework.events.instance_variable_get(:@session_event_subscribers).collect(&:class) + def is_session_notifier_subscribed? + subscribers = framework.events.instance_variable_get(:@session_event_subscribers).collect { |s| s.class } subscribers.include?(self.class) end - def send_text_to_dingtalk(session) - # https://ding-doc.dingtalk.com/doc#/serverapi2/qf2nxq/9e91d73c - uri_parser = URI.parse(dingtalk_webhook) - markdown_text = "## You have a new #{session.type} session!\n\n" \ - "**platform** : #{session.platform}\n\n" \ - "**tunnel** : #{session.tunnel_to_s}\n\n" \ - "**arch** : #{session.arch}\n\n" \ - "**info** : > #{session.info ? session.info.to_s : nil}" - json_post_data = JSON.pretty_generate({ - msgtype: 'markdown', - markdown: { title: 'Session Notifier', text: markdown_text } - }) - http = Net::HTTP.new(uri_parser.host, uri_parser.port) - http.use_ssl = true - request = Net::HTTP::Post.new(uri_parser.request_uri) - request.content_type = 'application/json' - request.body = json_post_data - res = http.request(request) - body = JSON.parse(res.body) - print_status((body['errcode'] == 0) ? 'Session notified to DingTalk.' : 'Failed to send notification.') - end - def notify_session(session, subject, msg) - if in_range?(session) && validate_sms_settings? - @sms_client.send_text_to_phones([sms_number], subject, msg) - print_status("Session notified to: #{sms_number}") - end - if in_range?(session) && !dingtalk_webhook.nil? - send_text_to_dingtalk(session) + if is_in_range?(session) + @sms_client.send_text_to_phones([self.sms_number], subject, msg) + print_status("Session notified to: #{self.sms_number}") end end - def in_range?(session) + def is_in_range?(session) # If both blank, it means we're not setting a range. - return true if minimum_ip.blank? && maximum_ip.blank? + return true if self.minimum_ip.blank? && self.maximum_ip.blank? ip = IPAddr.new(session.session_host) - if minimum_ip && !maximum_ip + if self.minimum_ip && !self.maximum_ip # There is only a minimum IP - minimum_ip < ip - elsif !minimum_ip && maximum_ip + self.minimum_ip < ip + elsif !self.minimum_ip && self.maximum_ip # There is only a max IP - maximum_ip > ip + self.maximum_ip > ip else # Both ends are set - range = minimum_ip..maximum_ip + range = self.minimum_ip..self.maximum_ip range.include?(ip) end end - def validate_sms_settings? - !(smtp_address.nil? || smtp_port.nil? || - smtp_username.nil? || smtp_password.nil? || - smtp_from.nil?) + def validate_settings! + if self.smtp_address.nil? || self.smtp_port.nil? || + self.smtp_username.nil? || self.smtp_password.nil? || + self.smtp_from.nil? + raise Msf::Plugin::SessionNotifier::Exception, "All Session Notifier's settings must be configured." + end end end @@ -287,9 +243,13 @@ module Msf remove_console_dispatcher(name) end + def name + 'SessionNotifier' + end + def desc 'This plugin notifies you a new session via SMS.' end end -end +end \ No newline at end of file From 736511f9303e6587727e94fefff23fc92c4a4d80 Mon Sep 17 00:00:00 2001 From: cn-kali-team Date: Tue, 25 Aug 2020 12:06:30 +0800 Subject: [PATCH 7/8] remove dingtalk_plugins --- plugins/dingtalk_notifier.rb | 199 ----------------------------------- 1 file changed, 199 deletions(-) delete mode 100644 plugins/dingtalk_notifier.rb diff --git a/plugins/dingtalk_notifier.rb b/plugins/dingtalk_notifier.rb deleted file mode 100644 index 7d31631cee..0000000000 --- a/plugins/dingtalk_notifier.rb +++ /dev/null @@ -1,199 +0,0 @@ -require 'net/https' -require 'net/http' -require 'uri' -module Msf - class Plugin::DingtalkNotifier < Msf::Plugin - - include Msf::SessionEvent - - class Exception < ::RuntimeError; end - - class DingtalkNotifierCommandDispatcher - - include Msf::Ui::Console::CommandDispatcher - attr_reader :dingtalk_webhook - attr_reader :minimum_ip_webhook - attr_reader :maximum_ip_webhook - - def name - 'DingtalkNotifier' - end - - def commands - { - 'set_dingtalk_minimum_ip' => 'Set the minimum session IP range you want to be notified for', - 'set_dingtalk_maximum_ip' => 'Set the maximum session IP range you want to be notified for', - 'set_dingtalk_webhook' => 'Set the DingTalk webhook for the session notifier (keyword: session).', - 'save_dingtalk_notifier_settings' => 'Save all the session notifier settings to framework', - 'start_dingtalk_notifier' => 'Start notifying dingtalk', - 'stop_dingtalk_notifier' => 'Stop notifying dingtalk', - 'restart_dingtalk_notifier' => 'Restart notifying dingtalk' - } - end - - def initialize(driver) - super(driver) - load_settings_from_config - end - - def cmd_set_dingtalk_minimum_ip(*args) - ip = args[0] - if ip.blank? - @minimum_ip_webhook = nil - elsif Rex::Socket.dotted_ip?(ip) - @minimum_ip_webhook = IPAddr.new(ip) - else - print_error('Invalid IP format') - end - end - - def cmd_set_dingtalk_maximum_ip(*args) - ip = args[0] - if ip.blank? - @maximum_ip_webhook = nil - elsif Rex::Socket.self.dotted_ip?(ip) - @maximum_ip_webhook = IPAddr.new(ip) - else - print_error('Invalid IP format') - end - end - - def cmd_set_dingtalk_webhook(*args) - webhook_url = args[0] - if webhook_url.blank? - @dingtalk_webhook = nil - elsif !(webhook_url =~ URI::DEFAULT_PARSER.make_regexp).nil? - @dingtalk_webhook = webhook_url - else - print_error('Invalid webhook_url') - end - end - - def cmd_save_dingtalk_notifier_settings(*_args) - save_settings_to_config - print_status('Dingtalk Notifier settings saved in config file.') - end - - def cmd_start_dingtalk_notifier(*_args) - if session_notifier_subscribed? - print_status('You already have an active dingtalk notifier.') - return - end - - begin - framework.events.add_session_subscriber(self) - if !dingtalk_webhook.nil? - print_status('DingTalk notification started.') - end - rescue Msf::Plugin::DingtalkNotifier::Exception => e - print_error(e.message) - end - end - - def cmd_stop_dingtalk_notifier(*_args) - framework.events.remove_session_subscriber(self) - print_status('DingTalk notification stopped.') - end - - def cmd_restart_dingtalk_notifier(*args) - cmd_stop_dingtalk_notifier(args) - cmd_start_dingtalk_notifier(args) - end - - def on_session_open(session) - notify_session(session) - end - - private - - def save_settings_to_config - config_file = Msf::Config.config_file - ini = Rex::Parser::Ini.new(config_file) - ini.add_group(name) unless ini[name] - ini[name]['dingtalk_webhook'] = dingtalk_webhook.to_s unless dingtalk_webhook.blank? - ini.to_file(config_file) - end - - def load_settings_from_config - config_file = Msf::Config.config_file - ini = Rex::Parser::Ini.new(config_file) - group = ini[name] - if group - @dingtalk_webhook = group['dingtalk_webhook'] if group['dingtalk_webhook'] - print_status('Session Notifier settings loaded from config file.') - end - end - - def session_notifier_subscribed? - subscribers = framework.events.instance_variable_get(:@session_event_subscribers).collect(&:class) - subscribers.include?(self.class) - end - - def send_text_to_dingtalk(session) - # https://ding-doc.dingtalk.com/doc#/serverapi2/qf2nxq/9e91d73c - uri_parser = URI.parse(dingtalk_webhook) - markdown_text = "## You have a new #{session.type} session!\n\n" \ - "**platform** : #{session.platform}\n\n" \ - "**tunnel** : #{session.tunnel_to_s}\n\n" \ - "**arch** : #{session.arch}\n\n" \ - "**info** : > #{session.info ? session.info.to_s : nil}" - json_post_data = JSON.pretty_generate({ - msgtype: 'markdown', - markdown: { title: 'Session Notifier', text: markdown_text } - }) - http = Net::HTTP.new(uri_parser.host, uri_parser.port) - http.use_ssl = true - request = Net::HTTP::Post.new(uri_parser.request_uri) - request.content_type = 'application/json' - request.body = json_post_data - res = http.request(request) - body = JSON.parse(res.body) - print_status((body['errcode'] == 0) ? 'Session notified to DingTalk.' : 'Failed to send notification.') - end - - def notify_session(session) - if in_range?(session) && !dingtalk_webhook.nil? - send_text_to_dingtalk(session) - end - end - - def in_range?(session) - # If both blank, it means we're not setting a range. - return true if minimum_ip_webhook.blank? && maximum_ip_webhook.blank? - - ip = IPAddr.new(session.session_host) - - if minimum_ip_webhook && !maximum_ip_webhook - # There is only a minimum IP - minimum_ip_webhook < ip - elsif !minimum_ip_webhook && maximum_ip_webhook - # There is only a max IP - maximum_ip_webhook > ip - else - # Both ends are set - range = minimum_ip_webhook..maximum_ip_webhook - range.include?(ip) - end - end - - end - - def name - 'DingtalkNotifier' - end - - def initialize(framework, opts) - super - add_console_dispatcher(DingtalkNotifierCommandDispatcher) - end - - def cleanup - remove_console_dispatcher(name) - end - - def desc - 'This plugin notifies you a new session via webhook.' - end - - end -end From f26133bef068211e0807de8ad53ad5c026db2552 Mon Sep 17 00:00:00 2001 From: cn-kali-team Date: Tue, 25 Aug 2020 12:06:57 +0800 Subject: [PATCH 8/8] add dingtalk's code --- plugins/session_notifier.rb | 166 ++++++++++++++++++++++-------------- 1 file changed, 103 insertions(+), 63 deletions(-) diff --git a/plugins/session_notifier.rb b/plugins/session_notifier.rb index 8cbce4c611..d6794ec8ad 100644 --- a/plugins/session_notifier.rb +++ b/plugins/session_notifier.rb @@ -1,9 +1,12 @@ +require 'net/https' +require 'net/http' +require 'uri' module Msf class Plugin::SessionNotifier < Msf::Plugin include Msf::SessionEvent - class Exception < ::RuntimeError ; end + class Exception < ::RuntimeError; end class SessionNotifierCommandDispatcher @@ -19,6 +22,7 @@ module Msf attr_reader :smtp_from attr_reader :minimum_ip attr_reader :maximum_ip + attr_reader :dingtalk_webhook def name 'SessionNotifier' @@ -35,6 +39,7 @@ module Msf 'set_session_mobile_carrier' => 'Set the mobile carrier of the phone', 'set_session_minimum_ip' => 'Set the minimum session IP range you want to be notified for', 'set_session_maximum_ip' => 'Set the maximum session IP range you want to be notified for', + 'set_session_dingtalk_webhook' => 'Set the DingTalk webhook for the session notifier (keyword: session).', 'save_session_notifier_settings' => 'Save all the session notifier settings to framework', 'start_session_notifier' => 'Start notifying sessions', 'stop_session_notifier' => 'Stop notifying sessions', @@ -107,38 +112,52 @@ module Msf end end - def cmd_save_session_notifier_settings(*args) - save_settings_to_config - print_status("Session Notifier settings saved in config file.") + def cmd_set_session_dingtalk_webhook(*args) + webhook_url = args[0] + if webhook_url.blank? + @dingtalk_webhook = nil + elsif !(webhook_url =~ URI::DEFAULT_PARSER.make_regexp).nil? + @dingtalk_webhook = webhook_url + else + print_error('Invalid webhook_url') + end end - def cmd_start_session_notifier(*args) - if is_session_notifier_subscribed? + def cmd_save_session_notifier_settings(*_args) + save_settings_to_config + print_status('Session Notifier settings saved in config file.') + end + + def cmd_start_session_notifier(*_args) + if session_notifier_subscribed? print_status('You already have an active session notifier.') return end begin - validate_settings! - self.framework.events.add_session_subscriber(self) - smtp = Rex::Proto::Sms::Model::Smtp.new( - address: self.smtp_address, - port: self.smtp_port, - username: self.smtp_username, - password: self.smtp_password, - login_type: :login, - from: self.smtp_from - ) - @sms_client = Rex::Proto::Sms::Client.new(carrier: self.sms_carrier, smtp_server: smtp) - print_status("Session notification started.") + framework.events.add_session_subscriber(self) + if validate_sms_settings? + smtp = Rex::Proto::Sms::Model::Smtp.new( + address: smtp_address, + port: smtp_port, + username: smtp_username, + password: smtp_password, + login_type: :login, + from: smtp_from + ) + @sms_client = Rex::Proto::Sms::Client.new(carrier: sms_carrier, smtp_server: smtp) + print_status('Session notification started.') + elsif !dingtalk_webhook.nil? + print_status('DingTalk notification started.') + end rescue Msf::Plugin::SessionNotifier::Exception, Rex::Proto::Sms::Exception => e print_error(e.message) end end - def cmd_stop_session_notifier(*args) - self.framework.events.remove_session_subscriber(self) - print_status("Session notification stopped.") + def cmd_stop_session_notifier(*_args) + framework.events.remove_session_subscriber(self) + print_status('Session notification stopped.') end def cmd_restart_session_notifier(*args) @@ -148,7 +167,7 @@ module Msf def on_session_open(session) subject = "You have a new #{session.type} session!" - msg = "#{session.tunnel_peer} (#{session.session_host}) #{session.info ? "\"#{session.info.to_s}\"" : nil}" + msg = "#{session.tunnel_peer} (#{session.session_host}) #{session.info ? "\"#{session.info}\"" : nil}" notify_session(session, subject, msg) end @@ -158,15 +177,16 @@ module Msf config_file = Msf::Config.config_file ini = Rex::Parser::Ini.new(config_file) ini.add_group(name) unless ini[name] - ini[name]['smtp_address'] = self.smtp_address - ini[name]['smtp_port'] = self.smtp_port - ini[name]['smtp_username'] = self.smtp_username - ini[name]['smtp_password'] = self.smtp_password - ini[name]['smtp_from'] = self.smtp_from - ini[name]['sms_number'] = self.sms_number - ini[name]['sms_carrier'] = self.sms_carrier - ini[name]['minimum_ip'] = self.minimum_ip.to_s unless self.minimum_ip.blank? - ini[name]['maximum_ip'] = self.maximum_ip.to_s unless self.maximum_ip.blank? + ini[name]['smtp_address'] = smtp_address + ini[name]['smtp_port'] = smtp_port + ini[name]['smtp_username'] = smtp_username + ini[name]['smtp_password'] = smtp_password + ini[name]['smtp_from'] = smtp_from + ini[name]['sms_number'] = sms_number + ini[name]['sms_carrier'] = sms_carrier + ini[name]['minimum_ip'] = minimum_ip.to_s unless minimum_ip.blank? + ini[name]['maximum_ip'] = maximum_ip.to_s unless maximum_ip.blank? + ini[name]['dingtalk_webhook'] = dingtalk_webhook.to_s unless dingtalk_webhook.blank? ini.to_file(config_file) end @@ -175,57 +195,81 @@ module Msf ini = Rex::Parser::Ini.new(config_file) group = ini[name] if group - @sms_carrier = group['sms_carrier'].to_sym if group['sms_carrier'] - @sms_number = group['sms_number'] if group['sms_number'] - @smtp_address = group['smtp_address'] if group['smtp_address'] - @smtp_port = group['smtp_port'] if group['smtp_port'] - @smtp_username = group['smtp_username'] if group['smtp_username'] - @smtp_password = group['smtp_password'] if group['smtp_password'] - @smtp_from = group['smtp_from'] if group['smtp_from'] - @minimum_ip = IPAddr.new(group['minimum_ip']) if group['minimum_ip'] - @maximum_ip = IPAddr.new(group['maximum_ip']) if group['maximum_ip'] + @sms_carrier = group['sms_carrier'].to_sym if group['sms_carrier'] + @sms_number = group['sms_number'] if group['sms_number'] + @smtp_address = group['smtp_address'] if group['smtp_address'] + @smtp_port = group['smtp_port'] if group['smtp_port'] + @smtp_username = group['smtp_username'] if group['smtp_username'] + @smtp_password = group['smtp_password'] if group['smtp_password'] + @smtp_from = group['smtp_from'] if group['smtp_from'] + @minimum_ip = IPAddr.new(group['minimum_ip']) if group['minimum_ip'] + @maximum_ip = IPAddr.new(group['maximum_ip']) if group['maximum_ip'] + @dingtalk_webhook = group['dingtalk_webhook'] if group['dingtalk_webhook'] print_status('Session Notifier settings loaded from config file.') end end - def is_session_notifier_subscribed? - subscribers = framework.events.instance_variable_get(:@session_event_subscribers).collect { |s| s.class } + def session_notifier_subscribed? + subscribers = framework.events.instance_variable_get(:@session_event_subscribers).collect(&:class) subscribers.include?(self.class) end + def send_text_to_dingtalk(session) + # https://ding-doc.dingtalk.com/doc#/serverapi2/qf2nxq/9e91d73c + uri_parser = URI.parse(dingtalk_webhook) + markdown_text = "## You have a new #{session.type} session!\n\n" \ + "**platform** : #{session.platform}\n\n" \ + "**tunnel** : #{session.tunnel_to_s}\n\n" \ + "**arch** : #{session.arch}\n\n" \ + "**info** : > #{session.info ? session.info.to_s : nil}" + json_post_data = JSON.pretty_generate({ + msgtype: 'markdown', + markdown: { title: 'Session Notifier', text: markdown_text } + }) + http = Net::HTTP.new(uri_parser.host, uri_parser.port) + http.use_ssl = true + request = Net::HTTP::Post.new(uri_parser.request_uri) + request.content_type = 'application/json' + request.body = json_post_data + res = http.request(request) + body = JSON.parse(res.body) + print_status((body['errcode'] == 0) ? 'Session notified to DingTalk.' : 'Failed to send notification.') + end + def notify_session(session, subject, msg) - if is_in_range?(session) - @sms_client.send_text_to_phones([self.sms_number], subject, msg) - print_status("Session notified to: #{self.sms_number}") + if in_range?(session) && validate_sms_settings? + @sms_client.send_text_to_phones([sms_number], subject, msg) + print_status("Session notified to: #{sms_number}") + end + if in_range?(session) && !dingtalk_webhook.nil? + send_text_to_dingtalk(session) end end - def is_in_range?(session) + def in_range?(session) # If both blank, it means we're not setting a range. - return true if self.minimum_ip.blank? && self.maximum_ip.blank? + return true if minimum_ip.blank? && maximum_ip.blank? ip = IPAddr.new(session.session_host) - if self.minimum_ip && !self.maximum_ip + if minimum_ip && !maximum_ip # There is only a minimum IP - self.minimum_ip < ip - elsif !self.minimum_ip && self.maximum_ip + minimum_ip < ip + elsif !minimum_ip && maximum_ip # There is only a max IP - self.maximum_ip > ip + maximum_ip > ip else # Both ends are set - range = self.minimum_ip..self.maximum_ip + range = minimum_ip..maximum_ip range.include?(ip) end end - def validate_settings! - if self.smtp_address.nil? || self.smtp_port.nil? || - self.smtp_username.nil? || self.smtp_password.nil? || - self.smtp_from.nil? - raise Msf::Plugin::SessionNotifier::Exception, "All Session Notifier's settings must be configured." - end + def validate_sms_settings? + !(smtp_address.nil? || smtp_port.nil? || + smtp_username.nil? || smtp_password.nil? || + smtp_from.nil?) end end @@ -243,13 +287,9 @@ module Msf remove_console_dispatcher(name) end - def name - 'SessionNotifier' - end - def desc 'This plugin notifies you a new session via SMS.' end end -end \ No newline at end of file +end