forked from p15670423/monkey
Turn get_instances into class method.
This leads to package_name and package_file both also being class methods. Now, each plugin family can load itself. Reimplemented Fingerprinters and PBAs to use this interface. No more need for fingerprinter collector
This commit is contained in:
parent
87cedacb7d
commit
69c66072af
|
@ -6,13 +6,13 @@ import sys
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import infection_monkey.tunnel as tunnel
|
import infection_monkey.tunnel as tunnel
|
||||||
|
from infection_monkey.network.HostFinger import HostFinger
|
||||||
from infection_monkey.utils.monkey_dir import create_monkey_dir, get_monkey_dir_path, remove_monkey_dir
|
from infection_monkey.utils.monkey_dir import create_monkey_dir, get_monkey_dir_path, remove_monkey_dir
|
||||||
from infection_monkey.utils.monkey_log_path import get_monkey_log_path
|
from infection_monkey.utils.monkey_log_path import get_monkey_log_path
|
||||||
from infection_monkey.utils.environment import is_windows_os
|
from infection_monkey.utils.environment import is_windows_os
|
||||||
from infection_monkey.config import WormConfiguration
|
from infection_monkey.config import WormConfiguration
|
||||||
from infection_monkey.control import ControlClient
|
from infection_monkey.control import ControlClient
|
||||||
from infection_monkey.model import DELAY_DELETE_CMD
|
from infection_monkey.model import DELAY_DELETE_CMD
|
||||||
from infection_monkey.network.fingerprinters_collector import get_fingerprint_instances
|
|
||||||
from infection_monkey.network.firewall import app as firewall
|
from infection_monkey.network.firewall import app as firewall
|
||||||
from infection_monkey.network.network_scanner import NetworkScanner
|
from infection_monkey.network.network_scanner import NetworkScanner
|
||||||
from infection_monkey.system_info import SystemInfoCollector
|
from infection_monkey.system_info import SystemInfoCollector
|
||||||
|
@ -146,7 +146,7 @@ class InfectionMonkey(object):
|
||||||
|
|
||||||
self._exploiters = WormConfiguration.exploiter_classes
|
self._exploiters = WormConfiguration.exploiter_classes
|
||||||
|
|
||||||
self._fingerprint = get_fingerprint_instances()
|
self._fingerprint = HostFinger.get_instances()
|
||||||
|
|
||||||
if not self._keep_running or not WormConfiguration.alive:
|
if not self._keep_running or not WormConfiguration.alive:
|
||||||
break
|
break
|
||||||
|
|
|
@ -1,10 +1,20 @@
|
||||||
from abc import ABCMeta, abstractproperty, abstractmethod
|
from abc import abstractmethod
|
||||||
|
|
||||||
from infection_monkey.config import WormConfiguration
|
from infection_monkey.config import WormConfiguration
|
||||||
from infection_monkey.utils.plugins.plugin import Plugin
|
from infection_monkey.utils.plugins.plugin import Plugin
|
||||||
|
|
||||||
|
|
||||||
class HostFinger(Plugin, metaclass=ABCMeta):
|
class HostFinger(Plugin):
|
||||||
|
@staticmethod
|
||||||
|
def base_package_file():
|
||||||
|
import infection_monkey.network # avoid circular imports
|
||||||
|
return infection_monkey.network.__file__
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def base_package_name():
|
||||||
|
import infection_monkey.network # avoid circular imports
|
||||||
|
return infection_monkey.network.__package__
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def _SCANNED_SERVICE(self):
|
def _SCANNED_SERVICE(self):
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
import logging
|
|
||||||
from typing import Sequence
|
|
||||||
from infection_monkey.utils.plugins.load_plugins import get_instances
|
|
||||||
from infection_monkey.network.HostFinger import HostFinger
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
def get_fingerprint_instances() -> Sequence[HostFinger]:
|
|
||||||
"""
|
|
||||||
Returns the fingerprint objects according to configuration as a list
|
|
||||||
:return: A list of HostFinger objects.
|
|
||||||
"""
|
|
||||||
# note this currently assumes we're in the same package as the fingerprinters
|
|
||||||
# if this changes, this file should be updated
|
|
||||||
# like when they move into a network plugins folder
|
|
||||||
return get_instances(__package__, __file__, HostFinger)
|
|
|
@ -20,6 +20,16 @@ class PBA(Plugin):
|
||||||
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.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def base_package_name():
|
||||||
|
import infection_monkey.post_breach.actions # avoid circular imports
|
||||||
|
return infection_monkey.post_breach.actions.__package__
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def base_package_file():
|
||||||
|
import infection_monkey.post_breach.actions
|
||||||
|
return infection_monkey.post_breach.actions.__file__
|
||||||
|
|
||||||
def __init__(self, name="unknown", linux_cmd="", windows_cmd=""):
|
def __init__(self, name="unknown", linux_cmd="", windows_cmd=""):
|
||||||
"""
|
"""
|
||||||
:param name: Name of post breach action.
|
:param name: Name of post breach action.
|
||||||
|
|
|
@ -1,4 +1,17 @@
|
||||||
|
import importlib
|
||||||
|
import inspect
|
||||||
|
import logging
|
||||||
from abc import ABCMeta, abstractmethod
|
from abc import ABCMeta, abstractmethod
|
||||||
|
from os.path import dirname, basename, isfile, join
|
||||||
|
import glob
|
||||||
|
from typing import Sequence
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_candidate_files(base_package_file):
|
||||||
|
files = glob.glob(join(dirname(base_package_file), "*.py"))
|
||||||
|
return [basename(f)[:-3] for f in files if isfile(f) and not f.endswith('__init__.py')]
|
||||||
|
|
||||||
|
|
||||||
class Plugin(metaclass=ABCMeta):
|
class Plugin(metaclass=ABCMeta):
|
||||||
|
@ -7,3 +20,43 @@ class Plugin(metaclass=ABCMeta):
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def should_run(class_name: str) -> bool:
|
def should_run(class_name: str) -> bool:
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_instances(cls) -> Sequence[object]:
|
||||||
|
"""
|
||||||
|
Returns the type objects from base_package_spec.
|
||||||
|
base_package name and file must refer to the same package otherwise bad results
|
||||||
|
:return: A list of parent_class objects.
|
||||||
|
"""
|
||||||
|
objects = []
|
||||||
|
candidate_files = _get_candidate_files(cls.base_package_file())
|
||||||
|
LOG.info("looking for classes of type {} in {}".format(cls.__name__, cls.base_package_name()))
|
||||||
|
# Go through all of files
|
||||||
|
for file in candidate_files:
|
||||||
|
# Import module from that file
|
||||||
|
module = importlib.import_module('.' + file, cls.base_package_name())
|
||||||
|
# Get all classes in a module
|
||||||
|
# m[1] because return object is (name,class)
|
||||||
|
classes = [m[1] for m in inspect.getmembers(module, inspect.isclass)
|
||||||
|
if ((m[1].__module__ == module.__name__) and issubclass(m[1], cls))]
|
||||||
|
# Get object from class
|
||||||
|
for class_object in classes:
|
||||||
|
LOG.debug("Checking if should run object {}".format(class_object.__name__))
|
||||||
|
try:
|
||||||
|
if class_object.should_run(class_object.__name__):
|
||||||
|
instance = class_object()
|
||||||
|
objects.append(instance)
|
||||||
|
LOG.debug("Added {} to list".format(class_object.__name__))
|
||||||
|
except Exception as e:
|
||||||
|
LOG.warning("Exception {} when checking if {} should run".format(str(e), class_object.__name__))
|
||||||
|
return objects
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
@abstractmethod
|
||||||
|
def base_package_file():
|
||||||
|
pass
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
@abstractmethod
|
||||||
|
def base_package_name():
|
||||||
|
pass
|
||||||
|
|
Loading…
Reference in New Issue