Skip to content

Commit

Permalink
Merge branch 'dev' version 1.12 Final
Browse files Browse the repository at this point in the history
  • Loading branch information
wolfthefallen committed Nov 7, 2018
2 parents 1970ea2 + 5125ab8 commit 74b85b7
Show file tree
Hide file tree
Showing 60 changed files with 3,444 additions and 1,640 deletions.
2 changes: 2 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
PIPENV_VENV_IN_PROJECT=True

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

.pylintrc
.python-version
.venv/*
build/*
configs/*
dist/*
Expand Down
70 changes: 4 additions & 66 deletions KingPhisher
Original file line number Diff line number Diff line change
Expand Up @@ -31,77 +31,15 @@
#

import argparse
import logging
import os
import sys
import threading
import time

if getattr(sys, 'frozen', False):
# set the basemap data directory for frozen builds
os.environ['BASEMAPDATA'] = os.path.join(os.path.dirname(sys.executable), 'mpl-basemap-data')

from king_phisher import color
from king_phisher import find
from king_phisher import utilities
from king_phisher import version
from king_phisher.client import application
from king_phisher.client import gui_utilities

from gi.repository import GObject
from gi.repository import Gtk
from king_phisher import startup

def main():
parser = argparse.ArgumentParser(description='King Phisher Client GUI', conflict_handler='resolve')
utilities.argp_add_args(parser, default_root='KingPhisher')
parser.add_argument('-c', '--config', dest='config_file', required=False, help='specify a configuration file to use')
parser.add_argument('--no-plugins', dest='use_plugins', default=True, action='store_false', help='disable all plugins')
parser.add_argument('--no-style', dest='use_style', default=True, action='store_false', help='disable interface styling')
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([])
parser = argparse.ArgumentParser(description='King Phisher Client', conflict_handler='resolve')
startup.argp_add_client(parser)
return startup.pipenv_entry(parser, os.path.basename(__file__))

if __name__ == '__main__':
sys.exit(main())
207 changes: 3 additions & 204 deletions KingPhisherServer
Original file line number Diff line number Diff line change
Expand Up @@ -29,218 +29,17 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# pylint: disable=too-many-locals

import argparse
import logging
import os
import pwd
import signal
import sys
import threading

from king_phisher import color
from king_phisher import constants
from king_phisher import errors
from king_phisher import find
from king_phisher import geoip
from king_phisher import its
from king_phisher import utilities
from king_phisher import version
from king_phisher.server import build
from king_phisher.server import configuration
from king_phisher.server import plugins

from boltons import strutils

logger = logging.getLogger('KingPhisher.Server.CLI')

def build_and_run(arguments, config, plugin_manager, log_file=None):
# fork into the background
should_fork = True
if arguments.foreground:
should_fork = False
elif config.has_option('server.fork'):
should_fork = bool(config.get('server.fork'))
if should_fork:
if os.fork():
return sys.exit(os.EX_OK)
os.setsid()

try:
king_phisher_server = build.server_from_config(config, plugin_manager=plugin_manager)
except errors.KingPhisherDatabaseAuthenticationError:
logger.critical('failed to authenticate to the database, this usually means the password is incorrect and needs to be updated')
return os.EX_SOFTWARE
except errors.KingPhisherError as error:
logger.critical('server failed to build with error: ' + error.message)
return os.EX_SOFTWARE

server_pid = os.getpid()
logger.info("server running in process: {0} main tid: 0x{1:x}".format(server_pid, threading.current_thread().ident))

if should_fork and config.has_option('server.pid_file'):
pid_file = open(config.get('server.pid_file'), 'w')
pid_file.write(str(server_pid))
pid_file.close()

if config.has_option('server.setuid_username'):
setuid_username = config.get('server.setuid_username')
try:
user_info = pwd.getpwnam(setuid_username)
except KeyError:
logger.critical('an invalid username was specified as \'server.setuid_username\'')
king_phisher_server.shutdown()
return os.EX_NOUSER
if log_file is not None:
os.chown(log_file, user_info.pw_uid, user_info.pw_gid)
os.setgroups([])
os.setresgid(user_info.pw_gid, user_info.pw_gid, user_info.pw_gid)
os.setresuid(user_info.pw_uid, user_info.pw_uid, user_info.pw_uid)
logger.info("dropped privileges to the {0} account".format(setuid_username))
else:
logger.warning('running with root privileges is dangerous, drop them by configuring \'server.setuid_username\'')
os.umask(0o077)

db_engine_url = king_phisher_server.database_engine.url
if db_engine_url.drivername == 'sqlite':
logger.warning('sqlite is no longer fully supported, see https://github.com/securestate/king-phisher/wiki/Database#sqlite for more details')
database_dir = os.path.dirname(db_engine_url.database)
if not os.access(database_dir, os.W_OK):
logger.critical('sqlite requires write permissions to the folder containing the database')
king_phisher_server.shutdown()
return os.EX_NOPERM
sighup_handler = lambda: threading.Thread(target=king_phisher_server.shutdown).start()
signal.signal(signal.SIGHUP, lambda signum, frame: sighup_handler())
try:
king_phisher_server.serve_forever(fork=False)
except KeyboardInterrupt:
pass
king_phisher_server.shutdown()
return os.EX_OK

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
from king_phisher import startup

def main():
parser = argparse.ArgumentParser(description='King Phisher Server', conflict_handler='resolve')
utilities.argp_add_args(parser)
parser.add_argument('-f', '--foreground', dest='foreground', action='store_true', default=False, help='run in the foreground (do not fork)')
parser.add_argument('--update-geoip-db', dest='update_geoip_db', action='store_true', default=False, help='update the geoip database and exit')
parser.add_argument('--verify-config', dest='verify_config', action='store_true', default=False, help='verify the configuration and exit')
parser.add_argument('config_file', action='store', help='configuration file to use')
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')
size = geoip.download_geolite2_city_db(config.get('server.geoip.database'))
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
startup.argp_add_server(parser)
return startup.pipenv_entry(parser, os.path.basename(__file__))

if __name__ == '__main__':
sys.exit(main())
60 changes: 60 additions & 0 deletions Pipfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]
setuptools = "==40.4.3"
alembic = "==0.9.7"
blinker = "==1.4"
boltons = "==18.0.0"
cryptography = "==2.1.4"
Cython = "==0.29"
dnspython = "==1.15.0"
ecdsa = "==0.13"
"geoip2" = "==2.8.0"
geojson = "==2.3.0"
graphene = "==2.0.1"
graphene-sqlalchemy = "==2.0.0"
graphql-relay = "==0.4.5"
icalendar = "==4.0.1"
ipaddress = "==1.0.19"
jsonschema = "==2.6.0"
matplotlib = "==2.2.2"
msgpack-python = "==0.5.6"
paramiko = "==2.4.0"
pluginbase = "==0.5"
"psycopg2" = "==2.7.3.2,<2.8"
py-gfm = "==0.1.3"
pygobject = "==3.28.3"
pyotp = "==2.2.6"
python-dateutil = "==2.7.2"
python-pam = "==1.8.3"
pytz = "==2018.4"
requests = "==2.18.4"
requests-file = "==1.4.3"
six = "==1.11.0"
smoke-zephyr = "==1.2.0"
termcolor = "==1.1.0"
tzlocal = "==1.5.1"
websocket-client = "==0.49.0"
AdvancedHTTPServer = "==2.0.11"
email_validator = "==1.0.3"
"Jinja2" = "==2.10"
Markdown = "==2.6.11"
MarkupSafe = "==1.0"
PyYAML = "==3.12"
SQLAlchemy = "==1.2.6"
XlsxWriter = "==0.9.6"
numpy = "==1.14.5"
"basemap" = {file = "https://github.com/matplotlib/basemap/archive/v1.2.0rel.tar.gz"}
pyproj = {git = "https://github.com/jswhit/pyproj.git"}

[dev-packages]

[scripts]
KingPhisher = "python -m king_phisher.client"
KingPhisherServer = "python -m king_phisher.server"

[pipenv]
allow_site_packages = true
Loading

0 comments on commit 74b85b7

Please sign in to comment.