def signal_renderer_toggled_install(self, _, path): repo_model, catalog_model = self._get_plugin_model_parents(self._model[path]) named_row = self._named_model(*self._model[path]) if named_row.installed: if named_row.enabled: if not gui_utilities.show_dialog_yes_no('Plugin is enabled', self.window, 'This will disable the plugin, do you want to continue?'): return self._disable_plugin(path) self._uninstall_plugin(path) return if named_row.id in self.config['plugins.installed']: plugin_src = self.config['plugins.installed'].get(named_row.id) if plugin_src != {'catalog_id': catalog_model.id, 'repo_id': repo_model.id, 'plugin_id': named_row.id}: window_question = 'A plugin with this name is already installed from another\nrepository. Do you want to replace it with this one?' if not gui_utilities.show_dialog_yes_no('Plugin installed from another source', self.window, window_question): return if not self._remove_matching_plugin(path, plugin_src): self.logger.warning("failed to uninstall plugin {0}".format(named_row.id)) return self.catalog_plugins.install_plugin(catalog_model.id, repo_model.id, named_row.id, self.plugin_path) self.config['plugins.installed'][named_row.id] = {'catalog_id': catalog_model.id, 'repo_id': repo_model.id, 'plugin_id': named_row.id} self._set_model_item(path, 'installed', True) self._set_model_item(path, 'version', self.catalog_plugins.get_collection(catalog_model.id, repo_model.id)[named_row.id]['version']) self.logger.info("installed plugin {} from catalog:{}, repository:{}".format(named_row.id, catalog_model.id, repo_model.id)) self.application.plugin_manager.load_all(on_error=self._on_plugin_load_error)
def signal_notebook_switch_page(self, notebook, current_page, index): previous_page = notebook.get_nth_page(self.last_page_id) self.last_page_id = index config_tab = self.tabs.get('config') edit_tab = self.tabs.get('edit') preview_tab = self.tabs.get('preview') if config_tab and previous_page == config_tab.box: config_tab.objects_save_to_config() elif edit_tab and previous_page == edit_tab.box: for _ in range(1): html_file = self.config.get('mailer.html_file') if not html_file: break text = edit_tab.textbuffer.get_text(edit_tab.textbuffer.get_start_iter(), edit_tab.textbuffer.get_end_iter(), False) if not text: break with codecs.open(html_file, 'r', encoding='utf-8') as file_h: old_text = file_h.read() if old_text == text: break if not gui_utilities.show_dialog_yes_no('Save HTML the file?', self.parent): break html_file_h = open(html_file, 'w') html_file_h.write(text) html_file_h.close() if config_tab and current_page == config_tab.box: config_tab.objects_load_from_config() elif edit_tab and current_page == edit_tab.box: edit_tab.show_tab() elif preview_tab and current_page == preview_tab.box: preview_tab.show_tab()
def signal_activate_edit_delete_campaign(self, _): if not gui_utilities.show_dialog_yes_no( 'Delete This Campaign?', self.application.get_active_window(), 'This action is irreversible, all campaign data will be lost.' ): return self.application.emit('campaign-delete', self.config['campaign_id'])
def signal_toolbutton_save(self, toolbutton): html_file = self.config.get("mailer.html_file") if not html_file: return if not gui_utilities.show_dialog_yes_no("Save HTML File", self.parent, "Do you want to save the changes?"): return self.save_html_file()
def delete_campaign(self): if not gui_utilities.show_dialog_yes_no('Delete This Campaign?', self, 'This action is irreversible. All campaign data will be lost.'): return self.rpc('campaign/delete', self.config['campaign_id']) if not self.show_campaign_selection(): gui_utilities.show_dialog_error('A Campaign Must Be Selected', self, 'Now exiting') self.client_quit()
def prompt_and_generate(self): active_window = self.application.get_active_window() dialog_txt = 'Would you like to submit anonymized data to SecureState for research purposes?' if not gui_utilities.show_dialog_yes_no('Submit Phishing Data', active_window, dialog_txt): return get_stats = StatsGenerator(self.application.rpc) stats = get_stats.generate_stats() stats = stats.encode('utf-8') stats = bz2.compress(stats) stats = base64.b64encode(stats) stats = stats.decode('utf-8') stats = '\n'.join(textwrap.wrap(stats, width=80)) try: response = requests.post( 'https://forms.hubspot.com/uploads/form/v2/147369/f374545b-987f-44ce-82e5-889293a0e6b3', data={ 'email': '*****@*****.**', 'statistics': stats } ) assert response.ok except (AssertionError, requests.exceptions.RequestException): self.logger.error('failed to submit data', exc_info=True) gui_utilities.show_dialog_error('Error Submitting Data', active_window, 'An Error occurred while submitting the data.') return gui_utilities.show_dialog_info('Submitted Data', active_window, 'Successfully submitted anonymized phishing data.\nThank you for your support!') self.config['last_date'] = datetime.datetime.utcnow()
def signal_notebook_switch_page(self, notebook, current_page, index): previous_page = notebook.get_nth_page(self.last_page_id) self.last_page_id = index config_tab = self.tabs.get('config') edit_tab = self.tabs.get('edit') preview_tab = self.tabs.get('preview') if config_tab and previous_page == config_tab.box: config_tab.objects_save_to_config() elif edit_tab and previous_page == edit_tab.box: for _ in range(1): text = edit_tab.textbuffer.get_text(edit_tab.textbuffer.get_start_iter(), edit_tab.textbuffer.get_end_iter(), False) if not text: break if its.py_v2: text = text.decode('utf-8') html_file = self.config.get('mailer.html_file') if html_file and os.access(html_file, os.R_OK): with codecs.open(html_file, 'r', encoding='utf-8') as file_h: old_text = file_h.read() if old_text == text: break message = 'Save the message HTML file?' if preview_tab and current_page == preview_tab.box: message += '\nSaving is required to preview the HTML.' if not gui_utilities.show_dialog_yes_no('Save HTML', self.parent, message): break edit_tab.save_html_file() if config_tab and current_page == config_tab.box: config_tab.objects_load_from_config() elif edit_tab and current_page == edit_tab.box: edit_tab.show_tab() elif preview_tab and current_page == preview_tab.box: preview_tab.show_tab()
def prompt_and_generate(self): active_window = self.application.get_active_window() dialog_txt = 'Would you like to submit anonymized data to SecureState for research purposes?' if not gui_utilities.show_dialog_yes_no('Submit Phishing Data', active_window, dialog_txt): return get_stats = StatsGenerator(self.application.rpc) stats = get_stats.generate_stats() stats = stats.encode('utf-8') stats = bz2.compress(stats) stats = base64.b64encode(stats) stats = stats.decode('utf-8') stats = '\n'.join(textwrap.wrap(stats, width=80)) try: response = requests.post( 'https://forms.hubspot.com/uploads/form/v2/147369/f374545b-987f-44ce-82e5-889293a0e6b3', data={ 'email': '*****@*****.**', 'statistics': stats }) assert response.ok except (AssertionError, requests.exceptions.RequestException): self.logger.error('failed to submit data', exc_info=True) gui_utilities.show_dialog_error( 'Error Submitting Data', active_window, 'An Error occurred while submitting the data.') return gui_utilities.show_dialog_info( 'Submitted Data', active_window, 'Successfully submitted anonymized phishing data.\nThank you for your support!' ) self.config['last_date'] = datetime.datetime.utcnow()
def enrollment_remove(self, _): rpc = self.application.rpc this_user = rpc.graphql_file(user_gql_query, {'name': rpc.username})['db']['user'] if this_user['otpSecret'] is None: gui_utilities.show_dialog_info( 'Not Enrolled', self.application.get_active_window(), 'This account is not currently enrolled in two factor\n'\ + 'authentication. There are no changes to make.' ) return remove = gui_utilities.show_dialog_yes_no( 'Already Enrolled', self.application.get_active_window(), 'Are you sure you want to unenroll in TOTP? This will remove\n'\ + 'two factor authentication on your account.' ) if not remove: return rpc.remote_table_row_set('users', this_user['id'], {'otp_secret': None}) gui_utilities.show_dialog_info( 'TOTP Unenrollment', self.application.get_active_window(), 'Successfully removed the TOTP secret. Your account is now unenrolled\n'\ + 'in two factor authentication. You will no longer be prompted to enter\n'\ + 'the value when you login.' )
def signal_treeview_key_pressed(self, widget, event): if event.type != Gdk.EventType.KEY_PRESS: return treeview = self.gobjects['treeview_campaigns'] keyval = event.get_keyval()[1] if event.get_state() == Gdk.ModifierType.CONTROL_MASK: if keyval == Gdk.KEY_c: gui_utilities.gtk_treeview_selection_to_clipboard(treeview) elif keyval == Gdk.KEY_F5: self.load_campaigns() self._highlight_campaign(self.config.get('campaign_name')) elif keyval == Gdk.KEY_Delete: treeview_selection = treeview.get_selection() (model, tree_iter) = treeview_selection.get_selected() if not tree_iter: return campaign_id = model.get_value(tree_iter, 0) if self.config.get('campaign_id') == campaign_id: gui_utilities.show_dialog_warning('Can Not Delete Campaign', self.dialog, 'Can not delete the current campaign.') return if not gui_utilities.show_dialog_yes_no('Delete This Campaign?', self.dialog, 'This action is irreversible, all campaign data will be lost.'): return self.parent.rpc('campaign/delete', campaign_id) self.load_campaigns() self._highlight_campaign(self.config.get('campaign_name'))
def _plugin_install(self, model_row): if not self._worker_thread_is_ready: # check it here to fail fast, then self._worker_thread_start checks it again later self._show_dialog_busy() return named_row = _ModelNamedRow(*model_row) repo_model, catalog_model = self._get_plugin_model_parents(model_row) if named_row.id in self.config['plugins.installed']: plugin_src = self.config['plugins.installed'].get(named_row.id) if plugin_src != { 'catalog_id': catalog_model.id, 'repo_id': repo_model.id, 'plugin_id': named_row.id }: window_question = 'A plugin with this name is already installed from another\nrepository. Do you want to replace it with this one?' if not gui_utilities.show_dialog_yes_no( 'Plugin installed from another source', self.window, window_question): return if not self._remove_matching_plugin(named_row, plugin_src): self.logger.warning( "failed to uninstall plugin {0}".format(named_row.id)) return self._worker_thread_start(self._plugin_install_tsafe, catalog_model, repo_model, model_row, named_row)
def enrollment_remove(self, _): rpc = self.application.rpc this_user = rpc.remote_table_row('users', rpc.username) if this_user.otp_secret is None: gui_utilities.show_dialog_info( 'Not Enrolled', self.application.get_active_window(), 'This account is not currently enrolled in two factor\n'\ + 'authentication. There are no changes to make.' ) return remove = gui_utilities.show_dialog_yes_no( 'Already Enrolled', self.application.get_active_window(), 'Are you sure you want to unenroll in TOTP? This will remove\n'\ + 'two factor authentication on your account.' ) if not remove: return this_user.otp_secret = None this_user.commit() gui_utilities.show_dialog_info( 'TOTP Unenrollment', self.application.get_active_window(), 'Successfully removed the TOTP secret. Your account is now unenrolled\n'\ + 'in two factor authentication. You will no longer be prompted to enter\n'\ + 'the value when you login.' )
def signal_notebook_switch_page(self, notebook, current_page, index): previous_page = notebook.get_nth_page(self.last_page_id) self.last_page_id = index config_tab = self.tabs.get('config') edit_tab = self.tabs.get('edit') preview_tab = self.tabs.get('preview') if config_tab and previous_page == config_tab.box: config_tab.objects_save_to_config() elif edit_tab and previous_page == edit_tab.box: for _ in range(1): html_file = self.config.get('mailer.html_file') if not html_file: break text = edit_tab.textbuffer.get_text( edit_tab.textbuffer.get_start_iter(), edit_tab.textbuffer.get_end_iter(), False) if not text: break old_text = open(html_file, 'r').read() if old_text == text: break if not gui_utilities.show_dialog_yes_no( 'Save HTML the file?', self.parent): break html_file_h = open(html_file, 'w') html_file_h.write(text) html_file_h.close() if config_tab and current_page == config_tab.box: config_tab.objects_load_from_config() elif edit_tab and current_page == edit_tab.box: edit_tab.show_tab() elif preview_tab and current_page == preview_tab.box: preview_tab.show_tab()
def prompt_and_generate(self): config = self.config dialog_txt = 'Would you like to generate research data to submit to SecureState?' if not gui_utilities.show_dialog_yes_no( 'Phishing Data Collection', self.application.get_active_window(), dialog_txt): return get_stats = StatsGenerator(self.application.rpc) stats = get_stats.generate_stats() dialog = extras.FileChooserDialog('Save Anonymized Data', self.application.get_active_window()) file_name = 'anonymized_phishing_data.txt' response = dialog.run_quick_save(file_name) dialog.destroy() if not response['target_path']: return with open(response['target_path'], 'w') as file_h: file_h.write(stats) gui_utilities.show_dialog_info( 'Successfully Generated Data', self.application.get_active_window(), "Please review and email:\n{}\nto [email protected]". format(response['target_path'])) config['last_date'] = datetime.datetime.utcnow()
def failed_import_action(self): response = gui_utilities.show_dialog_yes_no( 'Failed to import campaign', self.window, 'Import failed, do you want to cancel and delete this campaign?' ) return response
def signal_toolbutton_save(self, toolbutton): html_file = self.config.get('mailer.html_file') if not html_file: return if not gui_utilities.show_dialog_yes_no('Save HTML File', self.parent, 'Do you want to save the changes?'): return self.save_html_file()
def signal_check_domain(self, _): email = str(self.application.config['mailer.source_email']) user, at, domain = email.partition('@') try: self.logger.debug('checking email domain') result = getaddrinfo(domain, None) if result: try: info = whois.whois(domain) self.logger.info('email domain valid') gui_utilities.show_dialog_info( 'Email Domain Valid', self.application.get_active_window(), 'Domain registered to: ' + info.name + '\n', 'Name Servers: ' + info.name_servers + '\n', 'Contact Email: ' + info.emails) except Exception as err: self.logger.info('whois lookup unavailable') gui_utilities.show_dialog_info( 'Email Domain Valid', self.application.get_active_window(), 'Your domain is valid, however whois lookup failed.') else: self.logger.info('email domain valid') except Exception as err: if not gui_utilities.show_dialog_yes_no( 'Spoofed Email Domain Doesn\'t exist, continue?', self.application.get_active_window()): return return True
def _should_set_company_info(self): if self._last_company_id is None: return False if not self._company_info_changed: return False return gui_utilities.show_dialog_yes_no( 'Update Company Info?', self.parent, 'Do you want to save the changes to the company information?')
def signal_kpc_exit_confirm(self, kpc): if not self.sender_thread: return if not self.sender_thread.is_alive(): return if gui_utilities.show_dialog_yes_no('King Phisher Is Sending Messages', self.parent, 'Are you sure you want to exit?'): return kpc.emit_stop_by_name('exit-confirm')
def stop_remote_service(self): if not gui_utilities.show_dialog_yes_no('Stop The Remote King Phisher Service?', self, 'This will stop the remote King Phisher service and\nnew incoming requests will not be processed.'): return self.rpc('shutdown') self.logger.info('the remote king phisher service has been stopped') gui_utilities.show_dialog_error('The Remote Service Has Been Stopped', self, 'Now exiting') self.client_quit() return
def delete_tag(self, tag_table, treeview, selection): (model, tree_iter) = selection.get_selected() if not tree_iter: return tag_id = model.get_value(tree_iter, 0) if not gui_utilities.show_dialog_yes_no('Delete This Tag?', self.dialog, 'This action is irreversible.'): return self.application.rpc('db/table/delete', tag_table, tag_id) self.load_tags(tag_table)
def signal_notebook_switch_page(self, notebook, current_page, index): previous_page = notebook.get_nth_page(self.last_page_id) self.last_page_id = index config_tab = self.tabs.get('config') edit_tab = self.tabs.get('edit') preview_tab = self.tabs.get('preview') if config_tab and previous_page == config_tab.box: config_tab.objects_save_to_config() elif edit_tab and previous_page == edit_tab.box: for _ in xrange(1): html_file = self.config.get('mailer.html_file') if not html_file: break text = edit_tab.textbuffer.get_text( edit_tab.textbuffer.get_start_iter(), edit_tab.textbuffer.get_end_iter(), False) if not text: break old_text = open(html_file, 'r').read() if old_text == text: break if not gui_utilities.show_dialog_yes_no( 'Save HTML the file?', self.parent): break html_file_h = open(html_file, 'w') html_file_h.write(text) html_file_h.close() if config_tab and current_page == config_tab.box: config_tab.objects_load_from_config() if edit_tab and current_page == edit_tab.box: html_file = self.config.get('mailer.html_file') if not (html_file and os.path.isfile(html_file) and os.access(html_file, os.R_OK)): edit_tab.button_save_html_file.set_sensitive(False) edit_tab.textview.set_property('editable', False) return edit_tab.button_save_html_file.set_sensitive(True) edit_tab.textview.set_property('editable', True) with open(html_file, 'rb') as file_h: html_data = file_h.read() html_data = str(html_data.decode('utf-8', 'ignore')) edit_tab.textbuffer.set_text(html_data) elif preview_tab and current_page == preview_tab.box: html_file = self.config.get('mailer.html_file') if not (html_file and os.path.isfile(html_file) and os.access(html_file, os.R_OK)): return with open(html_file, 'rb') as file_h: html_data = file_h.read() html_data = str(html_data.decode('utf-8', 'ignore')) html_data = mailer.format_message(html_data, self.config) html_file_uri = urllib.parse.urlparse(html_file, 'file').geturl() if not html_file_uri.startswith('file://'): html_file_uri = 'file://' + html_file_uri preview_tab.webview.load_html_string(html_data, html_file_uri)
def signal_button_clicked_sender_stop(self, button): if not self.sender_thread: return if not gui_utilities.show_dialog_yes_no('King Phisher Is Sending Messages', self.parent, 'Are you sure you want to stop?'): return self.sender_thread.stop() self.gobjects['button_mail_sender_stop'].set_sensitive(False) self.gobjects['button_mail_sender_start'].set_sensitive(True) self.gobjects['togglebutton_mail_sender_pause'].set_property('active', False) self.gobjects['togglebutton_mail_sender_pause'].set_sensitive(False)
def menu_item_set_defaults(self, _): proceed = gui_utilities.show_dialog_yes_no( 'Set The Default Campaign Configuration?', self.application.get_active_window(), 'Are you sure you want to set the default\n'\ + 'message configuration for new campaigns?' ) if not proceed: return self.storage['default'] = self.get_current_config()
def _sender_precheck_source(self): valid = utilities.is_valid_email_address(self.config['mailer.source_email']) valid = valid and utilities.is_valid_email_address(self.config['mailer.source_email_smtp']) if valid: return True self.text_insert('WARNING: One or more source email addresses specified are invalid.\n') if not gui_utilities.show_dialog_yes_no('Invalid Email Address', self.parent, 'One or more source email addresses specified are invalid.\nContinue sending messages anyways?'): self.text_insert('Sending aborted due to invalid source email address.\n') return False return True
def signal_button_save(self, button): html_file = self.config.get('mailer.html_file') if not html_file: return if not gui_utilities.show_dialog_yes_no("Save HTML File?", self.parent): return text = self.textbuffer.get_text(self.textbuffer.get_start_iter(), self.textbuffer.get_end_iter(), False) html_file_h = open(html_file, 'w') html_file_h.write(text) html_file_h.close()
def signal_send_precheck(self, mailer_tab): test_ip = mailer.guess_smtp_server_address( self.application.config['smtp_server'], (self.application.config['ssh_server'] if self.application.config['smtp_ssh_enable'] else None) ) if not test_ip: self.logger.info('skipping dmarc policy check because the smtp server address could not be resolved') return True test_sender, test_domain = self.application.config['mailer.source_email_smtp'].split('@') self.logger.debug('checking the dmarc policy for domain: ' + test_domain) text_insert = mailer_tab.tabs['send_messages'].text_insert text_insert("Checking the DMARC policy of target domain '{0}'... ".format(test_domain)) try: spf_result = spf.check_host(test_ip, test_domain, sender=test_sender) except spf.SPFError as error: text_insert("done, encountered exception: {0}.\n".format(error.__class__.__name__)) return True try: dmarc_policy = DMARCPolicy.from_domain(test_domain) except DMARCNoRecordError: self.logger.debug('no dmarc policy found for domain: ' + test_domain) text_insert('done, no policy found.\n') return True except DMARCError as error: self.logger.warning('dmarc error: ' + error.message) text_insert("done, encountered exception: {0}.\n".format(error.__class__.__name__)) return False text_insert('done.\n') self.logger.debug("dmarc policy set to {0!r} for domain: {1}".format(dmarc_policy.policy, test_domain)) text_insert('Found DMARC policy:\n') text_insert(' Policy: ' + dmarc_policy.policy + '\n') text_insert(' Percent: ' + dmarc_policy.get('pct') + '\n') if dmarc_policy.get('rua'): text_insert(' RUA URI: ' + dmarc_policy.get('rua') + '\n') if dmarc_policy.get('ruf'): text_insert(' RUF URI: ' + dmarc_policy.get('ruf') + '\n') if spf_result == constants.SPFResult.PASS: return True if dmarc_policy.policy == 'none' or dmarc_policy.get('pct') == '0': return True if dmarc_policy.policy == 'quarantine': message = 'The DMARC policy results in these messages being quarantined.' elif dmarc_policy.policy == 'reject': message = 'The DMARC policy results in these messages being rejected.' text_insert('WARNING: ' + message + '\n') ignore = gui_utilities.show_dialog_yes_no( 'DMARC Policy Failure', self.application.get_active_window(), message + '\nContinue sending messages anyways?' ) return ignore
def delete_tag(self, tag_table, treeview, selection): (model, tree_iter) = selection.get_selected() if not tree_iter: return tag_id = model.get_value(tree_iter, 0) if not gui_utilities.show_dialog_yes_no( 'Delete This Tag?', self.dialog, 'This action is irreversible.'): return self.application.rpc('db/table/delete', tag_table, tag_id) self.load_tags(tag_table)
def signal_button_clicked_sender_stop(self, button): if not self.sender_thread: return if not gui_utilities.show_dialog_yes_no( "King Phisher Is Sending Messages", self.parent, "Are you sure you want to stop?" ): return self.sender_thread.stop() self.gobjects["button_mail_sender_stop"].set_sensitive(False) self.gobjects["button_mail_sender_start"].set_sensitive(True) self.gobjects["togglebutton_mail_sender_pause"].set_property("active", False) self.gobjects["togglebutton_mail_sender_pause"].set_sensitive(False)
def signal_button_save(self, button): html_file = self.config.get('mailer.html_file') if not html_file: return if not gui_utilities.show_dialog_yes_no('Save HTML the file?', self.parent): return text = self.textbuffer.get_text(self.textbuffer.get_start_iter(), self.textbuffer.get_end_iter(), False) html_file_h = open(html_file, 'w') html_file_h.write(text) html_file_h.close()
def _prompt_to_delete_row(self, treeview, selection): (model, tree_iter) = selection.get_selected() if not tree_iter: return campaign_id = model.get_value(tree_iter, 0) if self.config.get('campaign_id') == campaign_id: gui_utilities.show_dialog_warning('Can Not Delete Campaign', self.dialog, 'Can not delete the current campaign.') return if not gui_utilities.show_dialog_yes_no('Delete This Campaign?', self.dialog, 'This action is irreversible, all campaign data will be lost.'): return self.application.emit('campaign-delete', campaign_id) self.load_campaigns() self._highlight_campaign(self.config.get('campaign_name'))
def campaign_delete(self): """ Delete the campaign on the server. A confirmation dialog will be displayed before the operation is performed. If the campaign is deleted and a new campaign is not selected with :py:meth:`.show_campaign_selection`, the client will quit. """ if not gui_utilities.show_dialog_yes_no('Delete This Campaign?', self.get_active_window(), 'This action is irreversible, all campaign data will be lost.'): return self.rpc('db/table/delete', 'campaigns', self.config['campaign_id']) if not self.show_campaign_selection(): gui_utilities.show_dialog_error('Now Exiting', self.get_active_window(), 'A campaign must be selected.') self.quit()
def signal_send_precheck(self, mailer_tab): if 'message_padding' not in self.application.plugin_manager.enabled_plugins: return True proceed = gui_utilities.show_dialog_yes_no( 'Warning: You are running a conflicting plugin!', self.application.get_active_window(), 'The "message_padding" plugin conflicts with "message_plaintext" in such a way '\ + 'that will cause the message padding to be revealed in the plaintext version '\ + 'of the email. It is recommended you disable one of these plugins, or append '\ + 'additional line breaks in the HTML to conceal it.\n\n' \ + 'Do you wish to continue?' ) return proceed
def _sender_precheck_url(self): self.text_insert('Checking the target URL... ') try: test_webserver_url(self.config['mailer.webserver_url'], self.config['server_config']['server.secret_id']) except requests.exceptions.RequestException: self.text_insert('failed') if not gui_utilities.show_dialog_yes_no('Unable To Open The Web Server URL', self.parent, 'The URL may be invalid, continue sending messages anyways?'): self.text_insert(', sending aborted.\n') return self.text_insert(', error ignored.\n') else: self.text_insert('success, done.\n') return True
def stop_remote_service(self): """ Stop the remote King Phisher server. This will request that the server stop processing new requests and exit. This will display a confirmation dialog before performing the operation. If the remote service is stopped, the client will quit. """ if not gui_utilities.show_dialog_yes_no('Stop The Remote King Phisher Service?', self.get_active_window(), 'This will stop the remote King Phisher service and\nnew incoming requests will not be processed.'): return self.rpc('shutdown') self.logger.info('the remote king phisher service has been stopped') gui_utilities.show_dialog_error('Now Exiting', self.get_active_window(), 'The remote service has been stopped.') self.quit() return
def _sender_precheck_url(self): self.text_insert('Checking the target URL... ') try: response = test_webserver_url(self.config['mailer.webserver_url'], self.config['server_config']['server.secret_id']) assert response.ok except (AssertionError, requests.exceptions.ConnectionError, requests.exceptions.RequestException): self.text_insert('failed') if not gui_utilities.show_dialog_yes_no('Unable To Open The Web Server URL', self.parent, 'The URL may be invalid, continue sending messages anyways?'): self.text_insert(', sending aborted.\n') return self.text_insert(', error ignored.\n') else: self.text_insert('success, done.\n') return True
def interact(self): self.dialog.show_all() self.set_status('Waiting') if not web_cloner.has_webkit2: gui_utilities.show_dialog_error('WebKit2GTK+ Is Unavailable', self.dialog, 'The WebKit2GTK+ package is not available.') self.dialog.destroy() return while self.dialog.run() == Gtk.ResponseType.APPLY: target_url = self.entry_target.get_text() if not target_url: gui_utilities.show_dialog_error('Missing Information', self.dialog, 'Please set the target URL.') self.set_status('Missing Information') continue dest_dir = self.entry_directory.get_text() if not dest_dir: gui_utilities.show_dialog_error('Missing Information', self.dialog, 'Please set the destination directory.') self.set_status('Missing Information') continue if not os.access(dest_dir, os.W_OK): gui_utilities.show_dialog_error('Invalid Directory', self.dialog, 'Can not write to the specified directory.') self.set_status('Invalid Directory') continue self.objects_save_to_config() self.set_status('Cloning', spinner_active=True) cloner = web_cloner.WebPageCloner(target_url, dest_dir) signal_id = self.button_cancel.connect('clicked', lambda _: cloner.stop_cloning()) original_label = self.button_cancel.get_label() self.button_cancel.set_label('Cancel') cloner.wait() self.button_cancel.set_label(original_label) self.button_cancel.disconnect(signal_id) if cloner.load_failed: self.set_status('Failed') gui_utilities.show_dialog_error('Operation Failed', self.dialog, 'The web page clone operation failed.') continue for resource in cloner.cloned_resources.values(): if gui_utilities.gtk_list_store_search(self.resources, resource.resource, column=0): continue self.resources.append(_ModelNamedRow( path=resource.resource, mime_type=resource.mime_type or 'N/A', size=resource.size )) self.set_status('Done') gui_utilities.gtk_sync() if len(self.resources) and gui_utilities.show_dialog_yes_no('Transfer Cloned Pages', self.dialog, 'Would you like to start the SFTP client\nto upload the cloned pages?'): self.application.emit('sftp-client-start') self.dialog.destroy()
def signal_activate_popup_menu_delete(self, action): if isinstance(self.row_loader_thread, threading.Thread) and self.row_loader_thread.is_alive(): gui_utilities.show_dialog_warning('Can Not Delete Rows While Loading', self.parent) return treeview = self.gobjects['treeview_campaign'] selection = treeview.get_selection() (model, tree_iter) = selection.get_selected() if not tree_iter: return row_id = model.get_value(tree_iter, 0) if not gui_utilities.show_dialog_yes_no('Delete This Row?', self.parent, 'This information will be lost'): return self.parent.rpc(self.remote_table_name + '/delete', row_id) self.load_campaign_information(force=True)
def signal_change_page(self, _, __, page_number): """ will check to is if the page change is from editor to sftp, and then ask if the user if they want to save detected changes. If yes it passes to the save editor file to take action. """ # page_number is the page switched from if page_number: return if not self.editor_tab_save_button.is_sensitive(): return if not gui_utilities.show_dialog_yes_no('Changes not saved', self.application.get_active_window(), 'Do you want to save your changes?'): return self._save_editor_file()
def stop_remote_service(self): """ Stop the remote King Phisher server. This will request that the server stop processing new requests and exit. This will display a confirmation dialog before performing the operation. If the remote service is stopped, the client will quit. """ active_window = self.get_active_window() if not gui_utilities.show_dialog_yes_no('Stop The Remote King Phisher Service?', active_window, 'This will stop the remote King Phisher service and\nnew incoming requests will not be processed.'): return self.rpc('shutdown') self.logger.info('the remote king phisher service has been stopped') gui_utilities.show_dialog_error('Now Exiting', active_window, 'The remote service has been stopped.') self.quit() return
def _prompt_to_delete_row(self, treeview, _): if isinstance(self.loader_thread, threading.Thread) and self.loader_thread.is_alive(): gui_utilities.show_dialog_warning('Can Not Delete Rows While Loading', self.parent) return model = treeview.get_model() row_ids = [model.get_value(ti, 0) for ti in gui_utilities.gtk_treeview_selection_iterate(treeview)] if len(row_ids) == 0: return elif len(row_ids) == 1: message = 'Delete This Row?' else: message = "Delete These {0:,} Rows?".format(len(row_ids)) if not gui_utilities.show_dialog_yes_no(message, self.parent, 'This information will be lost.'): return self.application.emit(self.table_name[:-1] + '-delete', row_ids)
def _sender_precheck_spf(self): spf_check_level = self.config["spf_check_level"] if not spf_check_level: return True if not utilities.is_valid_email_address(self.config["mailer.source_email_smtp"]): self.text_insert("WARNING: Can not check SPF records for an invalid source email address.\n") return True spf_test_ip = mailer.guess_smtp_server_address( self.config["smtp_server"], (self.config["ssh_server"] if self.config["smtp_ssh_enable"] else None) ) if not spf_test_ip: self.text_insert("Skipped checking the SPF policy because the SMTP server address could not be detected.\n") self.logger.warning( "skipping spf policy check because the smtp server address could not be reliably detected" ) return True self.logger.debug("detected the smtp server address as " + str(spf_test_ip)) spf_test_sender, spf_test_domain = self.config["mailer.source_email_smtp"].split("@") self.text_insert("Checking the SPF policy of target domain '{0}'... ".format(spf_test_domain)) try: spf_test = spf.SenderPolicyFramework(spf_test_ip, spf_test_domain, spf_test_sender) spf_result = spf_test.check_host() except spf.SPFError as error: self.text_insert("done, encountered exception: {0}.\n".format(error.__class__.__name__)) return True if not spf_result: self.text_insert("done, no policy was found.\n") else: self.text_insert("done.\n") dialog_title = "Sender Policy Framework Failure" dialog_message = None if spf_check_level == 1 and spf_result in [SPFResult.FAIL, SPFResult.SOFT_FAIL]: dialog_message = "The configuration fails the domains SPF policy.\nMessages may be marked as forged." elif spf_check_level == 2 and not spf_result in [SPFResult.NEUTRAL, SPFResult.PASS]: dialog_message = "The configuration does not pass the domains SPF policy." spf_result = spf_result or "N/A (No policy found)" self.text_insert( "{0}SPF policy result: {1}\n".format(("WARNING: " if spf_result.endswith("fail") else ""), spf_result) ) if dialog_message: dialog_message += "\n\nContinue sending messages anyways?" if not gui_utilities.show_dialog_yes_no(dialog_title, self.parent, dialog_message): self.text_insert("Sending aborted due to the SPF policy.\n") return False return True
def delete_campaign(self): """ Delete the campaign on the server. A confirmation dialog will be displayed before the operation is performed. If the campaign is deleted and a new campaign is not selected with :py:meth:`.show_campaign_selection`, the client will quit. """ if not gui_utilities.show_dialog_yes_no( 'Delete This Campaign?', self, 'This action is irreversible, all campaign data will be lost.' ): return self.rpc('campaign/delete', self.config['campaign_id']) if not self.show_campaign_selection(): gui_utilities.show_dialog_error('Now Exiting', self, 'A campaign must be selected.') self.client_quit()
def _tab_changed(self, notebook, current_page, index): previous_page = notebook.get_nth_page(self.last_page_id) self.last_page_id = index config_tab = self.tabs.get('config') edit_tab = self.tabs.get('edit') preview_tab = self.tabs.get('preview') progress_tab = self.tabs.get('progress') if config_tab and previous_page == config_tab.box: config_tab.objects_save_to_config() elif edit_tab and previous_page == edit_tab.box: for i in xrange(1): html_file = self.config.get('mailer.html_file') if not html_file: break text = edit_tab.textbuffer.get_text(edit_tab.textbuffer.get_start_iter(), edit_tab.textbuffer.get_end_iter(), False) if not text: break old_text = open(html_file, 'r').read() if old_text == text: break if not gui_utilities.show_dialog_yes_no("Save HTML File?", self.parent): break html_file_h = open(html_file, 'w') html_file_h.write(text) html_file_h.close() if config_tab and current_page == config_tab.box: config_tab.objects_load_from_config() if edit_tab and current_page == edit_tab.box: html_file = self.config.get('mailer.html_file') if not (html_file and os.path.isfile(html_file) and os.access(html_file, os.R_OK)): edit_tab.button_save_html_file.set_sensitive(False) edit_tab.textview.set_property('editable', False) return edit_tab.button_save_html_file.set_sensitive(True) edit_tab.textview.set_property('editable', True) edit_tab.textbuffer.set_text(open(html_file, 'r').read()) elif preview_tab and current_page == preview_tab.box: html_file = self.config.get('mailer.html_file') if not (html_file and os.path.isfile(html_file) and os.access(html_file, os.R_OK)): return html_file_uri = urlparse.urlparse(html_file, 'file').geturl() html_data = open(html_file, 'r').read() html_data = format_message(html_data, self.config) preview_tab.webview.load_html_string(html_data, html_file_uri)
def _plugin_install(self, model_row): if not self._worker_thread_is_ready: # check it here to fail fast, then self._worker_thread_start checks it again later self._show_dialog_busy() return named_row = _ModelNamedRow(*model_row) repo_model, catalog_model = self._get_plugin_model_parents(model_row) if named_row.id in self.config['plugins.installed']: plugin_src = self.config['plugins.installed'].get(named_row.id) if plugin_src != {'catalog_id': catalog_model.id, 'repo_id': repo_model.id, 'plugin_id': named_row.id}: window_question = 'A plugin with this name is already installed from another\nrepository. Do you want to replace it with this one?' if not gui_utilities.show_dialog_yes_no('Plugin Already Installed', self.window, window_question): return if not self._remove_matching_plugin(named_row, plugin_src): self.logger.warning("failed to uninstall plugin {0}".format(named_row.id)) return self._worker_thread_start(self._plugin_install_tsafe, catalog_model, repo_model, model_row, named_row)
def enrollment_setup(self, _): rpc = self.application.rpc this_user = rpc.graphql_file(user_gql_query, {'name': rpc.username})['db']['user'] if this_user['otpSecret'] is not None: reset = gui_utilities.show_dialog_yes_no( 'Already Enrolled', self.application.get_active_window(), 'This account is already enrolled in TOTP,\nreset the existing TOTP token?' ) if not reset: return new_otp = pyotp.TOTP(pyotp.random_base32()) provisioning_uri = rpc.username + '@' + self.application.config[ 'server'].split(':', 1)[0] provisioning_uri = new_otp.provisioning_uri( provisioning_uri) + '&issuer=King%20Phisher' bytes_io = io.BytesIO() qrcode_ = qrcode.make(provisioning_uri).get_image() qrcode_.save(bytes_io, 'PNG') pixbuf_loader = GdkPixbuf.PixbufLoader.new() pixbuf_loader.write(bytes_io.getvalue()) pixbuf_loader.close() pixbuf = pixbuf_loader.get_pixbuf() self.logger.debug('loading gtk builder file from: ' + gtk_builder_file) builder = Gtk.Builder() builder.add_from_file(gtk_builder_file) window = builder.get_object('TOTPEnrollment.window') window.set_transient_for(self.application.get_active_window()) self.application.add_window(window) image = builder.get_object('TOTPEnrollment.image_qrcode') image.set_from_pixbuf(pixbuf) button_check = builder.get_object('TOTPEnrollment.button_check') entry_totp = builder.get_object('TOTPEnrollment.entry_totp') button_check.connect('clicked', self.check_totp, window, entry_totp, new_otp, this_user) entry_totp.connect('activate', self.check_totp, window, entry_totp, new_otp, this_user) window.show_all()
def _sender_precheck_spf(self): spf_check_level = self.config['spf_check_level'] if not spf_check_level: return True if not utilities.is_valid_email_address(self.config['mailer.source_email_smtp']): self.text_insert('WARNING: Can not check SPF records for an invalid source email address.\n') return True spf_test_ip = mailer.guess_smtp_server_address(self.config['smtp_server'], (self.config['ssh_server'] if self.config['smtp_ssh_enable'] else None)) if not spf_test_ip: self.text_insert('Skipped checking the SPF policy because the SMTP server address could not be detected.\n') self.logger.warning('skipping spf policy check because the smtp server address could not be reliably detected') return True self.logger.debug('detected the smtp server address as ' + str(spf_test_ip)) spf_test_sender, spf_test_domain = self.config['mailer.source_email_smtp'].split('@') self.text_insert("Checking the SPF policy of target domain '{0}'... ".format(spf_test_domain)) try: spf_test = spf.SenderPolicyFramework(spf_test_ip, spf_test_domain, spf_test_sender) spf_result = spf_test.check_host() except spf.SPFError as error: self.text_insert("done, encountered exception: {0}.\n".format(error.__class__.__name__)) return True if not spf_result: self.text_insert('done, no policy was found.\n') else: self.text_insert('done.\n') dialog_title = 'Sender Policy Framework Failure' dialog_message = None if spf_check_level == 1 and spf_result in [SPFResult.FAIL, SPFResult.SOFT_FAIL]: dialog_message = 'The configuration fails the domains SPF policy.\nMessages may be marked as forged.' elif spf_check_level == 2 and not spf_result in [SPFResult.NEUTRAL, SPFResult.PASS]: dialog_message = 'The configuration does not pass the domains SPF policy.' spf_result = spf_result or 'N/A (No policy found)' self.text_insert("{0}SPF policy result: {1}\n".format(('WARNING: ' if spf_result.endswith('fail') else ''), spf_result)) if dialog_message: dialog_message += '\n\nContinue sending messages anyways?' if not gui_utilities.show_dialog_yes_no(dialog_title, self.parent, dialog_message): self.text_insert('Sending aborted due to the SPF policy.\n') return False return True
def _sender_precheck_url(self): self.text_insert("Checking the target URL... ") try: response = test_webserver_url( self.config["mailer.webserver_url"], self.config["server_config"]["server.secret_id"] ) assert response.ok except (AssertionError, requests.exceptions.ConnectionError, requests.exceptions.RequestException): self.text_insert("failed") if not gui_utilities.show_dialog_yes_no( "Unable To Open The Web Server URL", self.parent, "The URL may be invalid, continue sending messages anyways?", ): self.text_insert(", sending aborted.\n") return self.text_insert(", error ignored.\n") else: self.text_insert("success, done.\n") return True
def _prompt_to_delete_row(self, treeview, selection): if isinstance(self.loader_thread, threading.Thread) and self.loader_thread.is_alive(): gui_utilities.show_dialog_warning('Can Not Delete Rows While Loading', self.parent) return (model, tree_paths) = selection.get_selected_rows() if not tree_paths: return tree_iters = map(model.get_iter, tree_paths) row_ids = [model.get_value(ti, 0) for ti in tree_iters] if len(row_ids) == 1: message = 'Delete This Row?' else: message = "Delete These {0:,} Rows?".format(len(row_ids)) if not gui_utilities.show_dialog_yes_no(message, self.parent, 'This information will be lost.'): return if len(row_ids) == 1: self.rpc('db/table/delete', self.remote_table_name, row_ids[0]) else: self.rpc('db/table/delete/multi', self.remote_table_name, row_ids) self.load_campaign_information()