예제 #1
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
예제 #2
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))