class Plugin(plugins.ServerPlugin): authors = ['Spencer McIntyre'] classifiers = ['Plugin :: Server :: Notifications'] title = 'XMPP Notifications' description = """ A plugin which pushes notifications regarding the King Phisher server to a specified XMPP server. """ homepage = 'https://github.com/securestate/king-phisher-plugins' options = [ plugin_opts.OptionString('jid', 'the username to login with'), plugin_opts.OptionString('password', 'the password to login with'), plugin_opts.OptionString('room', 'the room to send notifications to'), plugin_opts.OptionString('server', 'the server to connect to'), # verify_cert only functions when sleekxmpp supports it plugin_opts.OptionBoolean('verify_cert', 'verify the ssl certificate', default=True) ] req_min_version = '1.4.0' req_packages = { 'sleekxmpp': has_sleekxmpp } def initialize(self): logger = logging.getLogger('sleekxmpp') logger.setLevel(logging.INFO) self.bot = None signals.server_initialized.connect(self.on_server_initialized) return True def on_server_initialized(self, server): self.bot = NotificationBot( self.config['jid'], self.config['password'], self.config['room'], self.config['verify_cert'] ) self.bot.connect(utilities.parse_server(self.config['server'], 5222)) self.bot.process(block=False) def finalize(self): if self.bot is None: return self.bot.disconnect()
class Plugin(plugins.ServerPlugin): authors = ['Brandan Geise'] title = 'Pushbullet Notifications' description = """ A plugin that uses Pushbullet's API to send push notifications on new website visits and submitted credentials. """ homepage = 'https://github.com/securestate/king-phisher-plugins' options = [ plugin_opts.OptionString( name='api_keys', description='Pushbullet API key, if multiple, separate with comma' ), plugin_opts.OptionString( name='identifier', description= 'King Phisher server identifier to send in push notification header', default='King Phisher'), plugin_opts.OptionBoolean( name='mask', description='Partially mask email and campaign values', default=False) ] req_min_version = '1.4.0b0' req_packages = {'pushbullet.py': has_pushbullet} version = '1.2' def initialize(self): signals.server_initialized.connect(self.on_server_initialized) return True def on_server_initialized(self, server): signals.db_session_inserted.connect(self.on_kp_db_event, sender='visits') signals.db_session_inserted.connect(self.on_kp_db_event, sender='credentials') self.send_notification('Pushbullet notifications are now active') def on_kp_db_event(self, sender, targets, session): for event in targets: message = db_manager.get_row_by_id(session, db_models.Message, event.message_id) target_email, campaign_name = self.check_mask(message) if sender == 'visits': message = "New visit from {0} for campaign '{1}'".format( target_email, campaign_name) elif sender == 'credentials': message = "New credentials received from {0} for campaign '{1}'".format( target_email, campaign_name) else: return self.send_notification(message) def check_mask(self, message): if self.config['mask']: target_email = self.mask_string(message.target_email) campaign_name = self.mask_string(message.campaign.name) else: target_email = message.target_email campaign_name = message.campaign.name return target_email, campaign_name def mask_string(self, word): if utilities.is_valid_email_address(word): email_user, email_domain = word.split('@') safe_string = "{0}@{1}{2}{3}".format( email_user, email_domain[:1], ('*' * (len(email_domain) - 2)), email_domain[-1:]) else: safe_string = "{0}{1}{2}".format(word[:1], ('*' * (len(word) - 2)), word[-1:]) return safe_string def send_notification(self, message): api_keys = tuple(k.strip() for k in self.config['api_keys'].split(', ')) for key in api_keys: device = None if ':' in key: device, key = key.split(':') pb = pushbullet.Pushbullet(key) if device: try: device = pb.get_device(device) except pushbullet.errors.InvalidKeyError: self.logger.error( "failed to get pushbullet device: {0}".format(device)) try: pb.push_note(self.config['identifier'], message, device=device) except pushbullet.errors.PushError as error: self.logger.error('failed to send the pushbullet note')
class Plugin(plugins.ServerPlugin): authors = [ 'Austin DeFrancesco', 'Spencer McIntyre', 'Mike Stringer', 'Erik Daguerre' ] classifiers = ['Plugin :: Server :: Notifications :: Alerts'] title = 'Campaign Alerts: via Python 3 SMTPLib' description = """ Send campaign alerts via the SMTP Python 3 lib. This requires that users specify their email through the King Phisher client to subscribe to notifications. """ homepage = 'https://github.com/securestate/king-phisher-plugins' version = '1.1' # Email accounts with 2FA, such as Gmail, will not work unless "less secure apps" are allowed # Reference: https://support.google.com/accounts/answer/60610255 # Gmail and other providers require SSL on port 465, TLS will start with the activation of SSL options = [ plugin_opts.OptionString(name='smtp_server', description='Location of SMTP server', default='localhost'), plugin_opts.OptionInteger(name='smtp_port', description='Port used for SMTP server', default=25), plugin_opts.OptionString( name='smtp_email', description='SMTP email address to send notifications from', default=''), plugin_opts.OptionString( name='smtp_username', description='Username to authenticate to the SMTP server with'), plugin_opts.OptionString( name='smtp_password', description='Password to authenticate to the SMTP server with', default=''), plugin_opts.OptionBoolean( name='smtp_ssl', description='Connect to the SMTP server with SSL', default=False), plugin_opts.OptionString( name='email_jinja_template', description='Custom email jinja template to use for alerts', default=''), ] req_min_version = '1.12.0b2' def initialize(self): signals.campaign_alert.connect(self.on_campaign_alert) signals.campaign_alert_expired.connect(self.on_campaign_alert_expired) template_path = self.config['email_jinja_template'] if not template_path: template_path = os.path.join( os.path.dirname(os.path.realpath(__file__)), 'template.html') if not os.path.isfile(template_path): self.logger.warning('invalid email template: ' + template_path) return False with open(template_path, 'r') as file_: template_data = file_.read() self.render_template = templates.TemplateEnvironmentBase().from_string( template_data) return True def on_campaign_alert(self, table, alert_subscription, count): return self.send_alert(alert_subscription) def on_campaign_alert_expired(self, camapign, alert_subscription): return self.send_alert(alert_subscription) def get_template_vars(self, alert_subscription): campaign = alert_subscription.campaign template_vars = { 'campaign': { 'id': str(campaign.id), 'name': campaign.name, 'created': campaign.created, 'expiration': campaign.expiration, 'has_expired': campaign.has_expired, 'message_count': len(campaign.messages), 'visit_count': len(campaign.visits), 'credential_count': len(campaign.credentials) }, 'time': { 'local': datetime.datetime.now(), 'utc': datetime.datetime.utcnow() } } return template_vars def create_message(self, alert_subscription): message = MIMEMultipart() message['Subject'] = "Campaign Event: {0}".format( alert_subscription.campaign.name) message['From'] = "<{0}>".format(self.config['smtp_email']) message['To'] = "<{0}>".format(alert_subscription.user.email_address) textual_message = MIMEMultipart('alternative') plaintext_part = MIMEText( 'This message requires an HTML aware email agent to be properly viewed.\r\n\r\n', 'plain') textual_message.attach(plaintext_part) try: rendered_email = self.render_template.render( self.get_template_vars(alert_subscription)) except: self.logger.warning('failed to render the email template', exc_info=True) return False html_part = MIMEText(rendered_email, 'html') textual_message.attach(html_part) message.attach(textual_message) encoded_email = message.as_string() return encoded_email def send_alert(self, alert_subscription): user = alert_subscription.user if not user.email_address: self.logger.debug( "user {0} has no email address specified, skipping SMTP alert". format(user.name)) return False msg = self.create_message(alert_subscription) if not msg: return False if self.config['smtp_ssl']: SmtpClass = smtplib.SMTP_SSL else: SmtpClass = smtplib.SMTP try: server = SmtpClass(self.config['smtp_server'], self.config['smtp_port'], timeout=15) server.ehlo() except smtplib.SMTPException: self.logger.warning( 'received an SMTPException while connecting to the SMTP server', exc_info=True) return False except socket.error: self.logger.warning( 'received a socket.error while connecting to the SMTP server') return False if not self.config['smtp_ssl'] and 'starttls' in server.esmtp_features: self.logger.debug( 'target SMTP server supports the STARTTLS extension') try: server.starttls() server.ehlo() except smtplib.SMTPException: self.logger.warning( 'received an SMTPException wile negotiating STARTTLS with SMTP server', exc_info=True) return False if self.config['smtp_username']: try: server.login(self.config['smtp_username'], self.config['smtp_password']) except smtplib.SMTPNotSupportedError: self.logger.debug( 'SMTP server does not support authentication') except smtplib.SMTPException as error: self.logger.warning( "received an {0} while authenticating to the SMTP server". format(error.__class__.__name__)) server.quit() return False mail_options = ['SMTPUTF8'] if server.has_extn('SMTPUTF8') else [] try: server.sendmail(self.config['smtp_email'], alert_subscription.user.email_address, msg, mail_options) except smtplib.SMTPException as error: self.logger.warning("received error {0} while sending mail".format( error.__class__.__name__)) return False finally: server.quit() self.logger.debug( "successfully sent an email campaign alert to user: {0}".format( user.name)) return True