Exemplo n.º 1
0
def main():
    parser = argparse.ArgumentParser(description='Stat File Verification',
                                     conflict_handler='resolve')
    parser.add_argument('-v',
                        '--version',
                        action='version',
                        version='%(prog)s Version: ' + __version__)
    parser.add_argument('data_file',
                        type=argparse.FileType('r'),
                        help='the stats file to verify')
    arguments = parser.parse_args()

    try:
        data = serializers.JSON.load(arguments.data_file)
    except Exception:
        color.print_error('failed to load the data')
        return 1
    else:
        color.print_status('loaded the statistics data')
    finally:
        arguments.data_file.close()

    if not verify_signature(data):
        color.print_error('the signature is invalid')
        return 1

    color.print_good('the signature is valid')
    return 0
Exemplo n.º 2
0
def main():
	parser = argparse.ArgumentParser(description='King Phisher Client GUI', conflict_handler='resolve')
	utilities.argp_add_args(parser, default_root='KingPhisher')
	startup.argp_add_client(parser)
	arguments = parser.parse_args()

	# basic runtime checks
	if sys.version_info < (3, 4):
		color.print_error('the Python version is too old (minimum required is 3.4)')
		return 0

	if Gtk.check_version(3, 14, 0):
		color.print_error('the GTK+ version is too old (minimum required is 3.14)')
		return 0

	if sys.platform.startswith('linux') and not os.environ.get('DISPLAY'):
		color.print_error('no display was detected, this must be run with an interactive X session')
		return 0

	config_file = arguments.config_file
	use_plugins = arguments.use_plugins
	use_style = arguments.use_style
	del arguments, parser
	logger = logging.getLogger('KingPhisher.Client.CLI')

	if sys.platform.startswith('linux') and not os.getuid():
		logger.warning('it is not necessary to run the king phisher client as root')

	find.init_data_path('client')

	if not gui_utilities.which_glade():
		color.print_error('unable to locate the glade ui data file')
		return 0

	logger.debug("king phisher version: {0} python version: {1}.{2}.{3}".format(version.version, sys.version_info[0], sys.version_info[1], sys.version_info[2]))
	logger.debug("client running in process: {0} main tid: 0x{1:x}".format(os.getpid(), threading.current_thread().ident))

	start_time = time.time()
	logger.debug('using ui data from glade file: ' + gui_utilities.which_glade())
	try:
		app = application.KingPhisherClientApplication(config_file=config_file, use_plugins=use_plugins, use_style=use_style)
	except Exception as error:
		logger.critical("initialization error: {0} ({1})".format(error.__class__.__name__, getattr(error, 'message', 'n/a')))
		color.print_error('failed to initialize the King Phisher client')
		return 0
	logger.debug("client loaded in {0:.2f} seconds".format(time.time() - start_time))

	GObject.threads_init()
	return app.run([])
Exemplo n.º 3
0
def main():
    parser = argparse.ArgumentParser(description='DMARC Check Utility',
                                     conflict_handler='resolve')
    parser.add_argument('domain', help='the name of the domain to check')
    arguments = parser.parse_args()

    try:
        policy = DMARCPolicy.from_domain(arguments.domain)
    except DMARCNoRecordError:
        color.print_error('dmarc policy not found')
        return

    color.print_status('dmarc policy found')
    color.print_status('record:  ' + policy.record)
    color.print_status('version: ' + policy.version)
    color.print_status('policy:  ' + policy.policy)
Exemplo n.º 4
0
def graphql_query(query, query_vars=None, context=None):
	session = None
	if context is None:
		context = {}
	if 'session' not in context:
		session = manager.Session()
		context['session'] = session
	result = graphql.schema.execute(query, context_value=context, variable_values=query_vars)
	if session is not None:
		session.close()
	if result.errors:
		color.print_error('GraphQL Exception:')
		for error in result.errors:
			if hasattr(error, 'message'):
				print('  ' + error.message)
			elif hasattr(error, 'args'):
				print('  ' + str(error.args[0]))
			else:
				print('  ' + repr(error))
	else:
		pprint.pprint(result.data)
Exemplo n.º 5
0
def graphql_query(query, query_vars=None, context=None):
	session = None
	if context is None:
		context = {}
	if 'session' not in context:
		session = manager.Session()
		context['session'] = session
	result = graphql_schema.execute(query, context_value=context, variable_values=query_vars)
	if session is not None:
		session.close()
	if result.errors:
		color.print_error('GraphQL Exception:')
		for error in result.errors:
			if hasattr(error, 'message'):
				print('  ' + error.message)
			elif hasattr(error, 'args'):
				print('  ' + str(error.args[0]))
			else:
				print('  ' + repr(error))
	else:
		pprint.pprint(result.data)
Exemplo n.º 6
0
def main():
	parser = argparse.ArgumentParser(description='King Phisher SPF Check Utility', conflict_handler='resolve')
	utilities.argp_add_args(parser)
	parser.add_argument('smtp_server_ip', help='the ip address of the sending smtp server')
	parser.add_argument('target_email', help='the email address that messages are from')
	arguments = parser.parse_args()

	utilities.configure_stream_logger(arguments.loglvl, arguments.logger)

	server_ip = arguments.smtp_server_ip
	target_email = arguments.target_email

	if not utilities.is_valid_ip_address(server_ip):
		color.print_error('the smtp server ip address specified is invalid')
		return

	if not utilities.is_valid_email_address(target_email):
		color.print_error('the email address specified is invalid')
		return

	spf_sender, spf_domain = target_email.split('@')
	spf_test = spf.SenderPolicyFramework(server_ip, spf_domain, spf_sender)
	try:
		result = spf_test.check_host()
	except spf.SPFPermError as error:
		color.print_error('check_host failed with error: permerror')
		color.print_error('error reason: ' + error.message)
		return
	except spf.SPFTempError:
		color.print_error('check_host failed with error: temperror')
		return
	if not result:
		color.print_status('no spf policy was found for the specified domain')
		return

	color.print_good("spf policy result: {0}".format(result))
	color.print_status('top level spf records found:')
	for rid in range(len(spf_test.spf_records)):
		record = spf.record_unparse(spf_test.spf_records[rid])
		color.print_status("  #{0} {1: <10} {2}".format(rid + 1, ('(matched)' if rid == spf_test.spf_record_id else ''), record))
Exemplo n.º 7
0
def main():
	parser = argparse.ArgumentParser(description='Stat File Verification', conflict_handler='resolve')
	parser.add_argument('-v', '--version', action='version', version='%(prog)s Version: ' + __version__)
	parser.add_argument('data_file', type=argparse.FileType('r'), help='the stats file to verify')
	arguments = parser.parse_args()

	try:
		data = json_ex.load(arguments.data_file)
	except Exception:
		color.print_error('failed to load the data')
		return 1
	else:
		color.print_status('loaded the statistics data')
	finally:
		arguments.data_file.close()

	if not verify_signature(data):
		color.print_error('the signature is invalid')
		return 1

	color.print_good('the signature is valid')
	return 0
Exemplo n.º 8
0
def main():
	parser = argparse.ArgumentParser(description='King Phisher TOTP Enrollment Utility', conflict_handler='resolve')
	utilities.argp_add_args(parser)
	config_group = parser.add_mutually_exclusive_group(required=True)
	config_group.add_argument('-c', '--config', dest='server_config', type=argparse.FileType('r'), help='the server configuration file')
	config_group.add_argument('-u', '--url', dest='database_url', help='the database connection url')
	parser.add_argument('--otp', dest='otp_secret', help='a specific otp secret')
	parser.add_argument('user', help='the user to mange')
	parser.add_argument('action', choices=('remove', 'set', 'show'), help='the action to preform')
	parser.epilog = PARSER_EPILOG
	arguments = parser.parse_args()

	utilities.configure_stream_logger(arguments.loglvl, arguments.logger)

	if arguments.database_url:
		database_connection_url = arguments.database_url
	elif arguments.server_config:
		server_config = yaml.load(arguments.server_config)
		database_connection_url = server_config['server']['database']
	else:
		raise RuntimeError('no database connection was specified')

	manager.init_database(database_connection_url)
	session = manager.Session()
	user = session.query(models.User).filter_by(id=arguments.user).first()
	if not user:
		color.print_error("invalid user id: {0}".format(arguments.user))
		return

	for case in utilities.switch(arguments.action):
		if case('remove'):
			user.otp_secret = None
			break
		if case('set'):
			if user.otp_secret:
				color.print_error("the specified user already has an otp secret set")
				return
			if arguments.otp_secret:
				new_otp = arguments.otp_secret
			else:
				new_otp = pyotp.random_base32()
			if len(new_otp) != 16:
				color.print_error("invalid otp secret length, must be 16")
				return
			user.otp_secret = new_otp
			break

	if user.otp_secret:
		color.print_status("user: {0} otp: {1}".format(user.id, user.otp_secret))
		totp = pyotp.TOTP(user.otp_secret)
		uri = totp.provisioning_uri(user.id + '@king-phisher') + '&issuer=King%20Phisher'
		color.print_status("provisioning uri: {0}".format(uri))
	else:
		color.print_status("user: {0} otp: N/A".format(user.id))
	session.commit()
def main():
	parser = argparse.ArgumentParser(description='King Phisher SPF Check Utility', conflict_handler='resolve')
	parser.add_argument('-v', '--version', action='version', version=parser.prog + ' Version: ' + version.version)
	parser.add_argument('-L', '--log', dest='loglvl', action='store', choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'], default='CRITICAL', help='set the logging level')
	parser.add_argument('smtp_server_ip', help='the ip address of the sending smtp server')
	parser.add_argument('target_email', help='the email address that messages are from')
	arguments = parser.parse_args()

	logging.getLogger('').setLevel(logging.DEBUG)
	console_log_handler = logging.StreamHandler()
	console_log_handler.setLevel(getattr(logging, arguments.loglvl))
	console_log_handler.setFormatter(logging.Formatter("%(levelname)-8s %(message)s"))
	logging.getLogger('').addHandler(console_log_handler)

	server_ip = arguments.smtp_server_ip
	target_email = arguments.target_email

	if not utilities.is_valid_ip_address(server_ip):
		color.print_error('the smtp server ip address specified is invalid')
		return

	if not utilities.is_valid_email_address(target_email):
		color.print_error('the email address specified is invalid')
		return

	spf_sender, spf_domain = target_email.split('@')
	spf_test = spf.SenderPolicyFramework(server_ip, spf_domain, spf_sender)
	try:
		result = spf_test.check_host()
	except spf.SPFPermError:
		color.print_error('check_host failed with error: permerror')
		return
	except spf.SPFTempError:
		color.print_error('check_host failed with error: temperror')
		return
	if not result:
		color.print_status('no spf policy was found for the specified domain')
		return

	color.print_good("spf policy result: {0}".format(result))
	color.print_status('top level spf records found:')
	for rid in range(len(spf_test.spf_records)):
		record = spf.record_unparse(spf_test.spf_records[rid])
		color.print_status("  #{0} {1: <10} {2}".format(rid + 1, ('(matched)' if rid == spf_test.spf_record_id else ''), record))
Exemplo n.º 10
0
def main():
    parser = argparse.ArgumentParser(
        conflict_handler='resolve',
        description=PARSER_DESCRIPTION,
        epilog=PARSER_EPILOG,
        formatter_class=argparse.RawTextHelpFormatter)
    utilities.argp_add_args(parser)
    config_group = parser.add_mutually_exclusive_group(required=True)
    config_group.add_argument('-c',
                              '--config',
                              dest='server_config',
                              help='the server configuration file')
    config_group.add_argument('-u',
                              '--url',
                              dest='database_url',
                              help='the database connection url')
    parser.add_argument('--force',
                        dest='force',
                        action='store_true',
                        default=False,
                        help='create the user if necessary')
    parser.add_argument('--otp',
                        dest='otp_secret',
                        help='a specific otp secret')
    if has_qrcode:
        parser.add_argument('--qrcode',
                            dest='qrcode_filename',
                            help='generate a qrcode image file')
    parser.add_argument('user', help='the user to mange')
    parser.add_argument('action',
                        choices=('remove', 'set', 'show'),
                        help='the action to preform')
    parser.epilog = PARSER_EPILOG
    arguments = parser.parse_args()

    if arguments.database_url:
        database_connection_url = arguments.database_url
    elif arguments.server_config:
        server_config = configuration.ex_load_config(arguments.server_config)
        database_connection_url = server_config.get('server.database')
    else:
        raise RuntimeError('no database connection was specified')

    manager.init_database(database_connection_url)
    session = manager.Session()
    user = session.query(models.User).filter_by(name=arguments.user).first()
    if not user:
        if not arguments.force:
            color.print_error("invalid user id: {0}".format(arguments.user))
            return
        user = models.User(name=arguments.user)
        session.add(user)
        color.print_status('the specified user was created')

    for case in utilities.switch(arguments.action):
        if case('remove'):
            user.otp_secret = None
            break
        if case('set'):
            if user.otp_secret:
                color.print_error(
                    "the specified user already has an otp secret set")
                return
            if arguments.otp_secret:
                new_otp = arguments.otp_secret
            else:
                new_otp = pyotp.random_base32()
            if len(new_otp) != 16:
                color.print_error("invalid otp secret length, must be 16")
                return
            user.otp_secret = new_otp
            break

    if user.otp_secret:
        color.print_status("user: {0} otp: {1}".format(user.name,
                                                       user.otp_secret))
        totp = pyotp.TOTP(user.otp_secret)
        uri = totp.provisioning_uri(user.name +
                                    '@king-phisher') + '&issuer=King%20Phisher'
        color.print_status("provisioning uri: {0}".format(uri))
        if has_qrcode and arguments.qrcode_filename:
            img = qrcode.make(uri)
            img.save(arguments.qrcode_filename)
            color.print_status("wrote qrcode image to: " +
                               arguments.qrcode_filename)
    else:
        color.print_status("user: {0} otp: N/A".format(user.id))
    session.commit()
Exemplo n.º 11
0
def main():
	parser = argparse.ArgumentParser(description='King Phisher Server', conflict_handler='resolve')
	utilities.argp_add_args(parser)
	startup.argp_add_server(parser)
	arguments = parser.parse_args()

	# basic runtime checks
	if sys.version_info < (3, 4):
		color.print_error('the Python version is too old (minimum required is 3.4)')
		return 0

	console_log_handler = utilities.configure_stream_logger(arguments.logger, arguments.loglvl)
	del parser

	if os.getuid():
		color.print_error('the server must be started as root, configure the')
		color.print_error('\'server.setuid_username\' option in the config file to drop privileges')
		return os.EX_NOPERM

	# configure environment variables and load the config
	find.init_data_path('server')
	config = configuration.ex_load_config(arguments.config_file)
	if arguments.verify_config:
		color.print_good('configuration verification passed')
		color.print_good('all required settings are present')
		return os.EX_OK
	if config.has_option('server.data_path'):
		find.data_path_append(config.get('server.data_path'))

	if arguments.update_geoip_db:
		color.print_status('downloading a new geoip database')
		try:
			size = geoip.download_geolite2_city_db(config.get('server.geoip.database'))
		except errors.KingPhisherResourceError as error:
			color.print_error(error.message)
			return os.EX_UNAVAILABLE
		color.print_good("download complete, file size: {0}".format(strutils.bytes2human(size)))
		return os.EX_OK

	# setup logging based on the configuration
	if config.has_section('logging'):
		log_file = _ex_config_logging(arguments, config, console_log_handler)
	logger.debug("king phisher version: {0} python version: {1}.{2}.{3}".format(version.version, sys.version_info[0], sys.version_info[1], sys.version_info[2]))

	# initialize the plugin manager
	try:
		plugin_manager = plugins.ServerPluginManager(config)
	except errors.KingPhisherError as error:
		if isinstance(error, errors.KingPhisherPluginError):
			color.print_error("plugin error: {0} ({1})".format(error.plugin_name, error.message))
		else:
			color.print_error(error.message)
		return os.EX_SOFTWARE

	status_code = build_and_run(arguments, config, plugin_manager, log_file)
	plugin_manager.shutdown()
	logging.shutdown()
	return status_code
Exemplo n.º 12
0
def _ex_config_logging(arguments, config, console_handler):
	"""
	If a setting is configured improperly, this will terminate execution via
	:py:func:`sys.exit`.

	:return: The path to a log file if one is in use.
	:rtype: str
	"""
	default_log_level = min(
		getattr(logging, (arguments.loglvl or constants.DEFAULT_LOG_LEVEL)),
		getattr(logging, config.get_if_exists('logging.level', 'critical').upper())
	)
	log_levels = ('DEBUG', 'INFO', 'WARNING', 'ERROR', 'FATAL')
	file_path = None
	if config.has_option('logging.file'):
		options = config.get('logging.file')
		for _ in range(1):
			default_format = '%(asctime)s %(name)-50s %(levelname)-8s %(message)s'
			if isinstance(options, dict):   # new style
				if not options.get('enabled', True):
					break
				if 'path' not in options:
					color.print_error('logging.file is missing required key \'path\'')
					sys.exit(os.EX_CONFIG)
				if 'level' not in options:
					color.print_error('logging.file is missing required key \'level\'')
					sys.exit(os.EX_CONFIG)
				file_path = options['path']
				formatter = logging.Formatter(options.get('format', default_format))
				if not options['level'].upper() in log_levels:
					color.print_error('logging.file.level is invalid, must be one of: ' + ', '.join(log_levels))
					sys.exit(os.EX_CONFIG)
				log_level = getattr(logging, options['level'].upper())
				root = options.get('root', '')
			elif isinstance(options, str):  # old style
				file_path = options
				formatter = logging.Formatter(default_format)
				log_level = default_log_level
				root = ''
			else:
				break
			file_handler = logging.FileHandler(file_path)
			file_handler.setFormatter(formatter)
			logging.getLogger(root).addHandler(file_handler)
			file_handler.setLevel(log_level)

	if config.has_option('logging.console'):
		options = config.get('logging.console')
		for _ in range(1):
			if isinstance(options, dict):   # new style
				if not options.get('enabled', True):
					break
				if 'format' in options:
					console_handler.setFormatter(color.ColoredLogFormatter(options['format']))

				if arguments.loglvl is None and 'level' in options:
					log_level = str(options.get('level', '')).upper()
					if log_level not in log_levels:
						color.print_error('logging.console.level is invalid, must be one of: ' + ', '.join(log_levels))
						sys.exit(os.EX_CONFIG)
					console_handler.setLevel(getattr(logging, log_level))
			elif isinstance(options, str):  # old style
				console_handler.setLevel(default_log_level)
	return file_path
Exemplo n.º 13
0
def main():
    parser = argparse.ArgumentParser(
        description='King Phisher Certbot Wrapper Utility',
        conflict_handler='resolve')
    utilities.argp_add_args(parser)
    parser.add_argument('--certbot',
                        dest='certbot_bin',
                        help='the path to the certbot binary to use')
    parser.add_argument('--json-output',
                        dest='json_file',
                        help='update a json formatted file with the details')
    parser.add_argument('--restart-service',
                        action='store_true',
                        default=False,
                        help='attempt to restart the king-phisher service')
    parser.add_argument('server_config', help='the server configuration file')
    parser.add_argument('hostnames',
                        nargs='+',
                        help='the host names to request certificates for')
    parser.epilog = PARSER_EPILOG
    arguments = parser.parse_args()

    server_config = configuration.ex_load_config(
        arguments.server_config).get('server')
    web_root = server_config['web_root']

    if os.getuid():
        color.print_error('this tool must be run as root')
        return os.EX_NOPERM

    certbot_bin = arguments.certbot_bin or smoke_zephyr.utilities.which(
        'certbot')
    if certbot_bin is None:
        color.print_error(
            'could not identify the path to the certbot binary, make sure that it is'
        )
        color.print_error(
            'installed and see: https://certbot.eff.org/ for more details')
        return os.EX_UNAVAILABLE
    if not os.access(certbot_bin, os.R_OK | os.X_OK):
        color.print_error(
            'found insufficient permissions on the certbot binary')
        return os.EX_NOPERM

    logger = logging.getLogger('KingPhisher.Tool.CLI.CertbotWrapper')
    logger.info('using certbot binary at: ' + certbot_bin)

    logger.debug('getting server binding information')
    if server_config.get('addresses'):
        address = server_config['addresses'][0]
    else:
        address = server_config['address']
        address['ssl'] = bool(server_config.get('ssl_cert'))

    logger.debug(
        "checking that the king phisher server is running on: {host}:{port} (ssl={ssl})"
        .format(**address))
    try:
        rpc = advancedhttpserver.RPCClient((address['host'], address['port']),
                                           use_ssl=address['ssl'])
        version = rpc('version')
    except (advancedhttpserver.RPCError, socket.error):
        logger.error('received an rpc error while checking the version',
                     exc_info=True)
        color.print_error(
            'failed to verify that the king phisher server is running')
        return os.EX_UNAVAILABLE
    logger.info('connected to server version: ' + version['version'])

    vhost_directories = server_config['vhost_directories']
    if len(arguments.hostnames) > 1 and not vhost_directories:
        color.print_error(
            'vhost_directories must be true to specify multiple hostnames')
        return os.EX_CONFIG

    for hostname in arguments.hostnames:
        if vhost_directories:
            directory = os.path.join(web_root, hostname)
        else:
            directory = web_root
            if os.path.split(os.path.abspath(directory))[-1] != hostname:
                color.print_error(
                    'when the vhost_directories option is not set, the web_root option'
                )
                color.print_error('must be: ' +
                                  os.path.join(web_root, hostname))
                return os.EX_CONFIG
        if not os.path.exists(directory):
            os.mkdir(directory, mode=0o775)
            logger.info('created directory for host at: ' + directory)

        certbot_args = (certbot_bin, 'certonly', '--webroot', '-w', directory,
                        '-d', hostname)
        logger.info('running certbot command: ' + ' '.join(certbot_args))
        proc_h = subprocess.Popen(certbot_args, shell=False)
        status = proc_h.wait()
        if status != os.EX_OK:
            color.print_error('certbot exited with exit status: ' +
                              str(status))
            break
        color.print_good('certbot exited with a successful status code')
        timestamp = datetime.datetime.utcnow().isoformat() + '+00:00'
        if not os.path.isdir(os.path.join(LETS_ENCRYPT_LIVE_PATH, hostname)):
            logger.warning('failed to find the new hostname in: ' +
                           LETS_ENCRYPT_LIVE_PATH)
            continue

        details = {
            'created':
            timestamp,
            'host':
            hostname,
            'ssl_cert':
            os.path.join(LETS_ENCRYPT_LIVE_PATH, hostname, 'fullchain.pem'),
            'ssl_key':
            os.path.join(LETS_ENCRYPT_LIVE_PATH, hostname, 'privkey.pem')
        }

        if arguments.json_file:
            existing_data = []
            if os.path.isfile(arguments.json_file):
                with open(arguments.json_file, 'r') as file_h:
                    existing_data = serializers.JSON.load(file_h)
                if not isinstance(existing_data, list):
                    color.print_status(
                        'the existing json data must be a list to add the new data'
                    )
            existing_data.append(details)
            with open(arguments.json_file, 'w') as file_h:
                serializers.JSON.dump(existing_data, file_h)
        else:
            color.print_status(
                'copy the following lines into the server configuration file under'
            )
            color.print_status(
                'the \'ssl_hosts:\' section to use the certificates with king phisher'
            )
            print('    # created: ' + details['created'])
            print('    - host: ' + details['host'])
            print('      ssl_cert: ' + details['ssl_cert'])
            print('      ssl_key: ' + details['ssl_key'])

    if arguments.hostnames and arguments.json_file and arguments.restart_service:
        systemctl_bin = smoke_zephyr.utilities.which('systemctl')
        if systemctl_bin is None:
            color.print_error(
                'could not restart the king-phisher service (could not find systemctl)'
            )
            return os.EX_OK
        proc_h = subprocess.Popen([systemctl_bin, 'restart', 'king-phisher'],
                                  shell=False)
        if proc_h.wait() != 0:
            color.print_error(
                'failed to restart the king-phisher service via systemctl')
            return os.EX_SOFTWARE
        color.print_status('restarted the king-phisher service via systemctl')
    return os.EX_OK
Exemplo n.º 14
0
def main():
	parser = argparse.ArgumentParser(description='King Phisher SPF Check Utility', conflict_handler='resolve')
	utilities.argp_add_args(parser)
	parser.add_argument('smtp_server_ip', help='the ip address of the sending smtp server')
	parser.add_argument('target_email', help='the email address that messages are from')
	arguments = parser.parse_args()

	utilities.configure_stream_logger(arguments.logger, arguments.loglvl)

	server_ip = arguments.smtp_server_ip
	target_email = arguments.target_email

	if not ipaddress.is_valid(server_ip):
		color.print_error('the smtp server ip address specified is invalid')
		return

	if not '@' in target_email:
		target_email = utilities.random_string_lower_numeric(8) + '@' + target_email
		color.print_status('target email appears to be just a domain, changed to: ' + target_email)

	if not utilities.is_valid_email_address(target_email):
		color.print_error('the email address specified is invalid')
		return

	spf_sender, spf_domain = target_email.split('@')
	spf_test = spf.SenderPolicyFramework(server_ip, spf_domain, spf_sender)
	try:
		result = spf_test.check_host()
	except spf.SPFParseError as error:
		color.print_error('check_host failed with error: permerror (parsing failed)')
		color.print_error('error reason: ' + error.message)
		return
	except spf.SPFPermError as error:
		color.print_error('check_host failed with error: permerror')
		color.print_error('error reason: ' + error.message)
		return
	except spf.SPFTempError as error:
		color.print_error('check_host failed with error: temperror')
		color.print_error('error reason: ' + error.message)
		return
	if not result:
		color.print_status('no spf policy was found for the specified domain')
		return

	color.print_good("spf policy result: {0}".format(result))
	color.print_status('top level spf records found:')
	match = spf_test.match
	for record_id, record in enumerate(spf_test.records.values(), 1):
		color.print_status("  #{0} {1: <10} {2}".format(
			record_id,
			('(matched)' if match.record == record else ''),
			record.domain
		))
		for directive_id, directive in enumerate(record.directives, 1):
			color.print_status("    #{0}.{1} {2: <10} {3}".format(
				record_id,
				directive_id,
				('(matched)' if match.record == record and match.directive == directive else ''),
				directive
			))
Exemplo n.º 15
0
def main():
	parser = argparse.ArgumentParser(description='King Phisher TOTP Enrollment Utility', conflict_handler='resolve')
	utilities.argp_add_args(parser)
	config_group = parser.add_mutually_exclusive_group(required=True)
	config_group.add_argument('-c', '--config', dest='server_config', help='the server configuration file')
	config_group.add_argument('-u', '--url', dest='database_url', help='the database connection url')
	parser.add_argument('--force', dest='force', action='store_true', default=False, help='create the user if necessary')
	parser.add_argument('--otp', dest='otp_secret', help='a specific otp secret')
	if has_qrcode:
		parser.add_argument('--qrcode', dest='qrcode_filename', help='generate a qrcode image file')
	parser.add_argument('user', help='the user to mange')
	parser.add_argument('action', choices=('remove', 'set', 'show'), help='the action to preform')
	parser.epilog = PARSER_EPILOG
	arguments = parser.parse_args()

	if arguments.database_url:
		database_connection_url = arguments.database_url
	elif arguments.server_config:
		server_config = configuration.ex_load_config(arguments.server_config)
		database_connection_url = server_config.get('server.database')
	else:
		raise RuntimeError('no database connection was specified')

	manager.init_database(database_connection_url)
	session = manager.Session()
	user = session.query(models.User).filter_by(name=arguments.user).first()
	if not user:
		if not arguments.force:
			color.print_error("invalid user id: {0}".format(arguments.user))
			return
		user = models.User(name=arguments.user)
		session.add(user)
		color.print_status('the specified user was created')

	for case in utilities.switch(arguments.action):
		if case('remove'):
			user.otp_secret = None
			break
		if case('set'):
			if user.otp_secret:
				color.print_error("the specified user already has an otp secret set")
				return
			if arguments.otp_secret:
				new_otp = arguments.otp_secret
			else:
				new_otp = pyotp.random_base32()
			if len(new_otp) != 16:
				color.print_error("invalid otp secret length, must be 16")
				return
			user.otp_secret = new_otp
			break

	if user.otp_secret:
		color.print_status("user: {0} otp: {1}".format(user.name, user.otp_secret))
		totp = pyotp.TOTP(user.otp_secret)
		uri = totp.provisioning_uri(user.name + '@king-phisher') + '&issuer=King%20Phisher'
		color.print_status("provisioning uri: {0}".format(uri))
		if has_qrcode and arguments.qrcode_filename:
			img = qrcode.make(uri)
			img.save(arguments.qrcode_filename)
			color.print_status("wrote qrcode image to: " + arguments.qrcode_filename)
	else:
		color.print_status("user: {0} otp: N/A".format(user.id))
	session.commit()
Exemplo n.º 16
0
def ex_load_config(config_file, validate_schema=True):
	"""
	Load the server configuration from the specified file. This function is
	meant to be called early on during a scripts execution and if any error
	occurs, details will be printed and the process will exit.

	:param str config_file: The path to the configuration file to load.
	:param bool validate_schema: Whether or not to validate the schema of the configuration.
	:return: The loaded server configuration.
	:rtype: :py:class:`.Configuration`
	"""
	try:
		config = Configuration.from_file(config_file)
	except Exception as error:
		color.print_error('an error occurred while parsing the server configuration file')
		if isinstance(error, yaml.error.YAMLError):
			problem = getattr(error, 'problem', 'unknown yaml error')
			if hasattr(error, 'problem_mark'):
				prob_lineno = error.problem_mark.line + 1
				color.print_error("{0} - {1}:{2} {3}".format(error.__class__.__name__, config_file, prob_lineno, problem))
				lines = open(config_file, 'rU').readlines()
				for lineno, line in enumerate(lines[max(prob_lineno - 3, 0):(prob_lineno + 2)], max(prob_lineno - 3, 0) + 1):
					color.print_error("  {0} {1: <3}: {2}".format(('=>' if lineno == prob_lineno else '  '), lineno, line.rstrip()))
			else:
				color.print_error("{0} - {1}: {2}".format(error.__class__.__name__, config_file, problem))
		color.print_error('fix the errors in the configuration file and restart the server')
		sys.exit(os.EX_CONFIG)

	# check the configuration for missing and incompatible options
	if validate_schema:
		find.init_data_path('server')
		config_schema = find.data_file(os.path.join('schemas', 'json', 'king-phisher.server.config.json'))
		if not config_schema:
			color.print_error('could not load server configuration schema data')
			sys.exit(os.EX_NOINPUT)

		schema_errors = config.schema_errors(config_schema)
		if schema_errors:
			color.print_error('the server configuration validation encountered the following errors:')
			for schema_error in schema_errors:
				color.print_error("  - {0} error: {1} ({2})".format(schema_error.validator, '.'.join(map(str, schema_error.path)), schema_error.message))
			sys.exit(os.EX_CONFIG)
	return config
Exemplo n.º 17
0
def main():
	parser = argparse.ArgumentParser(
		conflict_handler='resolve',
		description=PARSER_DESCRIPTION,
		epilog=PARSER_EPILOG,
		formatter_class=argparse.RawTextHelpFormatter
	)
	utilities.argp_add_args(parser)
	parser.add_argument('--certbot', dest='certbot_bin', help='the path to the certbot binary to use')
	parser.add_argument('--json-output', dest='json_file', help='update a json formatted file with the details')
	parser.add_argument('--restart-service', action='store_true', default=False, help='attempt to restart the king-phisher service')
	parser.add_argument('server_config', help='the server configuration file')
	parser.add_argument('hostnames', nargs='+', help='the host names to request certificates for')
	parser.epilog = PARSER_EPILOG
	arguments = parser.parse_args()

	server_config = configuration.ex_load_config(arguments.server_config).get('server')
	web_root = server_config['web_root']

	if os.getuid():
		color.print_error('this tool must be run as root')
		return os.EX_NOPERM

	certbot_bin = arguments.certbot_bin or smoke_zephyr.utilities.which('certbot')
	if certbot_bin is None:
		color.print_error('could not identify the path to the certbot binary, make sure that it is')
		color.print_error('installed and see: https://certbot.eff.org/ for more details')
		return os.EX_UNAVAILABLE
	if not os.access(certbot_bin, os.R_OK | os.X_OK):
		color.print_error('found insufficient permissions on the certbot binary')
		return os.EX_NOPERM

	logger = logging.getLogger('KingPhisher.Tool.CLI.CertbotWrapper')
	logger.info('using certbot binary at: ' + certbot_bin)

	logger.debug('getting server binding information')
	if server_config.get('addresses'):
		address = server_config['addresses'][0]
	else:
		address = server_config['address']
		address['ssl'] = bool(server_config.get('ssl_cert'))

	logger.debug("checking that the king phisher server is running on: {host}:{port} (ssl={ssl})".format(**address))
	try:
		rpc = advancedhttpserver.RPCClient((address['host'], address['port']), use_ssl=address['ssl'])
		version = rpc('version')
	except (advancedhttpserver.RPCError, socket.error):
		logger.error('received an rpc error while checking the version', exc_info=True)
		color.print_error('failed to verify that the king phisher server is running')
		return os.EX_UNAVAILABLE
	logger.info('connected to server version: ' + version['version'])

	vhost_directories = server_config['vhost_directories']
	if len(arguments.hostnames) > 1 and not vhost_directories:
		color.print_error('vhost_directories must be true to specify multiple hostnames')
		return os.EX_CONFIG

	for hostname in arguments.hostnames:
		if vhost_directories:
			directory = os.path.join(web_root, hostname)
		else:
			directory = web_root
			if os.path.split(os.path.abspath(directory))[-1] != hostname:
				color.print_error('when the vhost_directories option is not set, the web_root option')
				color.print_error('must be: ' + os.path.join(web_root, hostname))
				return os.EX_CONFIG
		if not os.path.exists(directory):
			os.mkdir(directory, mode=0o775)
			logger.info('created directory for host at: ' + directory)

		certbot_args = (certbot_bin, 'certonly', '--webroot', '-w', directory, '-d', hostname)
		logger.info('running certbot command: ' + ' '.join(certbot_args))
		proc_h = subprocess.Popen(certbot_args, shell=False)
		status = proc_h.wait()
		if status != os.EX_OK:
			color.print_error('certbot exited with exit status: ' + str(status))
			break
		color.print_good('certbot exited with a successful status code')
		timestamp = datetime.datetime.utcnow().isoformat() + '+00:00'
		if not os.path.isdir(os.path.join(LETS_ENCRYPT_LIVE_PATH, hostname)):
			logger.warning('failed to find the new hostname in: ' + LETS_ENCRYPT_LIVE_PATH)
			continue

		details = {
			'created': timestamp,
			'host': hostname,
			'ssl_cert': os.path.join(LETS_ENCRYPT_LIVE_PATH, hostname, 'fullchain.pem'),
			'ssl_key': os.path.join(LETS_ENCRYPT_LIVE_PATH, hostname, 'privkey.pem')
		}

		if arguments.json_file:
			existing_data = []
			if os.path.isfile(arguments.json_file):
				with open(arguments.json_file, 'r') as file_h:
					existing_data = serializers.JSON.load(file_h)
				if not isinstance(existing_data, list):
					color.print_status('the existing json data must be a list to add the new data')
			existing_data.append(details)
			with open(arguments.json_file, 'w') as file_h:
				serializers.JSON.dump(existing_data, file_h)
		else:
			color.print_status('copy the following lines into the server configuration file under')
			color.print_status('the \'ssl_hosts:\' section to use the certificates with king phisher')
			print('    # created: ' + details['created'])
			print('    - host: ' + details['host'])
			print('      ssl_cert: ' + details['ssl_cert'])
			print('      ssl_key: ' + details['ssl_key'])

	if arguments.hostnames and arguments.json_file and arguments.restart_service:
		systemctl_bin = smoke_zephyr.utilities.which('systemctl')
		if systemctl_bin is None:
			color.print_error('could not restart the king-phisher service (could not find systemctl)')
			return os.EX_OK
		proc_h = subprocess.Popen([systemctl_bin, 'restart', 'king-phisher'], shell=False)
		if proc_h.wait() != 0:
			color.print_error('failed to restart the king-phisher service via systemctl')
			return os.EX_SOFTWARE
		color.print_status('restarted the king-phisher service via systemctl')
	return os.EX_OK
Exemplo n.º 18
0
def main():
    parser = argparse.ArgumentParser(prog='KingPhisher',
                                     description='King Phisher Client GUI',
                                     conflict_handler='resolve')
    utilities.argp_add_args(parser, default_root='KingPhisher')
    startup.argp_add_client(parser)
    arguments = parser.parse_args()

    # basic runtime checks
    if sys.version_info < (3, 4):
        color.print_error(
            'the Python version is too old (minimum required is 3.4)')
        return 0

    if Gtk.check_version(3, 14, 0):
        color.print_error(
            'the GTK+ version is too old (minimum required is 3.14)')
        return 0

    if sys.platform.startswith('linux') and not os.environ.get('DISPLAY'):
        color.print_error(
            'no display was detected, this must be run with an interactive X session'
        )
        return 0

    config_file = arguments.config_file
    use_plugins = arguments.use_plugins
    use_style = arguments.use_style
    del arguments, parser
    logger = logging.getLogger('KingPhisher.Client.CLI')

    if sys.platform.startswith('linux') and not os.getuid():
        logger.warning(
            'it is not necessary to run the king phisher client as root')

    find.init_data_path('client')

    if not gui_utilities.which_glade():
        color.print_error('unable to locate the glade ui data file')
        return 0

    logger.debug(
        "king phisher version: {0} python version: {1}.{2}.{3}".format(
            version.version, sys.version_info[0], sys.version_info[1],
            sys.version_info[2]))
    logger.debug("client running in process: {0} main tid: 0x{1:x}".format(
        os.getpid(),
        threading.current_thread().ident))

    start_time = time.time()
    logger.debug('using ui data from glade file: ' +
                 gui_utilities.which_glade())
    try:
        app = application.KingPhisherClientApplication(config_file=config_file,
                                                       use_plugins=use_plugins,
                                                       use_style=use_style)
    except Exception as error:
        logger.critical("initialization error: {0} ({1})".format(
            error.__class__.__name__, getattr(error, 'message', 'n/a')))
        color.print_error('failed to initialize the King Phisher client')
        return 0
    logger.debug("client loaded in {0:.2f} seconds".format(time.time() -
                                                           start_time))

    GObject.threads_init()
    return app.run([])
Exemplo n.º 19
0
def main():
    parser = argparse.ArgumentParser(
        description='King Phisher SPF Check Utility',
        conflict_handler='resolve')
    parser.add_argument('-v',
                        '--version',
                        action='version',
                        version=parser.prog + ' Version: ' + version.version)
    parser.add_argument(
        '-L',
        '--log',
        dest='loglvl',
        action='store',
        choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'],
        default='CRITICAL',
        help='set the logging level')
    parser.add_argument('smtp_server_ip',
                        help='the ip address of the sending smtp server')
    parser.add_argument('target_email',
                        help='the email address that messages are from')
    arguments = parser.parse_args()

    logging.getLogger('').setLevel(logging.DEBUG)
    console_log_handler = logging.StreamHandler()
    console_log_handler.setLevel(getattr(logging, arguments.loglvl))
    console_log_handler.setFormatter(
        logging.Formatter("%(levelname)-8s %(message)s"))
    logging.getLogger('').addHandler(console_log_handler)

    server_ip = arguments.smtp_server_ip
    target_email = arguments.target_email

    if not utilities.is_valid_ip_address(server_ip):
        color.print_error('the smtp server ip address specified is invalid')
        return

    if not utilities.is_valid_email_address(target_email):
        color.print_error('the email address specified is invalid')
        return

    spf_sender, spf_domain = target_email.split('@')
    spf_test = spf.SenderPolicyFramework(server_ip, spf_domain, spf_sender)
    try:
        result = spf_test.check_host()
    except spf.SPFPermError:
        color.print_error('check_host failed with error: permerror')
        return
    except spf.SPFTempError:
        color.print_error('check_host failed with error: temperror')
        return
    if not result:
        color.print_status('no spf policy was found for the specified domain')
        return

    color.print_good("spf policy result: {0}".format(result))
    color.print_status('top level spf records found:')
    for rid in range(len(spf_test.spf_records)):
        record = spf.record_unparse(spf_test.spf_records[rid])
        color.print_status("  #{0} {1: <10} {2}".format(
            rid + 1, ('(matched)' if rid == spf_test.spf_record_id else ''),
            record))
Exemplo n.º 20
0
def main():
	parser = argparse.ArgumentParser(
		conflict_handler='resolve',
		description=PARSER_DESCRIPTION,
		epilog=PARSER_EPILOG,
		formatter_class=argparse.RawTextHelpFormatter
	)
	utilities.argp_add_args(parser)
	parser.add_argument('smtp_server_ip', help='the ip address of the sending smtp server')
	parser.add_argument('target_email', help='the email address that messages are from')
	parser.add_argument('--dns-timeout', dest='dns_timeout', default=spf.DEFAULT_DNS_TIMEOUT, metavar='TIMEOUT', type=int, help='the timeout for dns queries')
	arguments = parser.parse_args()

	server_ip = arguments.smtp_server_ip
	target_email = arguments.target_email

	if not ipaddress.is_valid(server_ip):
		color.print_error('the smtp server ip address specified is invalid')
		return

	if not '@' in target_email:
		target_email = utilities.random_string_lower_numeric(8) + '@' + target_email
		color.print_status('target email appears to be just a domain, changed to: ' + target_email)

	if not utilities.is_valid_email_address(target_email):
		color.print_error('the email address specified is invalid')
		return

	spf_sender, spf_domain = target_email.split('@')
	spf_test = spf.SenderPolicyFramework(server_ip, spf_domain, sender=spf_sender, timeout=arguments.dns_timeout)
	try:
		result = spf_test.check_host()
	except spf.SPFParseError as error:
		color.print_error('check_host failed with error: permerror (parsing failed)')
		color.print_error('error reason: ' + error.message)
		return
	except spf.SPFPermError as error:
		color.print_error('check_host failed with error: permerror')
		color.print_error('error reason: ' + error.message)
		return
	except spf.SPFTempError as error:
		color.print_error('check_host failed with error: temperror')
		color.print_error('error reason: ' + error.message)
		return
	if not result:
		color.print_status('no spf policy was found for the specified domain')
		return

	color.print_good("spf policy result: {0}".format(result))
	color.print_status('top level spf records found:')
	match = spf_test.match
	for record_id, record in enumerate(spf_test.records.values(), 1):
		color.print_status("  #{0} {1: <10} {2}".format(
			record_id,
			('(matched)' if match.record == record else ''),
			record.domain
		))
		for directive_id, directive in enumerate(record.directives, 1):
			color.print_status("    #{0}.{1: <2} {2: <10} {3}".format(
				record_id,
				directive_id,
				('(matched)' if match.record == record and match.directive == directive else ''),
				directive
			))
Exemplo n.º 21
0
def ex_load_config(config_file, validate_schema=True):
    """
	Load the server configuration from the specified file. This function is
	meant to be called early on during a scripts execution and if any error
	occurs, details will be printed and the process will exit.

	:param str config_file: The path to the configuration file to load.
	:param bool validate_schema: Whether or not to validate the schema of the configuration.
	:return: The loaded server configuration.
	:rtype: :py:class:`.Configuration`
	"""
    try:
        config = Configuration.from_file(config_file)
    except Exception as error:
        color.print_error(
            'an error occurred while parsing the server configuration file')
        if isinstance(error, yaml.error.YAMLError):
            problem = getattr(error, 'problem', 'unknown yaml error')
            if hasattr(error, 'problem_mark'):
                prob_lineno = error.problem_mark.line + 1
                color.print_error("{0} - {1}:{2} {3}".format(
                    error.__class__.__name__, config_file, prob_lineno,
                    problem))
                lines = open(config_file, 'rU').readlines()
                for lineno, line in enumerate(
                        lines[max(prob_lineno - 3, 0):(prob_lineno + 2)],
                        max(prob_lineno - 3, 0) + 1):
                    color.print_error("  {0} {1: <3}: {2}".format(
                        ('=>' if lineno == prob_lineno else '  '), lineno,
                        line.rstrip()))
            else:
                color.print_error("{0} - {1}: {2}".format(
                    error.__class__.__name__, config_file, problem))
        color.print_error(
            'fix the errors in the configuration file and restart the server')
        sys.exit(os.EX_CONFIG)

    # check the configuration for missing and incompatible options
    if validate_schema:
        find.init_data_path('server')
        config_schema = find.data_file(
            os.path.join('schemas', 'json', 'king-phisher.server.config.json'))
        if not config_schema:
            color.print_error(
                'could not load server configuration schema data')
            sys.exit(os.EX_NOINPUT)

        schema_errors = config.schema_errors(config_schema)
        if schema_errors:
            color.print_error(
                'the server configuration validation encountered the following errors:'
            )
            for schema_error in schema_errors:
                color.print_error("  - {0} error: {1} ({2})".format(
                    schema_error.validator,
                    '.'.join(map(str,
                                 schema_error.path)), schema_error.message))
            sys.exit(os.EX_CONFIG)
    return config
Exemplo n.º 22
0
def _ex_config_logging(arguments, config, console_handler):
	"""
	If a setting is configured improperly, this will terminate execution via
	:py:func:`sys.exit`.

	:return: The path to a log file if one is in use.
	:rtype: str
	"""
	default_log_level = min(
		getattr(logging, (arguments.loglvl or constants.DEFAULT_LOG_LEVEL)),
		getattr(logging, config.get_if_exists('logging.level', 'critical').upper())
	)
	log_levels = ('DEBUG', 'INFO', 'WARNING', 'ERROR', 'FATAL')
	file_path = None
	if config.has_option('logging.file'):
		options = config.get('logging.file')
		for _ in range(1):
			default_format = '%(asctime)s %(name)-50s %(levelname)-8s %(message)s'
			if isinstance(options, dict):   # new style
				if not options.get('enabled', True):
					break
				if 'path' not in options:
					color.print_error('logging.file is missing required key \'path\'')
					sys.exit(os.EX_CONFIG)
				if 'level' not in options:
					color.print_error('logging.file is missing required key \'level\'')
					sys.exit(os.EX_CONFIG)
				file_path = options['path']
				formatter = logging.Formatter(options.get('format', default_format))
				if not options['level'].upper() in log_levels:
					color.print_error('logging.file.level is invalid, must be one of: ' + ', '.join(log_levels))
					sys.exit(os.EX_CONFIG)
				log_level = getattr(logging, options['level'].upper())
				root = options.get('root', '')
			elif isinstance(options, str):  # old style
				file_path = options
				formatter = logging.Formatter(default_format)
				log_level = default_log_level
				root = ''
			else:
				break
			file_handler = logging.FileHandler(file_path)
			file_handler.setFormatter(formatter)
			logging.getLogger(root).addHandler(file_handler)
			file_handler.setLevel(log_level)

	if config.has_option('logging.console'):
		options = config.get('logging.console')
		for _ in range(1):
			if isinstance(options, dict):   # new style
				if not options.get('enabled', True):
					break
				if 'format' in options:
					console_handler.setFormatter(color.ColoredLogFormatter(options['format']))

				if arguments.loglvl is None and 'level' in options:
					log_level = str(options.get('level', '')).upper()
					if log_level not in log_levels:
						color.print_error('logging.console.level is invalid, must be one of: ' + ', '.join(log_levels))
						sys.exit(os.EX_CONFIG)
					console_handler.setLevel(getattr(logging, log_level))
			elif isinstance(options, str):  # old style
				console_handler.setLevel(default_log_level)
	return file_path
Exemplo n.º 23
0
def main():
	parser = argparse.ArgumentParser(description='King Phisher SPF Check Utility', conflict_handler='resolve')
	utilities.argp_add_args(parser)
	parser.add_argument('smtp_server_ip', help='the ip address of the sending smtp server')
	parser.add_argument('target_email', help='the email address that messages are from')
	parser.add_argument('--dns-timeout', dest='dns_timeout', default=spf.DEFAULT_DNS_TIMEOUT, type=int, help='the timeout for dns queries')
	arguments = parser.parse_args()

	server_ip = arguments.smtp_server_ip
	target_email = arguments.target_email

	if not ipaddress.is_valid(server_ip):
		color.print_error('the smtp server ip address specified is invalid')
		return

	if not '@' in target_email:
		target_email = utilities.random_string_lower_numeric(8) + '@' + target_email
		color.print_status('target email appears to be just a domain, changed to: ' + target_email)

	if not utilities.is_valid_email_address(target_email):
		color.print_error('the email address specified is invalid')
		return

	spf_sender, spf_domain = target_email.split('@')
	spf_test = spf.SenderPolicyFramework(server_ip, spf_domain, sender=spf_sender, timeout=arguments.dns_timeout)
	try:
		result = spf_test.check_host()
	except spf.SPFParseError as error:
		color.print_error('check_host failed with error: permerror (parsing failed)')
		color.print_error('error reason: ' + error.message)
		return
	except spf.SPFPermError as error:
		color.print_error('check_host failed with error: permerror')
		color.print_error('error reason: ' + error.message)
		return
	except spf.SPFTempError as error:
		color.print_error('check_host failed with error: temperror')
		color.print_error('error reason: ' + error.message)
		return
	if not result:
		color.print_status('no spf policy was found for the specified domain')
		return

	color.print_good("spf policy result: {0}".format(result))
	color.print_status('top level spf records found:')
	match = spf_test.match
	for record_id, record in enumerate(spf_test.records.values(), 1):
		color.print_status("  #{0} {1: <10} {2}".format(
			record_id,
			('(matched)' if match.record == record else ''),
			record.domain
		))
		for directive_id, directive in enumerate(record.directives, 1):
			color.print_status("    #{0}.{1: <2} {2: <10} {3}".format(
				record_id,
				directive_id,
				('(matched)' if match.record == record and match.directive == directive else ''),
				directive
			))
Exemplo n.º 24
0
def main():
	parser = argparse.ArgumentParser(description='King Phisher Server', conflict_handler='resolve')
	utilities.argp_add_args(parser)
	startup.argp_add_server(parser)
	arguments = parser.parse_args()

	# basic runtime checks
	if sys.version_info < (3, 4):
		color.print_error('the Python version is too old (minimum required is 3.4)')
		return 0

	console_log_handler = utilities.configure_stream_logger(arguments.logger, arguments.loglvl)
	del parser

	if os.getuid():
		color.print_error('the server must be started as root, configure the')
		color.print_error('\'server.setuid_username\' option in the config file to drop privileges')
		return os.EX_NOPERM

	# configure environment variables and load the config
	find.init_data_path('server')
	config = configuration.ex_load_config(arguments.config_file)
	if arguments.verify_config:
		color.print_good('configuration verification passed')
		color.print_good('all required settings are present')
		return os.EX_OK
	if config.has_option('server.data_path'):
		find.data_path_append(config.get('server.data_path'))

	if arguments.update_geoip_db:
		color.print_status('downloading a new geoip database')
		try:
			size = geoip.download_geolite2_city_db(config.get('server.geoip.database'))
		except errors.KingPhisherResourceError as error:
			color.print_error(error.message)
			return os.EX_UNAVAILABLE
		color.print_good("download complete, file size: {0}".format(strutils.bytes2human(size)))
		return os.EX_OK

	# setup logging based on the configuration
	if config.has_section('logging'):
		log_file = _ex_config_logging(arguments, config, console_log_handler)
	logger.debug("king phisher version: {0} python version: {1}.{2}.{3}".format(version.version, sys.version_info[0], sys.version_info[1], sys.version_info[2]))

	# initialize the plugin manager
	try:
		plugin_manager = plugins.ServerPluginManager(config)
	except errors.KingPhisherError as error:
		if isinstance(error, errors.KingPhisherPluginError):
			color.print_error("plugin error: {0} ({1})".format(error.plugin_name, error.message))
		else:
			color.print_error(error.message)
		return os.EX_SOFTWARE

	status_code = build_and_run(arguments, config, plugin_manager, log_file)
	plugin_manager.shutdown()
	logging.shutdown()
	return status_code
Exemplo n.º 25
0
def main():
	parser = argparse.ArgumentParser(description='King Phisher Certbot Wrapper Utility', conflict_handler='resolve')
	utilities.argp_add_args(parser)
	parser.add_argument('--certbot', dest='certbot_bin', help='the path to the certbot binary to use')
	parser.add_argument('server_config', type=argparse.FileType('r'), help='the server configuration file')
	parser.add_argument('hostnames', nargs='+', help='the host names to request certificates for')
	parser.epilog = PARSER_EPILOG
	arguments = parser.parse_args()

	server_config = yaml.load(arguments.server_config)
	web_root = server_config['server']['web_root']

	if os.getuid():
		color.print_error('this tool must be ran as root')
		return os.EX_NOPERM

	certbot_bin = arguments.certbot_bin or smoke_zephyr.utilities.which('certbot')
	if certbot_bin is None:
		color.print_error('could not identify the path to the certbot binary, make sure that it is')
		color.print_error('installed and see: https://certbot.eff.org/ for more details')
		return os.EX_NOTFOUND
	if not os.access(certbot_bin, os.R_OK | os.X_OK):
		color.print_error('found insufficient permissions on the certbot binary')
		return os.EX_NOPERM

	logger = logging.getLogger('KingPhisher.Tool.CLI.CertbotWrapper')
	logger.info('using certbot binary at: ' + certbot_bin)

	logger.debug('getting server binding information')
	if server_config['server'].get('addresses'):
		address = server_config['server']['addresses'][0]
	else:
		address = server_config['server']['address']
		address['ssl'] = bool(server_config['server'].get('ssl_cert'))

	logger.debug("checking that the king phisher server is running on: {host}:{port} (ssl={ssl})".format(**address))
	try:
		rpc = advancedhttpserver.RPCClient((address['host'], address['port']), use_ssl=address['ssl'])
		version = rpc('version')
	except (advancedhttpserver.RPCError, socket.error):
		logger.error('received an rpc error while checking the version', exc_info=True)
		color.print_error('failed to verify that the king phisher server is running')
		return os.EX_UNAVAILABLE
	logger.info('connected to server version: ' + version['version'])

	vhost_directories = server_config['server']['vhost_directories']
	if len(arguments.hostnames) > 1 and not vhost_directories:
		color.print_error('vhost_directories must be true to specify multiple hostnames')
		return os.EX_CONFIG

	for hostname in arguments.hostnames:
		if vhost_directories:
			directory = os.path.join(web_root, hostname)
		else:
			directory = web_root
			if os.path.split(os.path.abspath(directory))[-1] != hostname:
				color.print_error('when the vhost_directories option is not set, the web_root option')
				color.print_error('must be: ' + os.path.join(web_root, hostname))
				return os.EX_CONFIG
		if not os.path.exists(directory):
			os.mkdir(directory, mode=0o775)
			logger.info('created directory for host at: ' + directory)

		certbot_args = (certbot_bin, 'certonly', '--webroot', '-w', directory, '-d', hostname)
		logger.info('running certbot command: ' + ' '.join(certbot_args))
		proc_h = subprocess.Popen(certbot_args, shell=False)
		status = proc_h.wait()
		if status != os.EX_OK:
			color.print_error('certbot exited with exit status: ' + int(status))
			break
		color.print_good('certbot exited with successful status code')
		if not os.path.isdir(os.path.join(LETS_ENCRYPT_LIVE_PATH, hostname)):
			logger.warning('failed to find the new hostname in: ' + LETS_ENCRYPT_LIVE_PATH)
			continue
		color.print_status('copy the following lines into the server configuration file under')
		color.print_status('the \'ssl_hosts:\' section to use the certificates with king phisher')
		print("    - host: {0}".format(hostname))
		print("      ssl_cert: /etc/letsencrypt/live/{0}/fullchain.pem".format(hostname))
		print("      ssl_key: /etc/letsencrypt/live/{0}/privkey.pem".format(hostname))