Added system info collectors as plugins and the first plugin - EnvironmentCollector

This commit is contained in:
Shay Nehmad 2020-01-05 15:49:05 +02:00
parent 974e2205d1
commit c0331f84ff
11 changed files with 65 additions and 4 deletions

View File

@ -1,3 +1,7 @@
UNKNOWN = "Unknown"
ON_PREMISE = "On Premise"
AZURE = "Azure"
AWS = "AWS"
GCP = "GCP"
ALL_ENV_NAMES = [UNKNOWN, ON_PREMISE, AZURE, AWS, GCP]

View File

@ -125,6 +125,7 @@ class Configuration(object):
finger_classes = []
exploiter_classes = []
system_info_collectors_classes = ["EnvironmentCollector"]
# how many victims to look for in a single scan iteration
victims_max_find = 100

View File

@ -9,6 +9,7 @@ from infection_monkey.network.info import get_host_subnets
from infection_monkey.system_info.aws_collector import AwsCollector
from infection_monkey.system_info.azure_cred_collector import AzureCollector
from infection_monkey.system_info.netstat_collector import NetstatCollector
from system_info.system_info_collectors_handler import SystemInfoCollectorsHandler
LOG = logging.getLogger(__name__)
@ -61,12 +62,16 @@ class InfoCollector(object):
self.info = {}
def get_info(self):
# Collect all hardcoded
self.get_hostname()
self.get_process_list()
self.get_network_info()
self.get_azure_info()
self.get_aws_info()
# Collect all plugins
SystemInfoCollectorsHandler().execute_all_configured()
def get_hostname(self):
"""
Adds the fully qualified computer hostname to the system information.

View File

@ -0,0 +1,3 @@
"""
This package holds all the dynamic (plugin) collectors
"""

View File

@ -11,7 +11,7 @@ class SystemInfoCollector(Plugin):
@staticmethod
def should_run(class_name) -> bool:
return class_name in WormConfiguration.system_info_collectors
return class_name in WormConfiguration.system_info_collectors_classes
@staticmethod
def base_package_file():

View File

@ -10,7 +10,7 @@ PATH_TO_COLLECTORS = "infection_monkey.system_info.collectors."
# TODO Add new collectors to config and config schema
class SystemInfo(object):
class SystemInfoCollectorsHandler(object):
def __init__(self):
self.collectors_list = self.config_to_collectors_list()
@ -27,7 +27,8 @@ class SystemInfo(object):
LOG.error("Collector {} failed. Error info: {}".format(collector.name, e))
LOG.info("All system info collectors executed. Total {} executed, out of which {} collected successfully.".
format(len(self.collectors_list), successful_collections))
# TODO Send SystemInfoTelem()
SystemInfoTelem({"collectors": system_info_telemetry}).send()
@staticmethod
def config_to_collectors_list() -> Sequence[SystemInfoCollector]:

View File

@ -9,6 +9,7 @@ from monkey_island.cc.models.monkey_ttl import MonkeyTtl, create_monkey_ttl_docu
from monkey_island.cc.consts import DEFAULT_MONKEY_TTL_EXPIRY_DURATION_IN_SECONDS
from monkey_island.cc.models.command_control_channel import CommandControlChannel
from monkey_island.cc.utils import local_ip_addresses
from common.cloud import environment_names
MAX_MONKEYS_AMOUNT_TO_CACHE = 100
@ -42,6 +43,9 @@ class Monkey(Document):
ttl_ref = ReferenceField(MonkeyTtl)
tunnel = ReferenceField("self")
command_control_channel = EmbeddedDocumentField(CommandControlChannel)
# Environment related fields
environment = StringField(default=environment_names.UNKNOWN, choices=environment_names.ALL_ENV_NAMES)
aws_instance_id = StringField(required=False) # This field only exists when the monkey is running on an AWS
# instance. See https://github.com/guardicore/monkey/issues/426.
@ -55,7 +59,8 @@ class Monkey(Document):
raise MonkeyNotFoundError("info: {0} | id: {1}".format(ex, str(db_id)))
@staticmethod
def get_single_monkey_by_guid(monkey_guid):
# See https://www.python.org/dev/peps/pep-0484/#forward-references
def get_single_monkey_by_guid(monkey_guid) -> 'Monkey':
try:
return Monkey.objects.get(guid=monkey_guid)
except DoesNotExist as ex:

View File

@ -99,6 +99,20 @@ SCHEMA = {
}
]
},
"system_info_collectors_classes": {
"title": "System Information Collectors",
"type": "string",
"anyOf": [
{
"type": "string",
"enum": [
"EnvironmentCollector"
],
"title": "Which Environment this machine is on (on prem/cloud)",
"attack_techniques": []
},
],
},
"post_breach_acts": {
"title": "Post breach actions",
"type": "string",
@ -433,6 +447,18 @@ SCHEMA = {
"attack_techniques": ["T1003"],
"description": "Determines whether to use Mimikatz"
},
"system_info_collectors_classes": {
"title": "System info collectors",
"type": "array",
"uniqueItems": True,
"items": {
"$ref": "#/definitions/system_info_collectors_classes"
},
"default": [
"EnvironmentCollector"
],
"description": "Determines which system information collectors will collect information."
},
}
},
"life_cycle": {

View File

@ -5,6 +5,7 @@ from monkey_island.cc.models import Monkey
from monkey_island.cc.services import mimikatz_utils
from monkey_island.cc.services.node import NodeService
from monkey_island.cc.services.config import ConfigService
from monkey_island.cc.services.telemetry.processing.system_info_collectors.environment import process_environment_telemetry
from monkey_island.cc.services.telemetry.zero_trust_tests.antivirus_existence import test_antivirus_existence
from monkey_island.cc.services.wmi_handler import WMIHandler
from monkey_island.cc.encryptor import encryptor
@ -20,6 +21,7 @@ def process_system_info_telemetry(telemetry_json):
process_aws_data,
update_db_with_new_hostname,
test_antivirus_existence,
process_environment_telemetry
]
# Calling safe_process_telemetry so if one of the stages fail, we log and move on instead of failing the rest of

View File

@ -0,0 +1,14 @@
import logging
from monkey_island.cc.models.monkey import Monkey
logger = logging.getLogger(__name__)
def process_environment_telemetry(telemetry_json):
if "EnvironmentCollector" in telemetry_json["data"]["collectors"]:
env = telemetry_json["data"]["collectors"]["EnvironmentCollector"]["environment"]
relevant_monkey = Monkey.get_single_monkey_by_guid(telemetry_json['monkey_guid'])
relevant_monkey.environment = env
relevant_monkey.save()
logger.debug("Updated Monkey {} with env {}".format(str(relevant_monkey), env))