Merge branch 'develop' into bugfix/remove_warnings

This commit is contained in:
Daniel Goldberg 2019-11-28 13:43:44 +01:00
commit 1a7c5b951a
23 changed files with 231 additions and 125 deletions

View File

@ -2,11 +2,9 @@ import hashlib
import os import os
import json import json
import sys import sys
import types
import uuid import uuid
from abc import ABCMeta from abc import ABCMeta
from itertools import product from itertools import product
import importlib
__author__ = 'itamar' __author__ = 'itamar'
@ -20,10 +18,6 @@ HIDDEN_FIELD_REPLACEMENT_CONTENT = "hidden"
class Configuration(object): class Configuration(object):
def from_kv(self, formatted_data): def from_kv(self, formatted_data):
# now we won't work at <2.7 for sure
network_import = importlib.import_module('infection_monkey.network')
exploit_import = importlib.import_module('infection_monkey.exploit')
unknown_items = [] unknown_items = []
for key, value in list(formatted_data.items()): for key, value in list(formatted_data.items()):
if key.startswith('_'): if key.startswith('_'):
@ -32,11 +26,6 @@ class Configuration(object):
continue continue
if self._depth_from_commandline and key == "depth": if self._depth_from_commandline and key == "depth":
continue continue
# handle in cases
elif key == 'exploiter_classes':
class_objects = [getattr(exploit_import, val) for val in value]
setattr(self, key, class_objects)
else:
if hasattr(self, key): if hasattr(self, key):
setattr(self, key, value) setattr(self, key, value)
else: else:

View File

@ -0,0 +1,98 @@
from abc import abstractmethod
from infection_monkey.config import WormConfiguration
from common.utils.exploit_enum import ExploitType
from datetime import datetime
from infection_monkey.utils.plugins.plugin import Plugin
import infection_monkey.exploit
__author__ = 'itamar'
class HostExploiter(Plugin):
@staticmethod
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.exploiter_classes
@staticmethod
def base_package_file():
return infection_monkey.exploit.__file__
@staticmethod
def base_package_name():
return infection_monkey.exploit.__package__
_TARGET_OS_TYPE = []
# Usual values are 'vulnerability' or 'brute_force'
EXPLOIT_TYPE = ExploitType.VULNERABILITY
@property
@abstractmethod
def _EXPLOITED_SERVICE(self):
pass
def __init__(self, host):
self._config = WormConfiguration
self.exploit_info = {'display_name': self._EXPLOITED_SERVICE,
'started': '',
'finished': '',
'vulnerable_urls': [],
'vulnerable_ports': [],
'executed_cmds': []}
self.exploit_attempts = []
self.host = host
def set_start_time(self):
self.exploit_info['started'] = datetime.now().isoformat()
def set_finish_time(self):
self.exploit_info['finished'] = datetime.now().isoformat()
def is_os_supported(self):
return self.host.os.get('type') in self._TARGET_OS_TYPE
def send_exploit_telemetry(self, result):
from infection_monkey.telemetry.exploit_telem import ExploitTelem
ExploitTelem(self, result).send()
def report_login_attempt(self, result, user, password='', lm_hash='', ntlm_hash='', ssh_key=''):
self.exploit_attempts.append({'result': result, 'user': user, 'password': password,
'lm_hash': lm_hash, 'ntlm_hash': ntlm_hash, 'ssh_key': ssh_key})
def exploit_host(self):
self.pre_exploit()
try:
result = self._exploit_host()
finally:
self.post_exploit()
return result
def pre_exploit(self):
self.set_start_time()
def post_exploit(self):
self.set_finish_time()
@abstractmethod
def _exploit_host(self):
raise NotImplementedError()
def add_vuln_url(self, url):
self.exploit_info['vulnerable_urls'].append(url)
def add_vuln_port(self, port):
self.exploit_info['vulnerable_ports'].append(port)
def add_executed_cmd(self, cmd):
"""
Appends command to exploiter's info.
:param cmd: String of executed command. e.g. 'echo Example'
"""
powershell = True if "powershell" in cmd.lower() else False
self.exploit_info['executed_cmds'].append({'cmd': cmd, 'powershell': powershell})

View File

@ -1,92 +0,0 @@
from abc import ABCMeta, abstractmethod, abstractproperty
import infection_monkey.config
from common.utils.exploit_enum import ExploitType
from datetime import datetime
__author__ = 'itamar'
class HostExploiter(object, metaclass=ABCMeta):
_TARGET_OS_TYPE = []
# Usual values are 'vulnerability' or 'brute_force'
EXPLOIT_TYPE = ExploitType.VULNERABILITY
@property
@abstractmethod
def _EXPLOITED_SERVICE(self):
pass
def __init__(self, host):
self._config = infection_monkey.config.WormConfiguration
self.exploit_info = {'display_name': self._EXPLOITED_SERVICE,
'started': '',
'finished': '',
'vulnerable_urls': [],
'vulnerable_ports': [],
'executed_cmds': []}
self.exploit_attempts = []
self.host = host
def set_start_time(self):
self.exploit_info['started'] = datetime.now().isoformat()
def set_finish_time(self):
self.exploit_info['finished'] = datetime.now().isoformat()
def is_os_supported(self):
return self.host.os.get('type') in self._TARGET_OS_TYPE
def send_exploit_telemetry(self, result):
from infection_monkey.telemetry.exploit_telem import ExploitTelem
ExploitTelem(self, result).send()
def report_login_attempt(self, result, user, password='', lm_hash='', ntlm_hash='', ssh_key=''):
self.exploit_attempts.append({'result': result, 'user': user, 'password': password,
'lm_hash': lm_hash, 'ntlm_hash': ntlm_hash, 'ssh_key': ssh_key})
def exploit_host(self):
self.pre_exploit()
try:
result = self._exploit_host()
finally:
self.post_exploit()
return result
def pre_exploit(self):
self.set_start_time()
def post_exploit(self):
self.set_finish_time()
@abstractmethod
def _exploit_host(self):
raise NotImplementedError()
def add_vuln_url(self, url):
self.exploit_info['vulnerable_urls'].append(url)
def add_vuln_port(self, port):
self.exploit_info['vulnerable_ports'].append(port)
def add_executed_cmd(self, cmd):
"""
Appends command to exploiter's info.
:param cmd: String of executed command. e.g. 'echo Example'
"""
powershell = True if "powershell" in cmd.lower() else False
self.exploit_info['executed_cmds'].append({'cmd': cmd, 'powershell': powershell})
from infection_monkey.exploit.win_ms08_067 import Ms08_067_Exploiter
from infection_monkey.exploit.wmiexec import WmiExploiter
from infection_monkey.exploit.smbexec import SmbExploiter
from infection_monkey.exploit.sshexec import SSHExploiter
from infection_monkey.exploit.shellshock import ShellShockExploiter
from infection_monkey.exploit.sambacry import SambaCryExploiter
from infection_monkey.exploit.elasticgroovy import ElasticGroovyExploiter
from infection_monkey.exploit.struts2 import Struts2Exploiter
from infection_monkey.exploit.weblogic import WebLogicExploiter
from infection_monkey.exploit.hadoop import HadoopExploiter
from infection_monkey.exploit.mssqlexec import MSSQLExploiter
from infection_monkey.exploit.vsftpd import VSFTPDExploiter

View File

@ -6,7 +6,7 @@ from time import sleep
import pymssql import pymssql
from common.utils.exploit_enum import ExploitType from common.utils.exploit_enum import ExploitType
from infection_monkey.exploit import HostExploiter from infection_monkey.exploit.HostExploiter import HostExploiter
from infection_monkey.exploit.tools.http_tools import MonkeyHTTPServer from infection_monkey.exploit.tools.http_tools import MonkeyHTTPServer
from infection_monkey.exploit.tools.helpers import get_monkey_dest_path, build_monkey_commandline, get_monkey_depth from infection_monkey.exploit.tools.helpers import get_monkey_dest_path, build_monkey_commandline, get_monkey_depth
from infection_monkey.model import DROPPER_ARG from infection_monkey.model import DROPPER_ARG

View File

@ -16,7 +16,7 @@ from impacket.smb3structs import SMB2_IL_IMPERSONATION, SMB2_CREATE, SMB2_FLAGS_
from impacket.smbconnection import SMBConnection from impacket.smbconnection import SMBConnection
import infection_monkey.monkeyfs as monkeyfs import infection_monkey.monkeyfs as monkeyfs
from infection_monkey.exploit import HostExploiter from infection_monkey.exploit.HostExploiter import HostExploiter
from infection_monkey.model import DROPPER_ARG from infection_monkey.model import DROPPER_ARG
from infection_monkey.network.smbfinger import SMB_SERVICE from infection_monkey.network.smbfinger import SMB_SERVICE
from infection_monkey.exploit.tools.helpers import build_monkey_commandline, get_target_monkey_by_os, get_monkey_depth from infection_monkey.exploit.tools.helpers import build_monkey_commandline, get_target_monkey_by_os, get_monkey_depth

View File

@ -7,7 +7,7 @@ from random import choice
import requests import requests
from common.utils.attack_utils import ScanStatus from common.utils.attack_utils import ScanStatus
from infection_monkey.exploit import HostExploiter from infection_monkey.exploit.HostExploiter 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.model import DROPPER_ARG from infection_monkey.model import DROPPER_ARG
from infection_monkey.exploit.shellshock_resources import CGI_FILES from infection_monkey.exploit.shellshock_resources import CGI_FILES

View File

@ -3,7 +3,7 @@ from logging import getLogger
from impacket.dcerpc.v5 import transport, scmr from impacket.dcerpc.v5 import transport, scmr
from impacket.smbconnection import SMB_DIALECT from impacket.smbconnection import SMB_DIALECT
from infection_monkey.exploit import HostExploiter from infection_monkey.exploit.HostExploiter 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

View File

@ -5,7 +5,7 @@ import time
import paramiko import paramiko
import infection_monkey.monkeyfs as monkeyfs import infection_monkey.monkeyfs as monkeyfs
from infection_monkey.exploit import HostExploiter from infection_monkey.exploit.HostExploiter 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.model import MONKEY_ARG from infection_monkey.model import MONKEY_ARG
from infection_monkey.network.tools import check_tcp_port, get_interface_to_target from infection_monkey.network.tools import check_tcp_port, get_interface_to_target

View File

@ -8,7 +8,7 @@ import socket
import time import time
from common.utils.attack_utils import ScanStatus from common.utils.attack_utils import ScanStatus
from infection_monkey.exploit import HostExploiter from infection_monkey.exploit.HostExploiter import HostExploiter
from infection_monkey.exploit.tools.helpers import get_target_monkey, build_monkey_commandline, get_monkey_depth from infection_monkey.exploit.tools.helpers import get_target_monkey, build_monkey_commandline, get_monkey_depth
from infection_monkey.exploit.tools.http_tools import HTTPTools from infection_monkey.exploit.tools.http_tools import HTTPTools
from infection_monkey.model import MONKEY_ARG, CHMOD_MONKEY, RUN_MONKEY, WGET_HTTP_UPLOAD, DOWNLOAD_TIMEOUT from infection_monkey.model import MONKEY_ARG, CHMOD_MONKEY, RUN_MONKEY, WGET_HTTP_UPLOAD, DOWNLOAD_TIMEOUT

View File

@ -3,7 +3,7 @@ import re
from posixpath import join from posixpath import join
from abc import abstractmethod from abc import abstractmethod
from infection_monkey.exploit import HostExploiter from infection_monkey.exploit.HostExploiter 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.http_tools import HTTPTools from infection_monkey.exploit.tools.http_tools import HTTPTools
from infection_monkey.model import CHECK_COMMAND, ID_STRING, GET_ARCH_LINUX, GET_ARCH_WINDOWS, BITSADMIN_CMDLINE_HTTP, \ from infection_monkey.model import CHECK_COMMAND, ID_STRING, GET_ARCH_LINUX, GET_ARCH_WINDOWS, BITSADMIN_CMDLINE_HTTP, \

View File

@ -7,7 +7,7 @@ from requests import post, exceptions
from http.server import BaseHTTPRequestHandler, HTTPServer from http.server import BaseHTTPRequestHandler, HTTPServer
from infection_monkey.exploit.web_rce import WebRCE from infection_monkey.exploit.web_rce import WebRCE
from infection_monkey.exploit import HostExploiter from infection_monkey.exploit.HostExploiter import HostExploiter
from infection_monkey.network.tools import get_interface_to_target from infection_monkey.network.tools import get_interface_to_target
from infection_monkey.network.info import get_free_tcp_port from infection_monkey.network.info import get_free_tcp_port
from http.server import BaseHTTPRequestHandler, HTTPServer from http.server import BaseHTTPRequestHandler, HTTPServer

View File

@ -19,7 +19,7 @@ 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.smbfinger 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 infection_monkey.exploit.HostExploiter import HostExploiter
LOG = getLogger(__name__) LOG = getLogger(__name__)

View File

@ -5,7 +5,7 @@ import traceback
from impacket.dcerpc.v5.rpcrt import DCERPCException from impacket.dcerpc.v5.rpcrt import DCERPCException
from infection_monkey.exploit import HostExploiter from infection_monkey.exploit.HostExploiter import HostExploiter
from infection_monkey.exploit.tools.helpers import get_target_monkey, \ from infection_monkey.exploit.tools.helpers import get_target_monkey, \
get_monkey_depth, build_monkey_commandline get_monkey_depth, build_monkey_commandline
from infection_monkey.exploit.tools.wmi_tools import AccessDeniedException from infection_monkey.exploit.tools.wmi_tools import AccessDeniedException

View File

@ -30,6 +30,7 @@ from infection_monkey.network.tools import get_interface_to_target
from infection_monkey.exploit.tools.exceptions import ExploitingVulnerableMachineError, FailedExploitationError from infection_monkey.exploit.tools.exceptions import ExploitingVulnerableMachineError, FailedExploitationError
from infection_monkey.telemetry.attack.t1106_telem import T1106Telem from infection_monkey.telemetry.attack.t1106_telem import T1106Telem
from common.utils.attack_utils import ScanStatus, UsageEnum from common.utils.attack_utils import ScanStatus, UsageEnum
from infection_monkey.exploit.HostExploiter import HostExploiter
__author__ = 'itamar' __author__ = 'itamar'
@ -144,10 +145,10 @@ class InfectionMonkey(object):
self._network.initialize() self._network.initialize()
self._exploiters = WormConfiguration.exploiter_classes
self._fingerprint = HostFinger.get_instances() self._fingerprint = HostFinger.get_instances()
self._exploiters = HostExploiter.get_classes()
if not self._keep_running or not WormConfiguration.alive: if not self._keep_running or not WormConfiguration.alive:
break break

View File

@ -0,0 +1,4 @@
from PyInstaller.utils.hooks import collect_submodules, collect_data_files
hiddenimports = collect_submodules('infection_monkey.exploit')
datas = (collect_data_files('infection_monkey.exploit', include_py_files=True))

View File

@ -4,7 +4,7 @@ import logging
from abc import ABCMeta, abstractmethod from abc import ABCMeta, abstractmethod
from os.path import dirname, basename, isfile, join from os.path import dirname, basename, isfile, join
import glob import glob
from typing import Sequence, TypeVar, Type from typing import Sequence, TypeVar, Type, Callable
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -14,7 +14,7 @@ def _get_candidate_files(base_package_file):
return [basename(f)[:-3] for f in files if isfile(f) and not f.endswith('__init__.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') PluginType = TypeVar('PluginType', bound='Plugin')
class Plugin(metaclass=ABCMeta): class Plugin(metaclass=ABCMeta):
@ -25,11 +25,11 @@ class Plugin(metaclass=ABCMeta):
raise NotImplementedError() raise NotImplementedError()
@classmethod @classmethod
def get_instances(cls) -> Sequence[Type[Plugin_type]]: def get_classes(cls) -> Sequence[Callable]:
""" """
Returns the type objects from base_package_spec. Returns the class objects from base_package_spec
base_package name and file must refer to the same package otherwise bad results base_package name and file must refer to the same package otherwise bad results
:return: A list of parent_class objects. :return: A list of parent_class classes.
""" """
objects = [] objects = []
candidate_files = _get_candidate_files(cls.base_package_file()) candidate_files = _get_candidate_files(cls.base_package_file())
@ -47,13 +47,29 @@ class Plugin(metaclass=ABCMeta):
LOG.debug("Checking if should run object {}".format(class_object.__name__)) LOG.debug("Checking if should run object {}".format(class_object.__name__))
try: try:
if class_object.should_run(class_object.__name__): if class_object.should_run(class_object.__name__):
instance = class_object() objects.append(class_object)
objects.append(instance)
LOG.debug("Added {} to list".format(class_object.__name__)) LOG.debug("Added {} to list".format(class_object.__name__))
except Exception as e: except Exception as e:
LOG.warning("Exception {} when checking if {} should run".format(str(e), class_object.__name__)) LOG.warning("Exception {} when checking if {} should run".format(str(e), class_object.__name__))
return objects return objects
@classmethod
def get_instances(cls) -> Sequence[Type[PluginType]]:
"""
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.
"""
class_objects = cls.get_classes()
instances = []
for class_object in class_objects:
try:
instance = class_object()
instances.append(instance)
except Exception as e:
LOG.warning("Exception {} when initializing {}".format(str(e), class_object.__name__))
return instances
@staticmethod @staticmethod
@abstractmethod @abstractmethod
def base_package_file(): def base_package_file():

View File

@ -0,0 +1,5 @@
from infection_monkey.utils.plugins.pluginTests.PluginTestClass import TestPlugin
class SomeDummyPlugin:
pass

View File

@ -0,0 +1,7 @@
from infection_monkey.utils.plugins.pluginTests.PluginTestClass import TestPlugin
class BadPluginInit(TestPlugin):
def __init__(self):
raise Exception("TestException")

View File

@ -0,0 +1,15 @@
from infection_monkey.utils.plugins.pluginTests.PluginTestClass import TestPlugin
class NoInheritance:
pass
class BadInit(TestPlugin):
def __init__(self):
raise Exception("TestException")
class ProperClass(TestPlugin):
pass

View File

@ -0,0 +1,22 @@
from infection_monkey.utils.plugins.plugin import Plugin
import infection_monkey.utils.plugins.pluginTests
class TestPlugin(Plugin):
classes_to_load = []
@staticmethod
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 TestPlugin.classes_to_load
@staticmethod
def base_package_file():
return infection_monkey.utils.plugins.pluginTests.__file__
@staticmethod
def base_package_name():
return infection_monkey.utils.plugins.pluginTests.__package__

View File

@ -0,0 +1,5 @@
from infection_monkey.utils.plugins.pluginTests.PluginTestClass import TestPlugin
class PluginWorking(TestPlugin):
pass

View File

@ -0,0 +1,36 @@
from unittest import TestCase
from infection_monkey.utils.plugins.pluginTests.ComboFile import BadInit, ProperClass
from infection_monkey.utils.plugins.pluginTests.PluginWorking import PluginWorking
from infection_monkey.utils.plugins.pluginTests.BadImport import SomeDummyPlugin
from infection_monkey.utils.plugins.pluginTests.BadInit import BadPluginInit
from infection_monkey.utils.plugins.pluginTests.PluginTestClass import TestPlugin
class PluginTester(TestCase):
def test_combo_file(self):
TestPlugin.classes_to_load = [BadInit.__name__, ProperClass.__name__]
to_init = TestPlugin.get_classes()
self.assertEqual(len(to_init), 2)
objects = TestPlugin.get_instances()
self.assertEqual(len(objects), 1)
def test_bad_init(self):
TestPlugin.classes_to_load = [BadPluginInit.__name__]
to_init = TestPlugin.get_classes()
self.assertEqual(len(to_init), 1)
objects = TestPlugin.get_instances()
self.assertEqual(len(objects), 0)
def test_bad_import(self):
TestPlugin.classes_to_load = [SomeDummyPlugin.__name__]
to_init = TestPlugin.get_classes()
self.assertEqual(len(to_init), 0)
def test_flow(self):
TestPlugin.classes_to_load = [PluginWorking.__name__]
to_init = TestPlugin.get_classes()
self.assertEqual(len(to_init), 1)
objects = TestPlugin.get_instances()
self.assertEqual(len(objects), 1)