From 5d01f12d45d7fb01996e0393422a71da27ced429 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Fri, 11 Feb 2022 22:26:21 +0530 Subject: [PATCH 01/22] Common: Add PBA const and remove system info collector const for process list collection --- monkey/common/common_consts/post_breach_consts.py | 1 + monkey/common/common_consts/system_info_collectors_names.py | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/common/common_consts/post_breach_consts.py b/monkey/common/common_consts/post_breach_consts.py index 01d314482..941565767 100644 --- a/monkey/common/common_consts/post_breach_consts.py +++ b/monkey/common/common_consts/post_breach_consts.py @@ -9,3 +9,4 @@ POST_BREACH_TIMESTOMPING = "Modify files' timestamps" POST_BREACH_SIGNED_SCRIPT_PROXY_EXEC = "Signed script proxy execution" POST_BREACH_ACCOUNT_DISCOVERY = "Account discovery" POST_BREACH_CLEAR_CMD_HISTORY = "Clear command history" +POST_BREACH_PROCESS_LIST_COLLECTION = "Process list collection" diff --git a/monkey/common/common_consts/system_info_collectors_names.py b/monkey/common/common_consts/system_info_collectors_names.py index 075d6ff45..711843b19 100644 --- a/monkey/common/common_consts/system_info_collectors_names.py +++ b/monkey/common/common_consts/system_info_collectors_names.py @@ -1,2 +1 @@ -PROCESS_LIST_COLLECTOR = "ProcessListCollector" MIMIKATZ_COLLECTOR = "MimikatzCollector" From 4839f099a449440c262e5bd60329b5a03a104fa3 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Fri, 11 Feb 2022 22:30:38 +0530 Subject: [PATCH 02/22] Agent: Add process list collection PBA Instead of a system info collector, it is now a PBA. --- .../actions/collect_processes_list.py} | 30 ++++++++++--------- monkey/infection_monkey/puppet/mock_puppet.py | 4 +++ 2 files changed, 20 insertions(+), 14 deletions(-) rename monkey/infection_monkey/{system_info/collectors/process_list_collector.py => post_breach/actions/collect_processes_list.py} (58%) diff --git a/monkey/infection_monkey/system_info/collectors/process_list_collector.py b/monkey/infection_monkey/post_breach/actions/collect_processes_list.py similarity index 58% rename from monkey/infection_monkey/system_info/collectors/process_list_collector.py rename to monkey/infection_monkey/post_breach/actions/collect_processes_list.py index 12cdf8aeb..c83faf9b3 100644 --- a/monkey/infection_monkey/system_info/collectors/process_list_collector.py +++ b/monkey/infection_monkey/post_breach/actions/collect_processes_list.py @@ -2,31 +2,33 @@ import logging import psutil -from common.common_consts.system_info_collectors_names import PROCESS_LIST_COLLECTOR -from infection_monkey.system_info.system_info_collector import SystemInfoCollector +from common.common_consts.post_breach_consts import POST_BREACH_PROCESS_LIST_COLLECTION +from infection_monkey.post_breach.pba import PBA logger = logging.getLogger(__name__) # Linux doesn't have WindowsError +applicable_exceptions = None try: - WindowsError + applicable_exceptions = (psutil.AccessDenied, WindowsError) except NameError: - # noinspection PyShadowingBuiltins - WindowsError = psutil.AccessDenied + applicable_exceptions = psutil.AccessDenied -class ProcessListCollector(SystemInfoCollector): +class ProcessListCollection(PBA): def __init__(self): - super().__init__(name=PROCESS_LIST_COLLECTOR) + super().__init__(POST_BREACH_PROCESS_LIST_COLLECTION) - def collect(self) -> dict: + def run(self): """ - Adds process information from the host to the system information. + Collects process information from the host. Currently lists process name, ID, parent ID, command line and the full image path of each process. """ logger.debug("Reading process list") + processes = {} + success_state = False for process in psutil.process_iter(): try: processes[process.pid] = { @@ -36,10 +38,10 @@ class ProcessListCollector(SystemInfoCollector): "cmdline": " ".join(process.cmdline()), "full_image_path": process.exe(), } - except (psutil.AccessDenied, WindowsError): - # we may be running as non root and some processes are impossible to acquire in - # Windows/Linux. - # In this case we'll just add what we know. + success_state = True + except applicable_exceptions: + # We may be running as non root and some processes are impossible to acquire in + # Windows/Linux. In this case, we'll just add what we know. processes[process.pid] = { "name": "null", "pid": process.pid, @@ -49,4 +51,4 @@ class ProcessListCollector(SystemInfoCollector): } continue - return {"process_list": processes} + return self.command, [str(processes), success_state] diff --git a/monkey/infection_monkey/puppet/mock_puppet.py b/monkey/infection_monkey/puppet/mock_puppet.py index ec3984685..904ece2e5 100644 --- a/monkey/infection_monkey/puppet/mock_puppet.py +++ b/monkey/infection_monkey/puppet/mock_puppet.py @@ -12,6 +12,7 @@ from infection_monkey.i_puppet import ( PortStatus, PostBreachData, ) +from infection_monkey.post_breach.actions.collect_processes_list import ProcessListCollection DOT_1 = "10.0.0.1" DOT_2 = "10.0.0.2" @@ -158,6 +159,9 @@ class MockPuppet(IPuppet): if name == "AccountDiscovery": return PostBreachData("pba command 1", ["pba result 1", True]) + elif name == "ProcessListCollection": + cmd, result = ProcessListCollection().run() + return PostBreachData(cmd, result) else: return PostBreachData("pba command 2", ["pba result 2", False]) From a8059f021aa182033cccd32ae043689ac544f4aa Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Fri, 11 Feb 2022 22:36:37 +0530 Subject: [PATCH 03/22] Island: Change config schema for process list collection --- .../config_schema/definitions/post_breach_actions.py | 8 ++++++++ .../definitions/system_info_collector_classes.py | 9 --------- monkey/monkey_island/cc/services/config_schema/monkey.py | 3 +-- .../system_info_telemetry_dispatcher.py | 5 +---- 4 files changed, 10 insertions(+), 15 deletions(-) diff --git a/monkey/monkey_island/cc/services/config_schema/definitions/post_breach_actions.py b/monkey/monkey_island/cc/services/config_schema/definitions/post_breach_actions.py index 7d62ac36e..e76b2c254 100644 --- a/monkey/monkey_island/cc/services/config_schema/definitions/post_breach_actions.py +++ b/monkey/monkey_island/cc/services/config_schema/definitions/post_breach_actions.py @@ -94,5 +94,13 @@ POST_BREACH_ACTIONS = { "info": "Attempts to clear the command history.", "attack_techniques": ["T1146"], }, + { + "type": "string", + "enum": ["ProcessListCollection"], + "title": "Process List Collector", + "safe": True, + "info": "Collects a list of running processes on the machine.", + "attack_techniques": ["T1082"], + }, ], } diff --git a/monkey/monkey_island/cc/services/config_schema/definitions/system_info_collector_classes.py b/monkey/monkey_island/cc/services/config_schema/definitions/system_info_collector_classes.py index 5e446513c..2f8c38ee8 100644 --- a/monkey/monkey_island/cc/services/config_schema/definitions/system_info_collector_classes.py +++ b/monkey/monkey_island/cc/services/config_schema/definitions/system_info_collector_classes.py @@ -1,6 +1,5 @@ from common.common_consts.system_info_collectors_names import ( MIMIKATZ_COLLECTOR, - PROCESS_LIST_COLLECTOR, ) SYSTEM_INFO_COLLECTOR_CLASSES = { @@ -16,13 +15,5 @@ SYSTEM_INFO_COLLECTOR_CLASSES = { "info": "Collects credentials from Windows credential manager.", "attack_techniques": ["T1003", "T1005"], }, - { - "type": "string", - "enum": [PROCESS_LIST_COLLECTOR], - "title": "Process List Collector", - "safe": True, - "info": "Collects a list of running processes on the machine.", - "attack_techniques": ["T1082"], - }, ], } diff --git a/monkey/monkey_island/cc/services/config_schema/monkey.py b/monkey/monkey_island/cc/services/config_schema/monkey.py index 80719d4c2..ba5c88661 100644 --- a/monkey/monkey_island/cc/services/config_schema/monkey.py +++ b/monkey/monkey_island/cc/services/config_schema/monkey.py @@ -1,6 +1,5 @@ from common.common_consts.system_info_collectors_names import ( MIMIKATZ_COLLECTOR, - PROCESS_LIST_COLLECTOR, ) MONKEY = { @@ -71,6 +70,7 @@ MONKEY = { "ScheduleJobs", "Timestomping", "AccountDiscovery", + "ProcessListCollection", ], }, }, @@ -85,7 +85,6 @@ MONKEY = { "uniqueItems": True, "items": {"$ref": "#/definitions/system_info_collector_classes"}, "default": [ - PROCESS_LIST_COLLECTOR, MIMIKATZ_COLLECTOR, ], }, diff --git a/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py b/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py index 13e0a9298..9df25a677 100644 --- a/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py +++ b/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py @@ -1,16 +1,13 @@ import logging import typing -from common.common_consts.system_info_collectors_names import PROCESS_LIST_COLLECTOR from monkey_island.cc.services.telemetry.zero_trust_checks.antivirus_existence import ( check_antivirus_existence, ) logger = logging.getLogger(__name__) -SYSTEM_INFO_COLLECTOR_TO_TELEMETRY_PROCESSORS = { - PROCESS_LIST_COLLECTOR: [check_antivirus_existence], -} +SYSTEM_INFO_COLLECTOR_TO_TELEMETRY_PROCESSORS = {} class SystemInfoTelemetryDispatcher(object): From 6ab62c6f56f6135063b9248dce212c91e7e34b15 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Fri, 11 Feb 2022 23:14:50 +0530 Subject: [PATCH 04/22] Docs: Change adding system info collectors' documentation to refer to existing files --- docs/content/development/adding-system-info-collectors.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/content/development/adding-system-info-collectors.md b/docs/content/development/adding-system-info-collectors.md index e865bcfd6..353bd6c0d 100644 --- a/docs/content/development/adding-system-info-collectors.md +++ b/docs/content/development/adding-system-info-collectors.md @@ -39,7 +39,7 @@ class MyNewCollector(SystemInfoCollector): #### Implementation -Override the `collect` method with your own implementation. See the `process_list_collector.py` System Info Collector for reference. You can log during collection as well. +Override the `collect` method with your own implementation. See the `aws_collector.py` System Info Collector for reference. You can log during collection as well. ### Modify the Monkey Island @@ -59,7 +59,7 @@ You'll need to add your Sytem Info Collector to the `monkey_island/cc/services/c "enum": [ "HostnameCollector" ], - "title": "Which Environment this machine is on (on prem/cloud)", + "title": "Which environment this machine is on (on prem/cloud)", "attack_techniques": [] }, { <================================= @@ -96,6 +96,6 @@ Also, you can add the System Info Collector to be used by default by adding it t #### Telemetry processing -1. Add a process function under `monkey_island/cc/telemetry/processing/system_info_collectors/{DATA_NAME_HERE}.py`. The function should parse the System Info Collector's result. See `processing/system_info_collectors/environment.py` for example. +1. Add a process function under `monkey_island/cc/telemetry/processing/system_info_collectors/{DATA_NAME_HERE}.py`. The function should parse the System Info Collector's result. See `processing/system_info_collectors/aws.py` for example. 2. Add that function to `SYSTEM_INFO_COLLECTOR_TO_TELEMETRY_PROCESSORS` under `monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py`. From fcfa01223dc9d3e90c36de15bca29030b8280195 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Fri, 11 Feb 2022 23:15:59 +0530 Subject: [PATCH 05/22] Project: Remove ProcessListCollector from Vulture allowlist --- vulture_allowlist.py | 1 - 1 file changed, 1 deletion(-) diff --git a/vulture_allowlist.py b/vulture_allowlist.py index 2d8163f29..dde79f032 100644 --- a/vulture_allowlist.py +++ b/vulture_allowlist.py @@ -98,7 +98,6 @@ Timestomping # unused class (monkey/infection_monkey/post_breach/actions/timest SignedScriptProxyExecution # unused class (monkey/infection_monkey/post_breach/actions/use_signed_scripts.py:15) EnvironmentCollector # unused class (monkey/infection_monkey/system_info/collectors/environment_collector.py:19) HostnameCollector # unused class (monkey/infection_monkey/system_info/collectors/hostname_collector.py:10) -ProcessListCollector # unused class (monkey/infection_monkey/system_info/collectors/process_list_collector.py:18) _.coinit_flags # unused attribute (monkey/infection_monkey/system_info/windows_info_collector.py:11) _.representations # unused attribute (monkey/monkey_island/cc/app.py:180) _.log_message # unused method (monkey/infection_monkey/transport/http.py:188) From 7cee2e49a21112a0ed91cfcfea0f77bab943a36c Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 14 Feb 2022 12:35:01 +0530 Subject: [PATCH 06/22] Agent: Improve exception catching logic in process list collection PBA --- .../post_breach/actions/collect_processes_list.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/monkey/infection_monkey/post_breach/actions/collect_processes_list.py b/monkey/infection_monkey/post_breach/actions/collect_processes_list.py index c83faf9b3..7e9e1b059 100644 --- a/monkey/infection_monkey/post_breach/actions/collect_processes_list.py +++ b/monkey/infection_monkey/post_breach/actions/collect_processes_list.py @@ -8,11 +8,11 @@ from infection_monkey.post_breach.pba import PBA logger = logging.getLogger(__name__) # Linux doesn't have WindowsError -applicable_exceptions = None +applicable_exceptions = psutil.AccessDenied try: applicable_exceptions = (psutil.AccessDenied, WindowsError) except NameError: - applicable_exceptions = psutil.AccessDenied + pass class ProcessListCollection(PBA): From 417f40d62d49c4fd6c27a711d8edbebe0a9bbadd Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 14 Feb 2022 17:13:59 +0530 Subject: [PATCH 07/22] Agent: Add TODOs in automated master and process collection list PBA --- monkey/infection_monkey/master/automated_master.py | 3 +++ .../post_breach/actions/collect_processes_list.py | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/monkey/infection_monkey/master/automated_master.py b/monkey/infection_monkey/master/automated_master.py index 28994d673..c29e3c6f3 100644 --- a/monkey/infection_monkey/master/automated_master.py +++ b/monkey/infection_monkey/master/automated_master.py @@ -176,6 +176,9 @@ class AutomatedMaster(IMaster): ) def _run_pba(self, pba: Tuple[str, Dict]): + # TODO: This is the class's name right now. We need `display_name` (see the + # ProcessListCollection PBA). This is shown in the Security report as the PBA + # name and is checked against in the T1082's mongo query in the ATT&CK report. name = pba[0] options = pba[1] diff --git a/monkey/infection_monkey/post_breach/actions/collect_processes_list.py b/monkey/infection_monkey/post_breach/actions/collect_processes_list.py index 7e9e1b059..cae3658c4 100644 --- a/monkey/infection_monkey/post_breach/actions/collect_processes_list.py +++ b/monkey/infection_monkey/post_breach/actions/collect_processes_list.py @@ -16,6 +16,9 @@ except NameError: class ProcessListCollection(PBA): + # TODO: (?) Move all PBA consts into their classes + display_name = POST_BREACH_PROCESS_LIST_COLLECTION + def __init__(self): super().__init__(POST_BREACH_PROCESS_LIST_COLLECTION) @@ -51,4 +54,4 @@ class ProcessListCollection(PBA): } continue - return self.command, [str(processes), success_state] + return self.command, (str(processes), success_state) From 547d4fce54712da9f43ba1601dca69f834e81632 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 14 Feb 2022 17:15:45 +0530 Subject: [PATCH 08/22] Island: Modify T1082's reporting to get data from process collection PBA too --- .../attack/technique_reports/T1082.py | 58 ++++++++++++++----- 1 file changed, 42 insertions(+), 16 deletions(-) diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1082.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1082.py index ad1bc6281..1af89e7f7 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1082.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1082.py @@ -1,3 +1,4 @@ +from common.common_consts.post_breach_consts import POST_BREACH_PROCESS_LIST_COLLECTION from common.utils.attack_utils import ScanStatus from monkey_island.cc.database import mongo from monkey_island.cc.services.attack.technique_reports import AttackTechnique @@ -9,14 +10,16 @@ class T1082(AttackTechnique): unscanned_msg = "Monkey didn't gather any system info on the network." scanned_msg = "" used_msg = "Monkey gathered system info from machines in the network." + # TODO: Remove the second item from this list after the TODO in `_run_pba()` in + # `automated_master.py` is resolved. + pba_names = [POST_BREACH_PROCESS_LIST_COLLECTION, "ProcessListCollection"] - query = [ + query_for_system_info_collectors = [ {"$match": {"telem_category": "system_info", "data.network_info": {"$exists": True}}}, { "$project": { "machine": {"hostname": "$data.hostname", "ips": "$data.network_info.networks"}, "aws": "$data.aws", - "process_list": "$data.process_list", "ssh_info": "$data.ssh_info", "azure_info": "$data.Azure", } @@ -30,15 +33,6 @@ class T1082(AttackTechnique): "used": {"$and": [{"$gt": ["$aws", {}]}]}, "name": {"$literal": "Amazon Web Services info"}, }, - { - "used": { - "$and": [ - {"$ifNull": ["$process_list", False]}, - {"$gt": ["$process_list", {}]}, - ] - }, - "name": {"$literal": "Running process list"}, - }, { "used": { "$and": [{"$ifNull": ["$ssh_info", False]}, {"$ne": ["$ssh_info", []]}] @@ -62,19 +56,51 @@ class T1082(AttackTechnique): {"$replaceRoot": {"newRoot": "$_id"}}, ] + query_for_pbas = [ + { + "$match": { + "$and": [ + {"telem_category": "post_breach"}, + {"$or": [{"data.name": pba_name} for pba_name in pba_names]}, + {"$or": [{"data.os": os} for os in relevant_systems]}, + ] + } + }, + { + "$project": { + "_id": 0, + "machine": { + "hostname": {"$arrayElemAt": ["$data.hostname", 0]}, + "ips": [{"$arrayElemAt": ["$data.ip", 0]}], + }, + "collections": [ + { + "used": {"$arrayElemAt": [{"$arrayElemAt": ["$data.result", 0]}, 1]}, + "name": {"$literal": "List of running processes"}, + } + ], + } + }, + ] + @staticmethod def get_report_data(): def get_technique_status_and_data(): - system_info = list(mongo.db.telemetry.aggregate(T1082.query)) - if system_info: + system_info_data = list( + mongo.db.telemetry.aggregate(T1082.query_for_system_info_collectors) + ) + pba_data = list(mongo.db.telemetry.aggregate(T1082.query_for_pbas)) + technique_data = system_info_data + pba_data + + if technique_data: status = ScanStatus.USED.value else: status = ScanStatus.UNSCANNED.value - return (status, system_info) + return (status, technique_data) - status, system_info = get_technique_status_and_data() + status, technique_data = get_technique_status_and_data() data = {"title": T1082.technique_title()} - data.update({"system_info": system_info}) + data.update({"technique_data": technique_data}) data.update(T1082.get_mitigation_by_status(status)) data.update(T1082.get_message_and_status(status)) From 5ab7bc520e42c53564b31ab88a3a2d8f5e5e0121 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 14 Feb 2022 17:16:41 +0530 Subject: [PATCH 09/22] UI: Modify variable names in T1082.js as per changes to backend --- .../cc/ui/src/components/attack/techniques/T1082.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1082.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1082.js index 790cb8271..a82adcf09 100644 --- a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1082.js +++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1082.js @@ -37,9 +37,9 @@ class T1082 extends React.Component { {this.props.data.status === ScanStatus.USED ? : ''} From afa7d4fca41d63eeeb729cddb3e9dba0edb10196 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 14 Feb 2022 19:18:39 +0530 Subject: [PATCH 10/22] Agent: Modify process list collection PBA to return dict of processes instead of string --- .../post_breach/actions/collect_processes_list.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/infection_monkey/post_breach/actions/collect_processes_list.py b/monkey/infection_monkey/post_breach/actions/collect_processes_list.py index cae3658c4..181fd5988 100644 --- a/monkey/infection_monkey/post_breach/actions/collect_processes_list.py +++ b/monkey/infection_monkey/post_breach/actions/collect_processes_list.py @@ -54,4 +54,4 @@ class ProcessListCollection(PBA): } continue - return self.command, (str(processes), success_state) + return self.command, (processes, success_state) From ff6fd5297997d29a052716a270d3c4f50773776f Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 14 Feb 2022 19:19:16 +0530 Subject: [PATCH 11/22] UI: Modify how process list collection PBA is shown in Security report --- .../report-components/security/PostBreachParser.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/security/PostBreachParser.js b/monkey/monkey_island/cc/ui/src/components/report-components/security/PostBreachParser.js index 4bb420f71..843ca89dd 100644 --- a/monkey/monkey_island/cc/ui/src/components/report-components/security/PostBreachParser.js +++ b/monkey/monkey_island/cc/ui/src/components/report-components/security/PostBreachParser.js @@ -5,6 +5,10 @@ export default function parsePbaResults(results) { const SHELL_STARTUP_NAME = 'Modify shell startup file'; const CMD_HISTORY_NAME = 'Clear command history'; +// TODO: Remove line 10 and un-comment line 11 after the TODO in `_run_pba()` in +// `automated_master.py` is resolved. +const PROCESS_LIST_COLLECTION = 'ProcessListCollection'; +// const PROCESS_LIST_COLLECTION = 'Process list collection'; const multipleResultsPbas = [SHELL_STARTUP_NAME, CMD_HISTORY_NAME] @@ -41,10 +45,17 @@ function aggregateMultipleResultsPba(results) { } } + function modifyProcessListCollectionResult(result) { + result[0] = "Found " + Object.keys(result[0]).length.toString() + " running processes"; + } + // check for pbas with multiple results and aggregate their results - for (let i = 0; i < results.length; i++) + for (let i = 0; i < results.length; i++) { if (multipleResultsPbas.includes(results[i].name)) aggregateResults(results[i]); + if (results[i].name === PROCESS_LIST_COLLECTION) + modifyProcessListCollectionResult(results[i].result); + } // if no modifications were made to the results, i.e. if no pbas had mutiple results, return `results` as it is let noResultsModifications = true; From 9d3931c380e5adacf59dfd3f572d148b77d9e35a Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 16 Feb 2022 16:38:38 +0530 Subject: [PATCH 12/22] Island: Fix T1082's mongo query to get the right data --- .../attack/technique_reports/T1082.py | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1082.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1082.py index 1af89e7f7..1fa81f4ed 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1082.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1082.py @@ -8,7 +8,7 @@ class T1082(AttackTechnique): tech_id = "T1082" relevant_systems = ["Linux", "Windows"] unscanned_msg = "Monkey didn't gather any system info on the network." - scanned_msg = "" + scanned_msg = "Monkey tried gathering system info on the network but failed." used_msg = "Monkey gathered system info from machines in the network." # TODO: Remove the second item from this list after the TODO in `_run_pba()` in # `automated_master.py` is resolved. @@ -89,14 +89,27 @@ class T1082(AttackTechnique): system_info_data = list( mongo.db.telemetry.aggregate(T1082.query_for_system_info_collectors) ) - pba_data = list(mongo.db.telemetry.aggregate(T1082.query_for_pbas)) - technique_data = system_info_data + pba_data + system_info_status = ( + ScanStatus.USED.value if system_info_data else ScanStatus.UNSCANNED.value + ) - if technique_data: - status = ScanStatus.USED.value - else: - status = ScanStatus.UNSCANNED.value - return (status, technique_data) + pba_data = list(mongo.db.telemetry.aggregate(T1082.query_for_pbas)) + successful_PBAs = mongo.db.telemetry.count( + { + "$and": [ + {"$or": [{"data.name": pba_name} for pba_name in T1082.pba_names]}, + {"$or": [{"data.os": os} for os in T1082.relevant_systems]}, + {"data.result.1": True}, + ] + } + ) + pba_status = ScanStatus.USED.value if successful_PBAs else ScanStatus.SCANNED.value + + technique_data = system_info_data + pba_data + # ScanStatus values are in order of precedence; used > scanned > unscanned + technique_status = max(system_info_status, pba_status) + + return (technique_status, technique_data) status, technique_data = get_technique_status_and_data() data = {"title": T1082.technique_title()} From e674f9e0c021e82d7beed2251b45024f3c18d17d Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 16 Feb 2022 16:41:00 +0530 Subject: [PATCH 13/22] Island: Move antivirus check for ZT report from system info processing to PBA processing --- .../telemetry/processing/post_breach.py | 17 ++++++++++++++++- .../system_info_telemetry_dispatcher.py | 4 +--- .../zero_trust_checks/antivirus_existence.py | 7 ++----- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/monkey/monkey_island/cc/services/telemetry/processing/post_breach.py b/monkey/monkey_island/cc/services/telemetry/processing/post_breach.py index 5506ff54d..3e02971de 100644 --- a/monkey/monkey_island/cc/services/telemetry/processing/post_breach.py +++ b/monkey/monkey_island/cc/services/telemetry/processing/post_breach.py @@ -1,8 +1,14 @@ import copy -from common.common_consts.post_breach_consts import POST_BREACH_COMMUNICATE_AS_BACKDOOR_USER +from common.common_consts.post_breach_consts import ( + POST_BREACH_COMMUNICATE_AS_BACKDOOR_USER, + POST_BREACH_PROCESS_LIST_COLLECTION, +) from monkey_island.cc.database import mongo from monkey_island.cc.models import Monkey +from monkey_island.cc.services.telemetry.zero_trust_checks.antivirus_existence import ( + check_antivirus_existence, +) from monkey_island.cc.services.telemetry.zero_trust_checks.communicate_as_backdoor_user import ( check_new_user_communication, ) @@ -17,8 +23,17 @@ def process_communicate_as_backdoor_user_telemetry(telemetry_json): check_new_user_communication(current_monkey, success, message) +def process_process_list_collection_telemetry(telemetry_json): + current_monkey = Monkey.get_single_monkey_by_guid(telemetry_json["monkey_guid"]) + check_antivirus_existence(telemetry_json, current_monkey) + + POST_BREACH_TELEMETRY_PROCESSING_FUNCS = { POST_BREACH_COMMUNICATE_AS_BACKDOOR_USER: process_communicate_as_backdoor_user_telemetry, + # TODO: Remove line 31 and un-comment line 32 after the TODO in `_run_pba()` in + # `automated_master.py` is resolved. + "ProcessListCollection": process_process_list_collection_telemetry, + # POST_BREACH_PROCESS_LIST_COLLECTION: process_process_list_collection_telemetry, } diff --git a/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py b/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py index 9df25a677..7faae8eb2 100644 --- a/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py +++ b/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py @@ -1,12 +1,10 @@ import logging import typing -from monkey_island.cc.services.telemetry.zero_trust_checks.antivirus_existence import ( - check_antivirus_existence, -) logger = logging.getLogger(__name__) + SYSTEM_INFO_COLLECTOR_TO_TELEMETRY_PROCESSORS = {} diff --git a/monkey/monkey_island/cc/services/telemetry/zero_trust_checks/antivirus_existence.py b/monkey/monkey_island/cc/services/telemetry/zero_trust_checks/antivirus_existence.py index d2f154a9e..4e8a86fb4 100644 --- a/monkey/monkey_island/cc/services/telemetry/zero_trust_checks/antivirus_existence.py +++ b/monkey/monkey_island/cc/services/telemetry/zero_trust_checks/antivirus_existence.py @@ -1,7 +1,6 @@ import json import common.common_consts.zero_trust_consts as zero_trust_consts -from monkey_island.cc.models import Monkey from monkey_island.cc.models.zero_trust.event import Event from monkey_island.cc.services.telemetry.zero_trust_checks.known_anti_viruses import ( ANTI_VIRUS_KNOWN_PROCESS_NAMES, @@ -11,9 +10,7 @@ from monkey_island.cc.services.zero_trust.monkey_findings.monkey_zt_finding_serv ) -def check_antivirus_existence(process_list_json, monkey_guid): - current_monkey = Monkey.get_single_monkey_by_guid(monkey_guid) - +def check_antivirus_existence(telemetry_json, current_monkey): process_list_event = Event.create_event( title="Process list", message="Monkey on {} scanned the process list".format(current_monkey.hostname), @@ -21,7 +18,7 @@ def check_antivirus_existence(process_list_json, monkey_guid): ) events = [process_list_event] - av_processes = filter_av_processes(process_list_json["process_list"]) + av_processes = filter_av_processes(telemetry_json["data"]["result"][0]) for process in av_processes: events.append( From 123f0aab16aaa1c33836f847d329d5973c96a83b Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 16 Feb 2022 16:45:22 +0530 Subject: [PATCH 14/22] Changelog: Add entry for process list collection PBA --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b51cc9321..c5e2d74ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ Changelog](https://keepachangelog.com/en/1.0.0/). - The setup procedure for custom server_config.json files to be simpler. #1576 - The order and content of Monkey Island's initialization logging to give clearer instructions to the user and avoid confusion. #1684 +- The process list collection system info collector to now be a post-breach action. #1697 ### Removed - VSFTPD exploiter. #1533 From 44a7b7e14808df7f57471f8ca1f0c7857e912670 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 16 Feb 2022 16:53:45 +0530 Subject: [PATCH 15/22] Island: Fix TODO comment in monkey_island/cc/services/telemetry/processing/post_breach.py --- .../cc/services/telemetry/processing/post_breach.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/monkey_island/cc/services/telemetry/processing/post_breach.py b/monkey/monkey_island/cc/services/telemetry/processing/post_breach.py index 3e02971de..5792ee947 100644 --- a/monkey/monkey_island/cc/services/telemetry/processing/post_breach.py +++ b/monkey/monkey_island/cc/services/telemetry/processing/post_breach.py @@ -30,7 +30,7 @@ def process_process_list_collection_telemetry(telemetry_json): POST_BREACH_TELEMETRY_PROCESSING_FUNCS = { POST_BREACH_COMMUNICATE_AS_BACKDOOR_USER: process_communicate_as_backdoor_user_telemetry, - # TODO: Remove line 31 and un-comment line 32 after the TODO in `_run_pba()` in + # TODO: Remove the line below and un-comment the next one after the TODO in `_run_pba()` in # `automated_master.py` is resolved. "ProcessListCollection": process_process_list_collection_telemetry, # POST_BREACH_PROCESS_LIST_COLLECTION: process_process_list_collection_telemetry, From 32cad45676cda45db822cf476758c572e88dcecc Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 16 Feb 2022 16:56:37 +0530 Subject: [PATCH 16/22] Island: Refactor post breach telemetry processing functions --- .../cc/services/telemetry/processing/post_breach.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/monkey/monkey_island/cc/services/telemetry/processing/post_breach.py b/monkey/monkey_island/cc/services/telemetry/processing/post_breach.py index 5792ee947..8392d3613 100644 --- a/monkey/monkey_island/cc/services/telemetry/processing/post_breach.py +++ b/monkey/monkey_island/cc/services/telemetry/processing/post_breach.py @@ -16,15 +16,13 @@ from monkey_island.cc.services.telemetry.zero_trust_checks.communicate_as_backdo EXECUTION_WITHOUT_OUTPUT = "(PBA execution produced no output)" -def process_communicate_as_backdoor_user_telemetry(telemetry_json): - current_monkey = Monkey.get_single_monkey_by_guid(telemetry_json["monkey_guid"]) +def process_communicate_as_backdoor_user_telemetry(telemetry_json, current_monkey): message = telemetry_json["data"]["result"][0] success = telemetry_json["data"]["result"][1] check_new_user_communication(current_monkey, success, message) -def process_process_list_collection_telemetry(telemetry_json): - current_monkey = Monkey.get_single_monkey_by_guid(telemetry_json["monkey_guid"]) +def process_process_list_collection_telemetry(telemetry_json, current_monkey): check_antivirus_existence(telemetry_json, current_monkey) @@ -59,7 +57,10 @@ def process_post_breach_telemetry(telemetry_json): post_breach_action_name = telemetry_json["data"]["name"] if post_breach_action_name in POST_BREACH_TELEMETRY_PROCESSING_FUNCS: - POST_BREACH_TELEMETRY_PROCESSING_FUNCS[post_breach_action_name](telemetry_json) + current_monkey = Monkey.get_single_monkey_by_guid(telemetry_json["monkey_guid"]) + POST_BREACH_TELEMETRY_PROCESSING_FUNCS[post_breach_action_name]( + telemetry_json, current_monkey + ) telemetry_json["data"] = convert_telem_data_to_list(telemetry_json["data"]) From 3017e6b250fd9b09308a9f6dd9b83dd1f50b9e9c Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 16 Feb 2022 17:25:36 +0530 Subject: [PATCH 17/22] UT: Remove references to process list collection system info collector in test data --- .../data_for_tests/monkey_configs/automated_master_config.json | 1 - monkey/tests/data_for_tests/monkey_configs/flat_config.json | 1 - .../data_for_tests/monkey_configs/monkey_config_standard.json | 2 -- 3 files changed, 4 deletions(-) diff --git a/monkey/tests/data_for_tests/monkey_configs/automated_master_config.json b/monkey/tests/data_for_tests/monkey_configs/automated_master_config.json index e7290d822..5556d8c23 100644 --- a/monkey/tests/data_for_tests/monkey_configs/automated_master_config.json +++ b/monkey/tests/data_for_tests/monkey_configs/automated_master_config.json @@ -104,7 +104,6 @@ } }, "system_info_collector_classes": [ - "ProcessListCollector", "MimikatzCollector" ] } diff --git a/monkey/tests/data_for_tests/monkey_configs/flat_config.json b/monkey/tests/data_for_tests/monkey_configs/flat_config.json index 563eb21d5..5693307f2 100644 --- a/monkey/tests/data_for_tests/monkey_configs/flat_config.json +++ b/monkey/tests/data_for_tests/monkey_configs/flat_config.json @@ -101,7 +101,6 @@ "smb_service_name": "InfectionMonkey", "subnet_scan_list": ["192.168.1.50", "192.168.56.0/24", "10.0.33.0/30"], "system_info_collector_classes": [ - "ProcessListCollector", "MimikatzCollector" ], "tcp_scan_timeout": 3000, diff --git a/monkey/tests/data_for_tests/monkey_configs/monkey_config_standard.json b/monkey/tests/data_for_tests/monkey_configs/monkey_config_standard.json index 69e6f4416..38c51042d 100644 --- a/monkey/tests/data_for_tests/monkey_configs/monkey_config_standard.json +++ b/monkey/tests/data_for_tests/monkey_configs/monkey_config_standard.json @@ -146,9 +146,7 @@ }, "system_info": { "system_info_collector_classes": [ - "environmentcollector", "hostnamecollector", - "processlistcollector", "mimikatzcollector" ] } From 7787984f4a5eaddf7657b2f2f281123364c76d6b Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 16 Feb 2022 17:31:40 +0530 Subject: [PATCH 18/22] BB: Remove ProcessListCollector from BB config templates --- envs/monkey_zoo/blackbox/config_templates/smb_mimikatz.py | 1 - envs/monkey_zoo/blackbox/config_templates/wmi_mimikatz.py | 1 - 2 files changed, 2 deletions(-) diff --git a/envs/monkey_zoo/blackbox/config_templates/smb_mimikatz.py b/envs/monkey_zoo/blackbox/config_templates/smb_mimikatz.py index 37b452801..25003eb20 100644 --- a/envs/monkey_zoo/blackbox/config_templates/smb_mimikatz.py +++ b/envs/monkey_zoo/blackbox/config_templates/smb_mimikatz.py @@ -17,7 +17,6 @@ class SmbMimikatz(ConfigTemplate): "internal.network.tcp_scanner.HTTP_PORTS": [], "internal.network.tcp_scanner.tcp_target_ports": [445], "monkey.system_info.system_info_collector_classes": [ - "ProcessListCollector", "MimikatzCollector", ], } diff --git a/envs/monkey_zoo/blackbox/config_templates/wmi_mimikatz.py b/envs/monkey_zoo/blackbox/config_templates/wmi_mimikatz.py index 7ff3ab84f..430547a73 100644 --- a/envs/monkey_zoo/blackbox/config_templates/wmi_mimikatz.py +++ b/envs/monkey_zoo/blackbox/config_templates/wmi_mimikatz.py @@ -16,7 +16,6 @@ class WmiMimikatz(ConfigTemplate): "internal.network.tcp_scanner.HTTP_PORTS": [], "internal.network.tcp_scanner.tcp_target_ports": [135], "monkey.system_info.system_info_collector_classes": [ - "ProcessListCollector", "MimikatzCollector", ], } From a234713e087c89aad08dc1b62078ee0da06f7839 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Thu, 17 Feb 2022 16:55:29 +0530 Subject: [PATCH 19/22] Common: Reword process list collection PBA constant --- monkey/common/common_consts/post_breach_consts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/common/common_consts/post_breach_consts.py b/monkey/common/common_consts/post_breach_consts.py index 941565767..19b6c4f19 100644 --- a/monkey/common/common_consts/post_breach_consts.py +++ b/monkey/common/common_consts/post_breach_consts.py @@ -9,4 +9,4 @@ POST_BREACH_TIMESTOMPING = "Modify files' timestamps" POST_BREACH_SIGNED_SCRIPT_PROXY_EXEC = "Signed script proxy execution" POST_BREACH_ACCOUNT_DISCOVERY = "Account discovery" POST_BREACH_CLEAR_CMD_HISTORY = "Clear command history" -POST_BREACH_PROCESS_LIST_COLLECTION = "Process list collection" +POST_BREACH_PROCESS_LIST_COLLECTION = "Collect running processes" From f243e4a7225141d0d779b3530dc72d96c149d05e Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Thu, 17 Feb 2022 16:58:27 +0530 Subject: [PATCH 20/22] Agent: Drop testing changes made to mock puppet --- monkey/infection_monkey/puppet/mock_puppet.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/monkey/infection_monkey/puppet/mock_puppet.py b/monkey/infection_monkey/puppet/mock_puppet.py index 904ece2e5..082ce523b 100644 --- a/monkey/infection_monkey/puppet/mock_puppet.py +++ b/monkey/infection_monkey/puppet/mock_puppet.py @@ -159,9 +159,6 @@ class MockPuppet(IPuppet): if name == "AccountDiscovery": return PostBreachData("pba command 1", ["pba result 1", True]) - elif name == "ProcessListCollection": - cmd, result = ProcessListCollection().run() - return PostBreachData(cmd, result) else: return PostBreachData("pba command 2", ["pba result 2", False]) From 83f544c9f26dd7e186597fabfa5d120e8336ec71 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Thu, 17 Feb 2022 16:58:41 +0530 Subject: [PATCH 21/22] Island: Rename mongo query variable in T1082.py --- .../cc/services/attack/technique_reports/T1082.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1082.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1082.py index 1fa81f4ed..4c79916ef 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1082.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1082.py @@ -56,7 +56,7 @@ class T1082(AttackTechnique): {"$replaceRoot": {"newRoot": "$_id"}}, ] - query_for_pbas = [ + query_for_running_processes_list = [ { "$match": { "$and": [ @@ -93,7 +93,7 @@ class T1082(AttackTechnique): ScanStatus.USED.value if system_info_data else ScanStatus.UNSCANNED.value ) - pba_data = list(mongo.db.telemetry.aggregate(T1082.query_for_pbas)) + pba_data = list(mongo.db.telemetry.aggregate(T1082.query_for_running_processes_list)) successful_PBAs = mongo.db.telemetry.count( { "$and": [ From 44b894749729ca5ed8cba2d4b37637f50e226438 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Thu, 17 Feb 2022 17:01:05 +0530 Subject: [PATCH 22/22] Docs: Remove adding-system-info-collectors.md --- docs/content/development/adding-exploits.md | 2 +- .../adding-system-info-collectors.md | 101 ------------------ 2 files changed, 1 insertion(+), 102 deletions(-) delete mode 100644 docs/content/development/adding-system-info-collectors.md diff --git a/docs/content/development/adding-exploits.md b/docs/content/development/adding-exploits.md index 1f4698820..468d17055 100644 --- a/docs/content/development/adding-exploits.md +++ b/docs/content/development/adding-exploits.md @@ -14,7 +14,7 @@ An exploit is a sequence of commands that takes advantage of a security vulnerab ### Do I need a new Exploit? -If all you want to do is execute a shell command, configure the required commands in the Monkey Island's post-breach action (PBA) configuration section or [add a new PBA](../adding-post-breach-actions/). If you would like the Infection Monkey agent to collect specific information, [add a new System Info Collector](../adding-system-info-collectors/). +If all you want to do is execute a shell command, configure the required commands in the Monkey Island's post-breach action (PBA) configuration section or [add a new PBA](../adding-post-breach-actions/). However, if you have your eye on an interesting CVE that you would like the Infection Monkey to support, you must add a new exploit. Keep reading to learn how to add a new exploit. diff --git a/docs/content/development/adding-system-info-collectors.md b/docs/content/development/adding-system-info-collectors.md deleted file mode 100644 index 353bd6c0d..000000000 --- a/docs/content/development/adding-system-info-collectors.md +++ /dev/null @@ -1,101 +0,0 @@ ---- -title: "Adding System Info Collectors" -date: 2020-06-09T11:03:42+03:00 -draft: false -tags: ["contribute"] -weight: 80 ---- - -## What does this guide cover? - -This guide will show you how to create a new _System Info Collector_ for the Infection Monkey. System Info Collectors are modules that each of the Infection Monkey agents runs that collect specific information and send it back to the Monkey Island as part of the System Info Telemetry. - -### Do I need a new System Info Collector? - -If all you want to do is execute a shell command, then there's no need to add a new System Info Collector - just configure the required commands in the Monkey Island's post-breach action (PBA) section! Also, if there is a relevant System Info Collector and you only need to add more information to it, simply expand the existing one. Otherwise, you must add a new System Info Collector. - -## How to add a new System Info Collector - -### Modify the Infection Monkey Agent - -#### Framework - -1. Create your new System Info Collector in the following directory: `monkey/infection_monkey/system_info/collectors` by first creating a new file with the name of your System Info Collector. -2. In that file, create a class that inherits from the `SystemInfoCollector` class: - -```py -from infection_monkey.system_info.system_info_collector import SystemInfoCollector - -class MyNewCollector(SystemInfoCollector): -``` - -3. Set the System Info Collector name in the constructor, like so: - -```py -class MyNewCollector(SystemInfoCollector): - def __init__(self): - super(MyNewCollector, self).__init__(name="MyNewCollector") -``` - -#### Implementation - -Override the `collect` method with your own implementation. See the `aws_collector.py` System Info Collector for reference. You can log during collection as well. - -### Modify the Monkey Island - -#### Configuration - -##### Definitions - -You'll need to add your Sytem Info Collector to the `monkey_island/cc/services/config_schema.py` file, under `definitions/system_info_collectors_classes/anyOf`, like so: - -```json -"system_info_collectors_classes": { - "title": "System Information Collectors", - "type": "string", - "anyOf": [ - { - "type": "string", - "enum": [ - "HostnameCollector" - ], - "title": "Which environment this machine is on (on prem/cloud)", - "attack_techniques": [] - }, - { <================================= - "type": "string", <================================= - "enum": [ <================================= - "MyNewCollector" <================================= - ], <================================= - "title": "My new title", <================================= - "attack_techniques": [] <================================= - }, - ], -}, -``` - -##### properties - -Also, you can add the System Info Collector to be used by default by adding it to the `default` key under `properties/monkey/system_info/system_info_collectors_classes`: - -```json -"system_info_collectors_classes": { - "title": "System info collectors", - "type": "array", - "uniqueItems": True, - "items": { - "$ref": "#/definitions/system_info_collectors_classes" - }, - "default": [ - "HostnameCollector", - "MyNewCollector" <================================= - ], - "description": "Determines which system information collectors will collect information." -}, -``` - -#### Telemetry processing - -1. Add a process function under `monkey_island/cc/telemetry/processing/system_info_collectors/{DATA_NAME_HERE}.py`. The function should parse the System Info Collector's result. See `processing/system_info_collectors/aws.py` for example. - -2. Add that function to `SYSTEM_INFO_COLLECTOR_TO_TELEMETRY_PROCESSORS` under `monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py`.