Merge pull request #478 from guardicore/feature/refactor_fingerprinting
Feature/refactor fingerprinting
This commit is contained in:
commit
e1b31e00a5
|
@ -33,9 +33,6 @@ class Configuration(object):
|
||||||
if self._depth_from_commandline and key == "depth":
|
if self._depth_from_commandline and key == "depth":
|
||||||
continue
|
continue
|
||||||
# handle in cases
|
# handle in cases
|
||||||
if key == 'finger_classes':
|
|
||||||
class_objects = [getattr(network_import, val) for val in value]
|
|
||||||
setattr(self, key, class_objects)
|
|
||||||
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)
|
||||||
|
|
|
@ -7,7 +7,7 @@ from infection_monkey.exploit import HostExploiter
|
||||||
from infection_monkey.exploit.tools.helpers import get_target_monkey, get_monkey_depth, build_monkey_commandline
|
from infection_monkey.exploit.tools.helpers import get_target_monkey, get_monkey_depth, build_monkey_commandline
|
||||||
from infection_monkey.exploit.tools.smb_tools import SmbTools
|
from infection_monkey.exploit.tools.smb_tools import SmbTools
|
||||||
from infection_monkey.model import MONKEY_CMDLINE_DETACHED_WINDOWS, DROPPER_CMDLINE_DETACHED_WINDOWS
|
from infection_monkey.model import MONKEY_CMDLINE_DETACHED_WINDOWS, DROPPER_CMDLINE_DETACHED_WINDOWS
|
||||||
from infection_monkey.network import SMBFinger
|
from infection_monkey.network.smbfinger import SMBFinger
|
||||||
from infection_monkey.network.tools import check_tcp_port
|
from infection_monkey.network.tools import check_tcp_port
|
||||||
from common.utils.exploit_enum import ExploitType
|
from common.utils.exploit_enum import ExploitType
|
||||||
from infection_monkey.telemetry.attack.t1035_telem import T1035Telem
|
from infection_monkey.telemetry.attack.t1035_telem import T1035Telem
|
||||||
|
|
|
@ -17,7 +17,7 @@ from impacket.dcerpc.v5 import transport
|
||||||
from infection_monkey.exploit.tools.helpers import get_target_monkey, get_monkey_depth, build_monkey_commandline
|
from infection_monkey.exploit.tools.helpers import get_target_monkey, get_monkey_depth, build_monkey_commandline
|
||||||
from infection_monkey.exploit.tools.smb_tools import SmbTools
|
from infection_monkey.exploit.tools.smb_tools import SmbTools
|
||||||
from infection_monkey.model import DROPPER_CMDLINE_WINDOWS, MONKEY_CMDLINE_WINDOWS
|
from infection_monkey.model import DROPPER_CMDLINE_WINDOWS, MONKEY_CMDLINE_WINDOWS
|
||||||
from infection_monkey.network import SMBFinger
|
from infection_monkey.network.smbfinger import SMBFinger
|
||||||
from infection_monkey.network.tools import check_tcp_port
|
from infection_monkey.network.tools import check_tcp_port
|
||||||
from . import HostExploiter
|
from . import HostExploiter
|
||||||
|
|
||||||
|
@ -234,7 +234,8 @@ class Ms08_067_Exploiter(HostExploiter):
|
||||||
# execute the remote dropper in case the path isn't final
|
# execute the remote dropper in case the path isn't final
|
||||||
if remote_full_path.lower() != self._config.dropper_target_path_win_32.lower():
|
if remote_full_path.lower() != self._config.dropper_target_path_win_32.lower():
|
||||||
cmdline = DROPPER_CMDLINE_WINDOWS % {'dropper_path': remote_full_path} + \
|
cmdline = DROPPER_CMDLINE_WINDOWS % {'dropper_path': remote_full_path} + \
|
||||||
build_monkey_commandline(self.host, get_monkey_depth() - 1, self._config.dropper_target_path_win_32)
|
build_monkey_commandline(self.host, get_monkey_depth() - 1,
|
||||||
|
self._config.dropper_target_path_win_32)
|
||||||
else:
|
else:
|
||||||
cmdline = MONKEY_CMDLINE_WINDOWS % {'monkey_path': remote_full_path} + \
|
cmdline = MONKEY_CMDLINE_WINDOWS % {'monkey_path': remote_full_path} + \
|
||||||
build_monkey_commandline(self.host, get_monkey_depth() - 1)
|
build_monkey_commandline(self.host, get_monkey_depth() - 1)
|
||||||
|
|
|
@ -6,6 +6,7 @@ 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
|
||||||
|
@ -145,7 +146,7 @@ class InfectionMonkey(object):
|
||||||
|
|
||||||
self._exploiters = WormConfiguration.exploiter_classes
|
self._exploiters = WormConfiguration.exploiter_classes
|
||||||
|
|
||||||
self._fingerprint = [fingerprint() for fingerprint in WormConfiguration.finger_classes]
|
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
|
||||||
|
@ -192,9 +193,7 @@ class InfectionMonkey(object):
|
||||||
self._exploiters = sorted(self._exploiters, key=lambda exploiter_: exploiter_.EXPLOIT_TYPE.value)
|
self._exploiters = sorted(self._exploiters, key=lambda exploiter_: exploiter_.EXPLOIT_TYPE.value)
|
||||||
host_exploited = False
|
host_exploited = False
|
||||||
for exploiter in [exploiter(machine) for exploiter in self._exploiters]:
|
for exploiter in [exploiter(machine) for exploiter in self._exploiters]:
|
||||||
|
|
||||||
if self.try_exploiting(machine, exploiter):
|
if self.try_exploiting(machine, exploiter):
|
||||||
|
|
||||||
host_exploited = True
|
host_exploited = True
|
||||||
VictimHostTelem('T1210', ScanStatus.USED, machine=machine).send()
|
VictimHostTelem('T1210', ScanStatus.USED, machine=machine).send()
|
||||||
break
|
break
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
from abc import abstractmethod
|
||||||
|
|
||||||
|
from infection_monkey.config import WormConfiguration
|
||||||
|
from infection_monkey.utils.plugins.plugin import Plugin
|
||||||
|
import infection_monkey.network
|
||||||
|
|
||||||
|
|
||||||
|
class HostFinger(Plugin):
|
||||||
|
@staticmethod
|
||||||
|
def base_package_file():
|
||||||
|
return infection_monkey.network.__file__
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def base_package_name():
|
||||||
|
return infection_monkey.network.__package__
|
||||||
|
|
||||||
|
@property
|
||||||
|
@abstractmethod
|
||||||
|
def _SCANNED_SERVICE(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def init_service(self, services, service_key, port):
|
||||||
|
services[service_key] = {}
|
||||||
|
services[service_key]['display_name'] = self._SCANNED_SERVICE
|
||||||
|
services[service_key]['port'] = port
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def get_host_fingerprint(self, host):
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def should_run(class_name: str) -> bool:
|
||||||
|
return class_name in WormConfiguration.finger_classes
|
|
@ -0,0 +1,8 @@
|
||||||
|
from abc import ABCMeta, abstractmethod
|
||||||
|
|
||||||
|
|
||||||
|
class HostScanner(metaclass=ABCMeta):
|
||||||
|
@property
|
||||||
|
@abstractmethod
|
||||||
|
def is_host_alive(self, host):
|
||||||
|
raise NotImplementedError()
|
|
@ -1,36 +1 @@
|
||||||
from abc import ABCMeta, abstractmethod
|
|
||||||
|
|
||||||
__author__ = 'itamar'
|
__author__ = 'itamar'
|
||||||
|
|
||||||
|
|
||||||
class HostScanner(object, metaclass=ABCMeta):
|
|
||||||
@abstractmethod
|
|
||||||
def is_host_alive(self, host):
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
|
|
||||||
class HostFinger(object, metaclass=ABCMeta):
|
|
||||||
@property
|
|
||||||
@abstractmethod
|
|
||||||
def _SCANNED_SERVICE(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def init_service(self, services, service_key, port):
|
|
||||||
services[service_key] = {}
|
|
||||||
services[service_key]['display_name'] = self._SCANNED_SERVICE
|
|
||||||
services[service_key]['port'] = port
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def get_host_fingerprint(self, host):
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
|
|
||||||
from infection_monkey.network.ping_scanner import PingScanner
|
|
||||||
from infection_monkey.network.tcp_scanner import TcpScanner
|
|
||||||
from infection_monkey.network.smbfinger import SMBFinger
|
|
||||||
from infection_monkey.network.sshfinger import SSHFinger
|
|
||||||
from infection_monkey.network.httpfinger import HTTPFinger
|
|
||||||
from infection_monkey.network.elasticfinger import ElasticFinger
|
|
||||||
from infection_monkey.network.mysqlfinger import MySQLFinger
|
|
||||||
from infection_monkey.network.info import local_ips, get_free_tcp_port
|
|
||||||
from infection_monkey.network.mssql_fingerprint import MSSQLFinger
|
|
||||||
|
|
|
@ -6,9 +6,8 @@ import requests
|
||||||
from requests.exceptions import Timeout, ConnectionError
|
from requests.exceptions import Timeout, ConnectionError
|
||||||
|
|
||||||
import infection_monkey.config
|
import infection_monkey.config
|
||||||
|
from infection_monkey.network.HostFinger import HostFinger
|
||||||
from common.data.network_consts import ES_SERVICE
|
from common.data.network_consts import ES_SERVICE
|
||||||
from infection_monkey.model.host import VictimHost
|
|
||||||
from infection_monkey.network import HostFinger
|
|
||||||
|
|
||||||
ES_PORT = 9200
|
ES_PORT = 9200
|
||||||
ES_HTTP_TIMEOUT = 5
|
ES_HTTP_TIMEOUT = 5
|
||||||
|
@ -31,7 +30,6 @@ class ElasticFinger(HostFinger):
|
||||||
:param host:
|
:param host:
|
||||||
:return: Success/failure, data is saved in the host struct
|
:return: Success/failure, data is saved in the host struct
|
||||||
"""
|
"""
|
||||||
assert isinstance(host, VictimHost)
|
|
||||||
try:
|
try:
|
||||||
url = 'http://%s:%s/' % (host.ip_addr, ES_PORT)
|
url = 'http://%s:%s/' % (host.ip_addr, ES_PORT)
|
||||||
with closing(requests.get(url, timeout=ES_HTTP_TIMEOUT)) as req:
|
with closing(requests.get(url, timeout=ES_HTTP_TIMEOUT)) as req:
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import infection_monkey.config
|
import infection_monkey.config
|
||||||
from infection_monkey.network import HostFinger
|
from infection_monkey.network.HostFinger import HostFinger
|
||||||
from infection_monkey.model.host import VictimHost
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
@ -21,7 +20,6 @@ class HTTPFinger(HostFinger):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def get_host_fingerprint(self, host):
|
def get_host_fingerprint(self, host):
|
||||||
assert isinstance(host, VictimHost)
|
|
||||||
from requests import head
|
from requests import head
|
||||||
from requests.exceptions import Timeout, ConnectionError
|
from requests.exceptions import Timeout, ConnectionError
|
||||||
from contextlib import closing
|
from contextlib import closing
|
||||||
|
|
|
@ -2,8 +2,7 @@ import errno
|
||||||
import logging
|
import logging
|
||||||
import socket
|
import socket
|
||||||
|
|
||||||
from infection_monkey.model.host import VictimHost
|
from infection_monkey.network.HostFinger import HostFinger
|
||||||
from infection_monkey.network import HostFinger
|
|
||||||
import infection_monkey.config
|
import infection_monkey.config
|
||||||
|
|
||||||
__author__ = 'Maor Rayzin'
|
__author__ = 'Maor Rayzin'
|
||||||
|
@ -30,7 +29,6 @@ class MSSQLFinger(HostFinger):
|
||||||
Discovered server information written to the Host info struct.
|
Discovered server information written to the Host info struct.
|
||||||
True if success, False otherwise.
|
True if success, False otherwise.
|
||||||
"""
|
"""
|
||||||
assert isinstance(host, VictimHost)
|
|
||||||
|
|
||||||
# Create a UDP socket and sets a timeout
|
# Create a UDP socket and sets a timeout
|
||||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
|
|
|
@ -2,8 +2,7 @@ import logging
|
||||||
import socket
|
import socket
|
||||||
|
|
||||||
import infection_monkey.config
|
import infection_monkey.config
|
||||||
from infection_monkey.model.host import VictimHost
|
from infection_monkey.network.HostFinger import HostFinger
|
||||||
from infection_monkey.network import HostFinger
|
|
||||||
from infection_monkey.network.tools import struct_unpack_tracker, struct_unpack_tracker_string
|
from infection_monkey.network.tools import struct_unpack_tracker, struct_unpack_tracker_string
|
||||||
|
|
||||||
MYSQL_PORT = 3306
|
MYSQL_PORT = 3306
|
||||||
|
@ -28,7 +27,6 @@ class MySQLFinger(HostFinger):
|
||||||
:param host:
|
:param host:
|
||||||
:return: Success/failure, data is saved in the host struct
|
:return: Success/failure, data is saved in the host struct
|
||||||
"""
|
"""
|
||||||
assert isinstance(host, VictimHost)
|
|
||||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
s.settimeout(self.SOCKET_TIMEOUT)
|
s.settimeout(self.SOCKET_TIMEOUT)
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,8 @@ from common.network.network_range import NetworkRange
|
||||||
from infection_monkey.config import WormConfiguration
|
from infection_monkey.config import WormConfiguration
|
||||||
from infection_monkey.model.victim_host_generator import VictimHostGenerator
|
from infection_monkey.model.victim_host_generator import VictimHostGenerator
|
||||||
from infection_monkey.network.info import local_ips, get_interfaces_ranges
|
from infection_monkey.network.info import local_ips, get_interfaces_ranges
|
||||||
from infection_monkey.network import TcpScanner, PingScanner
|
from infection_monkey.network.tcp_scanner import TcpScanner
|
||||||
|
from infection_monkey.network.ping_scanner import PingScanner
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,9 @@ import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import infection_monkey.config
|
import infection_monkey.config
|
||||||
|
from infection_monkey.network.HostFinger import HostFinger
|
||||||
|
from infection_monkey.network.HostScanner import HostScanner
|
||||||
from infection_monkey.model.host import VictimHost
|
from infection_monkey.model.host import VictimHost
|
||||||
from infection_monkey.network import HostScanner, HostFinger
|
|
||||||
|
|
||||||
__author__ = 'itamar'
|
__author__ = 'itamar'
|
||||||
|
|
||||||
|
@ -28,7 +29,6 @@ class PingScanner(HostScanner, HostFinger):
|
||||||
self._ttl_regex = re.compile(TTL_REGEX_STR, re.IGNORECASE)
|
self._ttl_regex = re.compile(TTL_REGEX_STR, re.IGNORECASE)
|
||||||
|
|
||||||
def is_host_alive(self, host):
|
def is_host_alive(self, host):
|
||||||
assert isinstance(host, VictimHost)
|
|
||||||
|
|
||||||
timeout = self._config.ping_scan_timeout
|
timeout = self._config.ping_scan_timeout
|
||||||
if not "win32" == sys.platform:
|
if not "win32" == sys.platform:
|
||||||
|
@ -42,7 +42,6 @@ class PingScanner(HostScanner, HostFinger):
|
||||||
stderr=self._devnull)
|
stderr=self._devnull)
|
||||||
|
|
||||||
def get_host_fingerprint(self, host):
|
def get_host_fingerprint(self, host):
|
||||||
assert isinstance(host, VictimHost)
|
|
||||||
|
|
||||||
timeout = self._config.ping_scan_timeout
|
timeout = self._config.ping_scan_timeout
|
||||||
if not "win32" == sys.platform:
|
if not "win32" == sys.platform:
|
||||||
|
|
|
@ -3,8 +3,7 @@ import struct
|
||||||
import logging
|
import logging
|
||||||
from odict import odict
|
from odict import odict
|
||||||
|
|
||||||
from infection_monkey.network import HostFinger
|
from infection_monkey.network.HostFinger import HostFinger
|
||||||
from infection_monkey.model.host import VictimHost
|
|
||||||
|
|
||||||
SMB_PORT = 445
|
SMB_PORT = 445
|
||||||
SMB_SERVICE = 'tcp-445'
|
SMB_SERVICE = 'tcp-445'
|
||||||
|
@ -114,7 +113,6 @@ class SMBFinger(HostFinger):
|
||||||
self._config = WormConfiguration
|
self._config = WormConfiguration
|
||||||
|
|
||||||
def get_host_fingerprint(self, host):
|
def get_host_fingerprint(self, host):
|
||||||
assert isinstance(host, VictimHost)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import re
|
import re
|
||||||
|
|
||||||
import infection_monkey.config
|
import infection_monkey.config
|
||||||
from infection_monkey.model.host import VictimHost
|
from infection_monkey.network.HostFinger import HostFinger
|
||||||
from infection_monkey.network import HostFinger
|
|
||||||
from infection_monkey.network.tools import check_tcp_port
|
from infection_monkey.network.tools import check_tcp_port
|
||||||
|
|
||||||
SSH_PORT = 22
|
SSH_PORT = 22
|
||||||
|
@ -34,7 +33,6 @@ class SSHFinger(HostFinger):
|
||||||
break
|
break
|
||||||
|
|
||||||
def get_host_fingerprint(self, host):
|
def get_host_fingerprint(self, host):
|
||||||
assert isinstance(host, VictimHost)
|
|
||||||
|
|
||||||
for name, data in list(host.services.items()):
|
for name, data in list(host.services.items()):
|
||||||
banner = data.get('banner', '')
|
banner = data.get('banner', '')
|
||||||
|
|
|
@ -2,7 +2,8 @@ from itertools import zip_longest
|
||||||
from random import shuffle
|
from random import shuffle
|
||||||
|
|
||||||
import infection_monkey.config
|
import infection_monkey.config
|
||||||
from infection_monkey.network import HostScanner, HostFinger
|
from infection_monkey.network.HostFinger import HostFinger
|
||||||
|
from infection_monkey.network.HostScanner import HostScanner
|
||||||
from infection_monkey.network.tools import check_tcp_ports, tcp_port_to_service
|
from infection_monkey.network.tools import check_tcp_ports, tcp_port_to_service
|
||||||
|
|
||||||
__author__ = 'itamar'
|
__author__ = 'itamar'
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
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')]
|
|
|
@ -6,7 +6,8 @@ from infection_monkey.telemetry.post_breach_telem import PostBreachTelem
|
||||||
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.telemetry.attack.t1064_telem import T1064Telem
|
from infection_monkey.telemetry.attack.t1064_telem import T1064Telem
|
||||||
|
from infection_monkey.utils.plugins.plugin import Plugin
|
||||||
|
import infection_monkey.post_breach.actions
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
__author__ = 'VakarisZ'
|
__author__ = 'VakarisZ'
|
||||||
|
@ -14,11 +15,19 @@ __author__ = 'VakarisZ'
|
||||||
EXECUTION_WITHOUT_OUTPUT = "(PBA execution produced no output)"
|
EXECUTION_WITHOUT_OUTPUT = "(PBA execution produced no output)"
|
||||||
|
|
||||||
|
|
||||||
class PBA(object):
|
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():
|
||||||
|
return infection_monkey.post_breach.actions.__package__
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def base_package_file():
|
||||||
|
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,9 +1,8 @@
|
||||||
import logging
|
import logging
|
||||||
import inspect
|
from typing import Sequence
|
||||||
import importlib
|
|
||||||
from infection_monkey.post_breach.pba import PBA
|
|
||||||
from infection_monkey.post_breach.actions import get_pba_files
|
|
||||||
from infection_monkey.utils.environment import is_windows_os
|
from infection_monkey.utils.environment import is_windows_os
|
||||||
|
from infection_monkey.post_breach.pba import PBA
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -34,25 +33,8 @@ class PostBreach(object):
|
||||||
LOG.info("All PBAs executed. Total {} executed.".format(len(self.pba_list)))
|
LOG.info("All PBAs executed. Total {} executed.".format(len(self.pba_list)))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def config_to_pba_list():
|
def config_to_pba_list() -> Sequence[PBA]:
|
||||||
"""
|
"""
|
||||||
Passes config to each post breach action class and aggregates results into a list.
|
|
||||||
:return: A list of PBA objects.
|
:return: A list of PBA objects.
|
||||||
"""
|
"""
|
||||||
pba_list = []
|
return PBA.get_instances()
|
||||||
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:
|
|
||||||
LOG.debug("Checking if should run PBA {}".format(pba_class.__name__))
|
|
||||||
if pba_class.should_run(pba_class.__name__):
|
|
||||||
pba = pba_class()
|
|
||||||
pba_list.append(pba)
|
|
||||||
LOG.debug("Added PBA {} to PBA list".format(pba_class.__name__))
|
|
||||||
return pba_list
|
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
from PyInstaller.utils.hooks import collect_submodules, collect_data_files
|
||||||
|
|
||||||
|
hiddenimports = collect_submodules('infection_monkey.network')
|
||||||
|
datas = (collect_data_files('infection_monkey.network', include_py_files=True))
|
|
@ -0,0 +1,65 @@
|
||||||
|
import importlib
|
||||||
|
import inspect
|
||||||
|
import logging
|
||||||
|
from abc import ABCMeta, abstractmethod
|
||||||
|
from os.path import dirname, basename, isfile, join
|
||||||
|
import glob
|
||||||
|
from typing import Sequence, TypeVar, Type
|
||||||
|
|
||||||
|
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')]
|
||||||
|
|
||||||
|
|
||||||
|
Plugin_type = TypeVar('Plugin_type', bound='Plugin')
|
||||||
|
|
||||||
|
|
||||||
|
class Plugin(metaclass=ABCMeta):
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
@abstractmethod
|
||||||
|
def should_run(class_name: str) -> bool:
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_instances(cls) -> Sequence[Type[Plugin_type]]:
|
||||||
|
"""
|
||||||
|
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