From 26b07933310fd992476e6ea2ca017b877f7dbcfb Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 22 Sep 2021 15:53:52 +0530 Subject: [PATCH 01/26] island: Add code to create reverse schema i.e. each attack technique mapped to its config fields --- .../config_schema_per_attack_technique.py | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 monkey/monkey_island/cc/services/config_schema/config_schema_per_attack_technique.py diff --git a/monkey/monkey_island/cc/services/config_schema/config_schema_per_attack_technique.py b/monkey/monkey_island/cc/services/config_schema/config_schema_per_attack_technique.py new file mode 100644 index 000000000..b00c378f0 --- /dev/null +++ b/monkey/monkey_island/cc/services/config_schema/config_schema_per_attack_technique.py @@ -0,0 +1,48 @@ +from typing import Dict, List + +from monkey_island.cc.services.config_schema.config_schema import SCHEMA + + +def get_reverse_config_schema(): + return _get_config_schema_per_attack_technique() + + +def _get_config_schema_per_attack_technique() -> Dict[str, Dict[str, List[str]]]: + """ + :return: dictionary mapping each attack technique to relevant config fields; example - + { + "T1003": { + "System Info Collectors": [ + "Mimikatz collector", + "Azure credential collector" + ] + } + } + """ + reverse_schema = {} + + definitions = SCHEMA["definitions"] + for definition in definitions: + definition_type = definitions[definition]["title"] + for field in definitions[definition]["anyOf"]: + config_field = field["title"] + if "attack_techniques" in field: + for attack_technique in field["attack_techniques"]: + _add_config_field_to_reverse_schema( + definition_type, config_field, attack_technique, reverse_schema + ) + + return reverse_schema + + +def _add_config_field_to_reverse_schema( + definition_type: str, config_field: str, attack_technique: str, reverse_schema: Dict +) -> None: + if attack_technique in reverse_schema: + technique = reverse_schema[attack_technique] + if definition_type in technique: + technique[definition_type].append(config_field) + else: + technique[definition_type] = [config_field] + else: + reverse_schema[attack_technique] = {definition_type: [config_field]} From 836069ab117644a0070fba319d9bfd1e6d5d1d85 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 22 Sep 2021 16:10:13 +0530 Subject: [PATCH 02/26] island: Change config schema definitions' titles to title case and so they make more sense --- .../definitions/exploiter_classes.py | 2 +- .../definitions/finger_classes.py | 16 +++++++------- .../definitions/post_breach_actions.py | 22 +++++++++---------- .../system_info_collector_classes.py | 12 +++++----- 4 files changed, 25 insertions(+), 27 deletions(-) diff --git a/monkey/monkey_island/cc/services/config_schema/definitions/exploiter_classes.py b/monkey/monkey_island/cc/services/config_schema/definitions/exploiter_classes.py index 9a7922a0f..981756bc7 100644 --- a/monkey/monkey_island/cc/services/config_schema/definitions/exploiter_classes.py +++ b/monkey/monkey_island/cc/services/config_schema/definitions/exploiter_classes.py @@ -1,7 +1,7 @@ from monkey_island.cc.services.utils.typographic_symbols import WARNING_SIGN EXPLOITER_CLASSES = { - "title": "Exploit class", + "title": "Exploiters", "description": "Click on exploiter to get more information about it." + WARNING_SIGN + " Note that using unsafe exploits may cause crashes of the exploited " diff --git a/monkey/monkey_island/cc/services/config_schema/definitions/finger_classes.py b/monkey/monkey_island/cc/services/config_schema/definitions/finger_classes.py index 2a617e011..6389f1b13 100644 --- a/monkey/monkey_island/cc/services/config_schema/definitions/finger_classes.py +++ b/monkey/monkey_island/cc/services/config_schema/definitions/finger_classes.py @@ -1,5 +1,5 @@ FINGER_CLASSES = { - "title": "Fingerprint class", + "title": "Fingerprinters", "description": "Fingerprint modules collect info about external services " "Infection Monkey scans.", "type": "string", @@ -7,7 +7,7 @@ FINGER_CLASSES = { { "type": "string", "enum": ["SMBFinger"], - "title": "SMBFinger", + "title": "SMB Fingerprinter", "safe": True, "info": "Figures out if SMB is running and what's the version of it.", "attack_techniques": ["T1210"], @@ -15,7 +15,7 @@ FINGER_CLASSES = { { "type": "string", "enum": ["SSHFinger"], - "title": "SSHFinger", + "title": "SSH Fingerprinter", "safe": True, "info": "Figures out if SSH is running.", "attack_techniques": ["T1210"], @@ -23,21 +23,21 @@ FINGER_CLASSES = { { "type": "string", "enum": ["PingScanner"], - "title": "PingScanner", + "title": "Ping Scanner", "safe": True, "info": "Tries to identify if host is alive and which OS it's running by ping scan.", }, { "type": "string", "enum": ["HTTPFinger"], - "title": "HTTPFinger", + "title": "HTTP Fingerprinter", "safe": True, "info": "Checks if host has HTTP/HTTPS ports open.", }, { "type": "string", "enum": ["MySQLFinger"], - "title": "MySQLFinger", + "title": "MySQL Fingerprinter", "safe": True, "info": "Checks if MySQL server is running and tries to get it's version.", "attack_techniques": ["T1210"], @@ -45,7 +45,7 @@ FINGER_CLASSES = { { "type": "string", "enum": ["MSSQLFinger"], - "title": "MSSQLFinger", + "title": "MSSQL Fingerprinter", "safe": True, "info": "Checks if Microsoft SQL service is running and tries to gather " "information about it.", @@ -54,7 +54,7 @@ FINGER_CLASSES = { { "type": "string", "enum": ["ElasticFinger"], - "title": "ElasticFinger", + "title": "Elastic Fingerprinter", "safe": True, "info": "Checks if ElasticSearch is running and attempts to find it's " "version.", "attack_techniques": ["T1210"], 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 be1aa802b..7d62ac36e 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 @@ -1,14 +1,13 @@ POST_BREACH_ACTIONS = { - "title": "Post breach actions", + "title": "Post-Breach Actions", "description": "Runs scripts/commands on infected machines. These actions safely simulate what " - "an adversary" - "might do after breaching a new machine. Used in ATT&CK and Zero trust reports.", + "an adversary might do after breaching a new machine. Used in ATT&CK and Zero trust reports.", "type": "string", "anyOf": [ { "type": "string", "enum": ["CommunicateAsBackdoorUser"], - "title": "Communicate as backdoor user", + "title": "Communicate as Backdoor User", "safe": True, "info": "Attempts to create a new user, create HTTPS requests as that " "user and delete the user " @@ -18,7 +17,7 @@ POST_BREACH_ACTIONS = { { "type": "string", "enum": ["ModifyShellStartupFiles"], - "title": "Modify shell startup files", + "title": "Modify Shell Startup Files", "safe": True, "info": "Attempts to modify shell startup files, like ~/.profile, " "~/.bashrc, ~/.bash_profile " @@ -29,7 +28,7 @@ POST_BREACH_ACTIONS = { { "type": "string", "enum": ["HiddenFiles"], - "title": "Hidden files and directories", + "title": "Hidden Files and Directories", "safe": True, "info": "Attempts to create a hidden file and remove it afterward.", "attack_techniques": ["T1158"], @@ -37,11 +36,10 @@ POST_BREACH_ACTIONS = { { "type": "string", "enum": ["TrapCommand"], - "title": "Trap", + "title": "Trap Command", "safe": True, "info": "On Linux systems, attempts to trap a terminate signal in order " - "to execute a command " - "upon receiving that signal. Removes the trap afterwards.", + "to execute a command upon receiving that signal. Removes the trap afterwards.", "attack_techniques": ["T1154"], }, { @@ -57,7 +55,7 @@ POST_BREACH_ACTIONS = { { "type": "string", "enum": ["ScheduleJobs"], - "title": "Job scheduling", + "title": "Job Scheduling", "safe": True, "info": "Attempts to create a scheduled job on the system and remove it.", "attack_techniques": ["T1168", "T1053"], @@ -74,7 +72,7 @@ POST_BREACH_ACTIONS = { { "type": "string", "enum": ["SignedScriptProxyExecution"], - "title": "Signed script proxy execution", + "title": "Signed Script Proxy Execution", "safe": False, "info": "On Windows systems, attempts to execute an arbitrary file " "with the help of a pre-existing signed script.", @@ -91,7 +89,7 @@ POST_BREACH_ACTIONS = { { "type": "string", "enum": ["ClearCommandHistory"], - "title": "Clear command history", + "title": "Clear Command History", "safe": False, "info": "Attempts to clear the command history.", "attack_techniques": ["T1146"], 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 9a4a39050..072640352 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 @@ -15,7 +15,7 @@ SYSTEM_INFO_COLLECTOR_CLASSES = { { "type": "string", "enum": [ENVIRONMENT_COLLECTOR], - "title": "Environment collector", + "title": "Environment Collector", "safe": True, "info": "Collects information about machine's environment (on " "premise/GCP/AWS).", "attack_techniques": ["T1082"], @@ -23,7 +23,7 @@ SYSTEM_INFO_COLLECTOR_CLASSES = { { "type": "string", "enum": [MIMIKATZ_COLLECTOR], - "title": "Mimikatz collector", + "title": "Mimikatz Collector", "safe": True, "info": "Collects credentials from Windows credential manager.", "attack_techniques": ["T1003", "T1005"], @@ -31,7 +31,7 @@ SYSTEM_INFO_COLLECTOR_CLASSES = { { "type": "string", "enum": [AWS_COLLECTOR], - "title": "AWS collector", + "title": "AWS Collector", "safe": True, "info": "If on AWS, collects more information about the AWS instance " "currently running on.", @@ -40,7 +40,7 @@ SYSTEM_INFO_COLLECTOR_CLASSES = { { "type": "string", "enum": [HOSTNAME_COLLECTOR], - "title": "Hostname collector", + "title": "Hostname Collector", "safe": True, "info": "Collects machine's hostname.", "attack_techniques": ["T1082", "T1016"], @@ -48,7 +48,7 @@ SYSTEM_INFO_COLLECTOR_CLASSES = { { "type": "string", "enum": [PROCESS_LIST_COLLECTOR], - "title": "Process list collector", + "title": "Process List Collector", "safe": True, "info": "Collects a list of running processes on the machine.", "attack_techniques": ["T1082"], @@ -56,7 +56,7 @@ SYSTEM_INFO_COLLECTOR_CLASSES = { { "type": "string", "enum": [AZURE_CRED_COLLECTOR], - "title": "Azure credential collector", + "title": "Azure Credential Collector", "safe": True, "info": "Collects password credentials from Azure VMs", "attack_techniques": ["T1003", "T1005"], From f9e994d8f8711ad2ce1a589aacb7572ff92ec4e1 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 22 Sep 2021 16:13:34 +0530 Subject: [PATCH 03/26] island: Update doc link for PowerShell exploiter --- .../cc/services/config_schema/definitions/exploiter_classes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/monkey_island/cc/services/config_schema/definitions/exploiter_classes.py b/monkey/monkey_island/cc/services/config_schema/definitions/exploiter_classes.py index 981756bc7..92898fdad 100644 --- a/monkey/monkey_island/cc/services/config_schema/definitions/exploiter_classes.py +++ b/monkey/monkey_island/cc/services/config_schema/definitions/exploiter_classes.py @@ -163,7 +163,7 @@ EXPLOITER_CLASSES = { "computers.", "safe": True, "link": "https://www.guardicore.com/infectionmonkey" - "/docs/reference/exploiters/", # TODO: Change link once documentation is updated + "/docs/reference/exploiters/powershell", }, ], } From ba2207b21dd298001a2a4475cada73452e3cdc8c Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 22 Sep 2021 16:16:46 +0530 Subject: [PATCH 04/26] island: Remove unneeded function to get reverse schema --- .../config_schema/config_schema_per_attack_technique.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/monkey/monkey_island/cc/services/config_schema/config_schema_per_attack_technique.py b/monkey/monkey_island/cc/services/config_schema/config_schema_per_attack_technique.py index b00c378f0..b97a1bf3e 100644 --- a/monkey/monkey_island/cc/services/config_schema/config_schema_per_attack_technique.py +++ b/monkey/monkey_island/cc/services/config_schema/config_schema_per_attack_technique.py @@ -3,11 +3,7 @@ from typing import Dict, List from monkey_island.cc.services.config_schema.config_schema import SCHEMA -def get_reverse_config_schema(): - return _get_config_schema_per_attack_technique() - - -def _get_config_schema_per_attack_technique() -> Dict[str, Dict[str, List[str]]]: +def get_config_schema_per_attack_technique() -> Dict[str, Dict[str, List[str]]]: """ :return: dictionary mapping each attack technique to relevant config fields; example - { From 9564fb1aaac328b51f2eca333841f5fb31a29633 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 22 Sep 2021 18:23:17 +0530 Subject: [PATCH 05/26] island: Move T1216's details from T1216.py to attack_schema.py so that it's shown in the config instead of the ATT&CK report --- .../cc/services/attack/attack_schema.py | 7 ++++--- .../cc/services/attack/technique_reports/T1216.py | 12 ++---------- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/monkey/monkey_island/cc/services/attack/attack_schema.py b/monkey/monkey_island/cc/services/attack/attack_schema.py index e11de8d96..6db87d4fb 100644 --- a/monkey/monkey_island/cc/services/attack/attack_schema.py +++ b/monkey/monkey_island/cc/services/attack/attack_schema.py @@ -214,9 +214,10 @@ SCHEMA = { "value": False, "necessary": False, "link": "https://attack.mitre.org/techniques/T1216", - "description": "Adversaries may use scripts signed with " - "trusted certificates to " - "proxy execution of malicious files on Windows systems.", + "description": "Adversaries may use scripts signed with trusted certificates " + "to proxy execution of malicious files on Windows systems. This behavior could " + "be abused by adversaries to execute malicious files that could bypass " + "application control and signature validation on systems.", }, }, }, diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1216.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1216.py index 7ef32c559..fd69417df 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1216.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1216.py @@ -6,22 +6,14 @@ class T1216(PostBreachTechnique): tech_id = "T1216" unscanned_msg = ( "Monkey didn't attempt to execute an arbitrary program with the help of a " - + "pre-existing signed script since it didn't run on any Windows machines. " - + "If successful, this behavior could be abused by adversaries to execute malicious " - "files that could " + "bypass application control and signature validation on " - "systems." + "pre-existing signed script since it didn't run on any Windows machines. " ) scanned_msg = ( "Monkey attempted to execute an arbitrary program with the help of a " - + "pre-existing signed script on Windows but failed. " - + "If successful, this behavior could be abused by adversaries to execute malicious " - "files that could " + "bypass application control and signature validation on " - "systems." + "pre-existing signed script on Windows but failed. " ) used_msg = ( "Monkey executed an arbitrary program with the help of a pre-existing signed script " "on Windows. " - + "This behavior could be abused by adversaries to execute malicious files that could " - + "bypass application control and signature validation on systems." ) pba_names = [POST_BREACH_SIGNED_SCRIPT_PROXY_EXEC] From 8e733a84409303e75649433ff310944a5fc9cfa5 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 22 Sep 2021 18:30:35 +0530 Subject: [PATCH 06/26] island: Add `relevant_systems` property to attack techniques that run on specific systems And remove hardcoded "since it didn't run on any ... systems" from the unscanned message for those techniques --- .../cc/services/attack/technique_reports/T1053.py | 9 ++++----- .../cc/services/attack/technique_reports/T1075.py | 5 ++--- .../cc/services/attack/technique_reports/T1086.py | 5 +++-- .../cc/services/attack/technique_reports/T1146.py | 5 ++--- .../cc/services/attack/technique_reports/T1154.py | 3 ++- .../cc/services/attack/technique_reports/T1156.py | 5 ++--- .../cc/services/attack/technique_reports/T1168.py | 5 ++--- .../cc/services/attack/technique_reports/T1197.py | 5 ++--- .../cc/services/attack/technique_reports/T1216.py | 3 ++- 9 files changed, 21 insertions(+), 24 deletions(-) diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1053.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1053.py index 3a10e92f7..c6420be0d 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1053.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1053.py @@ -4,9 +4,8 @@ from monkey_island.cc.services.attack.technique_reports.pba_technique import Pos class T1053(PostBreachTechnique): tech_id = "T1053" - unscanned_msg = ( - "Monkey didn't try scheduling a job on Windows since it didn't run on any Windows machines." - ) - scanned_msg = "Monkey tried scheduling a job on the Windows system but failed." - used_msg = "Monkey scheduled a job on the Windows system." + relevant_systems = ["Windows"] + unscanned_msg = "Monkey didn't try scheduling a job on any Windows system." + scanned_msg = "Monkey tried scheduling a job on a Windows system but failed." + used_msg = "Monkey scheduled a job on a Windows system." pba_names = [POST_BREACH_JOB_SCHEDULING] diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1075.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1075.py index 372ec35b0..4dddb9e9c 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1075.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1075.py @@ -5,9 +5,8 @@ from monkey_island.cc.services.attack.technique_reports import AttackTechnique class T1075(AttackTechnique): tech_id = "T1075" - unscanned_msg = ( - "Monkey didn't try to use pass the hash attack since it didn't run on any Windows machines." - ) + relevant_systems = ["Windows"] + unscanned_msg = "Monkey didn't try to use pass the hash attack." scanned_msg = "Monkey tried to use hashes while logging in but didn't succeed." used_msg = "Monkey successfully used hashed credentials." diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1086.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1086.py index eaaa7a155..253dc3d8d 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1086.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1086.py @@ -5,9 +5,10 @@ from monkey_island.cc.services.attack.technique_reports import AttackTechnique class T1086(AttackTechnique): tech_id = "T1086" - unscanned_msg = "Monkey didn't run powershell since it didn't run on any Windows machines." + relevant_systems = ["Windows"] + unscanned_msg = "Monkey didn't run PowerShell." scanned_msg = "" - used_msg = "Monkey successfully ran powershell commands on exploited machines in the network." + used_msg = "Monkey successfully ran PowerShell commands on exploited machines in the network." query = [ { diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1146.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1146.py index 951233418..d0b8cb4b5 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1146.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1146.py @@ -4,9 +4,8 @@ from monkey_island.cc.services.attack.technique_reports.pba_technique import Pos class T1146(PostBreachTechnique): tech_id = "T1146" - unscanned_msg = ( - "Monkey didn't try clearing the command history since it didn't run on any Linux machines." - ) + relevant_systems = ["Linux"] + unscanned_msg = "Monkey didn't try clearing the command history." scanned_msg = "Monkey tried clearing the command history but failed." used_msg = "Monkey successfully cleared the command history (and then restored it back)." pba_names = [POST_BREACH_CLEAR_CMD_HISTORY] diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1154.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1154.py index 3e7cb677b..7a1375208 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1154.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1154.py @@ -4,7 +4,8 @@ from monkey_island.cc.services.attack.technique_reports.pba_technique import Pos class T1154(PostBreachTechnique): tech_id = "T1154" - unscanned_msg = "Monkey didn't use the trap command since it didn't run on any Linux machines." + relevant_systems = ["Linux"] + unscanned_msg = "Monkey didn't use the trap command." scanned_msg = "Monkey tried using the trap command but failed." used_msg = "Monkey used the trap command successfully." pba_names = [POST_BREACH_TRAP_COMMAND] diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1156.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1156.py index 2dd6e03af..f9c5c5020 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1156.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1156.py @@ -4,9 +4,8 @@ from monkey_island.cc.services.attack.technique_reports.pba_technique import Pos class T1156(PostBreachTechnique): tech_id = "T1156" - unscanned_msg = ( - "Monkey didn't try modifying bash startup files since it didn't run on any Linux machines." - ) + relevant_systems = ["Linux"] + unscanned_msg = "Monkey didn't try modifying bash startup files." scanned_msg = "Monkey tried modifying bash startup files but failed." used_msg = "Monkey successfully modified bash startup files." pba_names = [POST_BREACH_SHELL_STARTUP_FILE_MODIFICATION] diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1168.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1168.py index a0cc0ee78..9a2b7547f 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1168.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1168.py @@ -4,9 +4,8 @@ from monkey_island.cc.services.attack.technique_reports.pba_technique import Pos class T1168(PostBreachTechnique): tech_id = "T1168" - unscanned_msg = ( - "Monkey didn't try scheduling a job on Linux since it didn't run on any Linux machines." - ) + relevant_systems = ["Linux"] + unscanned_msg = "Monkey didn't try scheduling a job on Linux." scanned_msg = "Monkey tried scheduling a job on the Linux system but failed." used_msg = "Monkey scheduled a job on the Linux system." pba_names = [POST_BREACH_JOB_SCHEDULING] diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1197.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1197.py index 1de5f3080..1d16a08ef 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1197.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1197.py @@ -4,9 +4,8 @@ from monkey_island.cc.services.attack.technique_reports import AttackTechnique class T1197(AttackTechnique): tech_id = "T1197" - unscanned_msg = ( - "Monkey didn't try to use any bits jobs since it didn't run on any Windows machines." - ) + relevant_systems = ["Windows"] + unscanned_msg = "Monkey didn't try to use any bits jobs." scanned_msg = "Monkey tried to use bits jobs but failed." used_msg = "Monkey successfully used bits jobs at least once in the network." diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1216.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1216.py index fd69417df..24cab65d8 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1216.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1216.py @@ -4,9 +4,10 @@ from monkey_island.cc.services.attack.technique_reports.pba_technique import Pos class T1216(PostBreachTechnique): tech_id = "T1216" + relevant_sytems = ["Windows"] unscanned_msg = ( "Monkey didn't attempt to execute an arbitrary program with the help of a " - "pre-existing signed script since it didn't run on any Windows machines. " + "pre-existing signed script. " ) scanned_msg = ( "Monkey attempted to execute an arbitrary program with the help of a " From b0b0f515d0f2531d3ec16c517eb05940215d4e60 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 22 Sep 2021 19:15:06 +0530 Subject: [PATCH 07/26] island: Add abstract property `relevant_systems` to AttackTechnique and declare it for all techniques left --- .../services/attack/technique_reports/T1003.py | 1 + .../services/attack/technique_reports/T1005.py | 1 + .../services/attack/technique_reports/T1016.py | 1 + .../services/attack/technique_reports/T1018.py | 1 + .../services/attack/technique_reports/T1021.py | 1 + .../services/attack/technique_reports/T1035.py | 6 ++---- .../services/attack/technique_reports/T1041.py | 1 + .../services/attack/technique_reports/T1059.py | 3 ++- .../services/attack/technique_reports/T1064.py | 1 + .../services/attack/technique_reports/T1065.py | 1 + .../services/attack/technique_reports/T1082.py | 1 + .../services/attack/technique_reports/T1087.py | 1 + .../services/attack/technique_reports/T1090.py | 1 + .../services/attack/technique_reports/T1099.py | 1 + .../services/attack/technique_reports/T1105.py | 1 + .../services/attack/technique_reports/T1106.py | 1 + .../services/attack/technique_reports/T1107.py | 1 + .../services/attack/technique_reports/T1110.py | 1 + .../services/attack/technique_reports/T1136.py | 1 + .../services/attack/technique_reports/T1145.py | 5 +++-- .../services/attack/technique_reports/T1146.py | 9 ++++++--- .../services/attack/technique_reports/T1158.py | 1 + .../services/attack/technique_reports/T1166.py | 6 ++---- .../services/attack/technique_reports/T1188.py | 1 + .../services/attack/technique_reports/T1210.py | 1 + .../services/attack/technique_reports/T1216.py | 2 +- .../services/attack/technique_reports/T1222.py | 1 + .../services/attack/technique_reports/T1504.py | 10 ++++------ .../attack/technique_reports/__init__.py | 18 +++++++++++++++++- 29 files changed, 58 insertions(+), 22 deletions(-) diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py index d79aa7575..79edfc8fd 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py @@ -6,6 +6,7 @@ from monkey_island.cc.services.reporting.report import ReportService class T1003(AttackTechnique): tech_id = "T1003" + relevant_systems = ["Linux", "Windows"] unscanned_msg = ( "Monkey tried to obtain credentials from systems in the network but didn't " "find any or failed." diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1005.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1005.py index 5aa2f4ad8..2a9ecfded 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1005.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1005.py @@ -4,6 +4,7 @@ from monkey_island.cc.services.attack.technique_reports import AttackTechnique class T1005(AttackTechnique): tech_id = "T1005" + relevant_systems = ["Linux", "Windows"] unscanned_msg = "Monkey didn't gather any sensitive data from local system." scanned_msg = "" used_msg = "Monkey successfully gathered sensitive data from local system." diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1016.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1016.py index 3ff4544d2..240b38b18 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1016.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1016.py @@ -5,6 +5,7 @@ from monkey_island.cc.services.attack.technique_reports import AttackTechnique class T1016(AttackTechnique): tech_id = "T1016" + relevant_systems = ["Linux", "Windows"] unscanned_msg = "Monkey didn't gather network configurations." scanned_msg = "" used_msg = "Monkey gathered network configurations on systems in the network." diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1018.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1018.py index 1495911bd..f78718de7 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1018.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1018.py @@ -5,6 +5,7 @@ from monkey_island.cc.services.attack.technique_reports import AttackTechnique class T1018(AttackTechnique): tech_id = "T1018" + relevant_systems = ["Linux", "Windows"] unscanned_msg = "Monkey didn't find any machines on the network." scanned_msg = "" used_msg = "Monkey found machines on the network." diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1021.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1021.py index 4e668f601..e829098fd 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1021.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1021.py @@ -6,6 +6,7 @@ from monkey_island.cc.services.attack.technique_reports.technique_report_tools i class T1021(AttackTechnique): tech_id = "T1021" + relevant_systems = ["Linux", "Windows"] unscanned_msg = "Monkey didn't try to login to any remote services." scanned_msg = "Monkey tried to login to remote services with valid credentials, but failed." used_msg = "Monkey successfully logged into remote services on the network." diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1035.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1035.py index cb8775fc4..daba462fe 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1035.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1035.py @@ -3,10 +3,8 @@ from monkey_island.cc.services.attack.technique_reports.usage_technique import U class T1035(UsageTechnique): tech_id = "T1035" - unscanned_msg = ( - "Monkey didn't try to interact with Windows services since it didn't run on " - "any Windows machines." - ) + relevant_systems = ["Windows"] + unscanned_msg = "Monkey didn't try to interact with Windows services." scanned_msg = "Monkey tried to interact with Windows services, but failed." used_msg = "Monkey successfully interacted with Windows services." diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1041.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1041.py index 692a41e8b..d13f557fb 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1041.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1041.py @@ -5,6 +5,7 @@ from monkey_island.cc.services.attack.technique_reports import AttackTechnique class T1041(AttackTechnique): tech_id = "T1041" + relevant_systems = ["Linux", "Windows"] unscanned_msg = "Monkey didn't exfiltrate any info through command and control channel." scanned_msg = "" used_msg = "Monkey exfiltrated info through command and control channel." diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py index 6d7940718..e4301d61b 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py @@ -5,7 +5,8 @@ from monkey_island.cc.services.attack.technique_reports import AttackTechnique class T1059(AttackTechnique): tech_id = "T1059" - unscanned_msg = "Monkey didn't exploit any machines to run commands at." + relevant_systems = ["Linux", "Windows"] + unscanned_msg = "Monkey didn't exploit any machines to run commands on." scanned_msg = "" used_msg = "Monkey successfully ran commands on exploited machines in the network." diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1064.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1064.py index d8c723053..6af7fb7de 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1064.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1064.py @@ -4,6 +4,7 @@ from monkey_island.cc.services.attack.technique_reports.usage_technique import U class T1064(UsageTechnique): tech_id = "T1064" + relevant_systems = ["Linux", "Windows"] unscanned_msg = "Monkey didn't run scripts or tried to run and failed." scanned_msg = "" used_msg = "Monkey ran scripts on machines in the network." diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1065.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1065.py index edc35b23a..7615a46c2 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1065.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1065.py @@ -6,6 +6,7 @@ from monkey_island.cc.services.config import ConfigService class T1065(AttackTechnique): tech_id = "T1065" + relevant_systems = ["Linux", "Windows"] unscanned_msg = "" scanned_msg = "" used_msg = "" 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 a9409d4bc..5d5246187 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1082.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1082.py @@ -5,6 +5,7 @@ from monkey_island.cc.services.attack.technique_reports import AttackTechnique class T1082(AttackTechnique): tech_id = "T1082" + relevant_systems = ["Linux", "Windows"] 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." diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1087.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1087.py index 6c42fea74..a4012dda3 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1087.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1087.py @@ -4,6 +4,7 @@ from monkey_island.cc.services.attack.technique_reports.pba_technique import Pos class T1087(PostBreachTechnique): tech_id = "T1087" + relevant_systems = ["Linux", "Windows"] unscanned_msg = "Monkey didn't try to get a listing of user accounts." scanned_msg = "Monkey tried to get a listing of user accounts but failed to do so." used_msg = "Monkey got a listing of user accounts successfully." diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1090.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1090.py index c5b0a9eed..aa172b87d 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1090.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1090.py @@ -5,6 +5,7 @@ from monkey_island.cc.services.attack.technique_reports import AttackTechnique class T1090(AttackTechnique): tech_id = "T1090" + relevant_systems = ["Linux", "Windows"] unscanned_msg = "Monkey didn't use connection proxy." scanned_msg = "" used_msg = "Monkey used connection proxy to communicate with machines on the network." diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1099.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1099.py index 59daea695..4a13ba073 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1099.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1099.py @@ -4,6 +4,7 @@ from monkey_island.cc.services.attack.technique_reports.pba_technique import Pos class T1099(PostBreachTechnique): tech_id = "T1099" + relevant_systems = ["Linux", "Windows"] unscanned_msg = "Monkey didn't try changing any file's time attributes." scanned_msg = "Monkey tried changing a file's time attributes but failed." used_msg = "Monkey successfully changed a file's time attributes." diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1105.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1105.py index 225efcda8..80700edc5 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1105.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1105.py @@ -4,6 +4,7 @@ from monkey_island.cc.services.attack.technique_reports import AttackTechnique class T1105(AttackTechnique): tech_id = "T1105" + relevant_systems = ["Linux", "Windows"] unscanned_msg = "Monkey didn't try to copy files to any systems." scanned_msg = "Monkey tried to copy files, but failed." used_msg = "Monkey successfully copied files to systems on the network." diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1106.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1106.py index 14019634a..5f23ee94e 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1106.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1106.py @@ -3,6 +3,7 @@ from monkey_island.cc.services.attack.technique_reports.usage_technique import U class T1106(UsageTechnique): tech_id = "T1106" + relevant_systems = ["Windows"] unscanned_msg = "Monkey didn't try to directly use WinAPI." scanned_msg = "Monkey tried to use WinAPI, but failed." used_msg = "Monkey successfully used WinAPI." diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1107.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1107.py index 713fffb24..c1555f5dd 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1107.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1107.py @@ -4,6 +4,7 @@ from monkey_island.cc.services.attack.technique_reports import AttackTechnique class T1107(AttackTechnique): tech_id = "T1107" + relevant_systems = ["Linux", "Windows"] unscanned_msg = "" scanned_msg = "Monkey tried to delete files on systems in the network, but failed." used_msg = "Monkey successfully deleted files on systems in the network." diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1110.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1110.py index 2d1702b64..30f4d8508 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1110.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1110.py @@ -6,6 +6,7 @@ from monkey_island.cc.services.attack.technique_reports.technique_report_tools i class T1110(AttackTechnique): tech_id = "T1110" + relevant_systems = ["Linux", "Windows"] unscanned_msg = "Monkey didn't try to brute force any services." scanned_msg = "Monkey tried to brute force some services, but failed." used_msg = "Monkey successfully used brute force in the network." diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1136.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1136.py index d2be05a9b..37537776d 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1136.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1136.py @@ -4,6 +4,7 @@ from monkey_island.cc.services.attack.technique_reports.pba_technique import Pos class T1136(PostBreachTechnique): tech_id = "T1136" + relevant_systems = ["Linux", "Windows"] unscanned_msg = "Monkey didn't try creating a new user on the network's systems." scanned_msg = "Monkey tried creating a new user on the network's systems, but failed." used_msg = "Monkey created a new user on the network's systems." diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1145.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1145.py index 818691bd0..5fea316aa 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1145.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1145.py @@ -5,9 +5,10 @@ from monkey_island.cc.services.attack.technique_reports import AttackTechnique class T1145(AttackTechnique): tech_id = "T1145" - unscanned_msg = "Monkey didn't find any shh keys." + relevant_systems = ["Linux", "Windows"] + unscanned_msg = "Monkey didn't find any SSH keys." scanned_msg = "" - used_msg = "Monkey found ssh keys on machines in the network." + used_msg = "Monkey found SSH keys on machines in the network." # Gets data about ssh keys found query = [ diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1146.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1146.py index d0b8cb4b5..98a725dcd 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1146.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1146.py @@ -5,9 +5,12 @@ from monkey_island.cc.services.attack.technique_reports.pba_technique import Pos class T1146(PostBreachTechnique): tech_id = "T1146" relevant_systems = ["Linux"] - unscanned_msg = "Monkey didn't try clearing the command history." - scanned_msg = "Monkey tried clearing the command history but failed." - used_msg = "Monkey successfully cleared the command history (and then restored it back)." + unscanned_msg = "Monkey didn't try clearing the command history on a Linux system." + scanned_msg = "Monkey tried clearing the command history on a Linux system but failed." + used_msg = ( + "Monkey successfully cleared the command history on a Linux system (and then " + "restored it back)." + ) pba_names = [POST_BREACH_CLEAR_CMD_HISTORY] @staticmethod diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1158.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1158.py index f58ef371a..22006d5db 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1158.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1158.py @@ -4,6 +4,7 @@ from monkey_island.cc.services.attack.technique_reports.pba_technique import Pos class T1158(PostBreachTechnique): tech_id = "T1158" + relevant_systems = ["Linux", "Windows"] unscanned_msg = "Monkey didn't try creating hidden files or folders." scanned_msg = "Monkey tried creating hidden files and folders on the system but failed." used_msg = "Monkey created hidden files and folders on the system." diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1166.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1166.py index 2b13d0865..abc8baa69 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1166.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1166.py @@ -4,10 +4,8 @@ from monkey_island.cc.services.attack.technique_reports.pba_technique import Pos class T1166(PostBreachTechnique): tech_id = "T1166" - unscanned_msg = ( - "Monkey didn't try setting the setuid or setgid bits since it didn't run on " - "any Linux machines." - ) + relevant_systems = ["Linux"] + unscanned_msg = "Monkey didn't try setting the setuid or setgid bits." scanned_msg = "Monkey tried setting the setuid or setgid bits but failed." used_msg = "Monkey successfully set the setuid or setgid bits." pba_names = [POST_BREACH_SETUID_SETGID] diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1188.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1188.py index b41c1fb54..47aabf7aa 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1188.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1188.py @@ -5,6 +5,7 @@ from monkey_island.cc.services.attack.technique_reports import AttackTechnique class T1188(AttackTechnique): tech_id = "T1188" + relevant_systems = ["Linux", "Windows"] unscanned_msg = "Monkey didn't use multi-hop proxy." scanned_msg = "" used_msg = "Monkey used multi-hop proxy." diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1210.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1210.py index 02acad288..a00462d85 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1210.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1210.py @@ -5,6 +5,7 @@ from monkey_island.cc.services.attack.technique_reports import AttackTechnique class T1210(AttackTechnique): tech_id = "T1210" + relevant_systems = ["Linux", "Windows"] unscanned_msg = ( "Monkey didn't scan any remote services. Maybe it didn't find any machines on the network?" ) diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1216.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1216.py index 24cab65d8..4cd4d28f6 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1216.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1216.py @@ -4,7 +4,7 @@ from monkey_island.cc.services.attack.technique_reports.pba_technique import Pos class T1216(PostBreachTechnique): tech_id = "T1216" - relevant_sytems = ["Windows"] + relevant_systems = ["Windows"] unscanned_msg = ( "Monkey didn't attempt to execute an arbitrary program with the help of a " "pre-existing signed script. " diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1222.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1222.py index 73eab6fd1..59587d2bd 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1222.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1222.py @@ -5,6 +5,7 @@ from monkey_island.cc.services.attack.technique_reports import AttackTechnique class T1222(AttackTechnique): tech_id = "T1222" + relevant_systems = ["Linux", "Windows"] unscanned_msg = "Monkey didn't try to change any file permissions." scanned_msg = "Monkey tried to change file permissions, but failed." used_msg = "Monkey successfully changed file permissions in network systems." diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1504.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1504.py index de2571b6b..edeb083b3 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1504.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1504.py @@ -4,12 +4,10 @@ from monkey_island.cc.services.attack.technique_reports.pba_technique import Pos class T1504(PostBreachTechnique): tech_id = "T1504" - unscanned_msg = ( - "Monkey didn't try modifying powershell startup files since it didn't run on " - "any Windows machines." - ) - scanned_msg = "Monkey tried modifying powershell startup files but failed." - used_msg = "Monkey successfully modified powershell startup files." + relevant_systems = ["Windows"] + unscanned_msg = "Monkey didn't try modifying PowerShell startup files." + scanned_msg = "Monkey tried modifying PowerShell startup files but failed." + used_msg = "Monkey successfully modified PowerShell startup files." pba_names = [POST_BREACH_SHELL_STARTUP_FILE_MODIFICATION] @staticmethod diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py b/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py index 40a421d74..360288a07 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py @@ -1,5 +1,6 @@ import abc import logging +from typing import List from common.utils.attack_utils import ScanStatus from common.utils.code_utils import abstractstatic @@ -50,6 +51,16 @@ class AttackTechnique(object, metaclass=abc.ABCMeta): """ pass + @property + @abc.abstractmethod + def relevant_systems(self) -> List[str]: + """ + :return: systems on which the technique is relevant + (examples: 1. "Trap Command" PBA (technique T1154) is Linux only. + 2. "Job Scheduling" PBA has different techniques for Windows and Linux. + """ + pass + @staticmethod @abstractstatic def get_report_data(): @@ -104,12 +115,17 @@ class AttackTechnique(object, metaclass=abc.ABCMeta): if status == ScanStatus.DISABLED.value: return disabled_msg if status == ScanStatus.UNSCANNED.value: - return cls.unscanned_msg + unscanned_msg = AttackTechnique._get_unscanned_msg_with_reasons(cls.unscanned_msg) + return unscanned_msg elif status == ScanStatus.SCANNED.value: return cls.scanned_msg else: return cls.used_msg + @staticmethod + def _get_unscanned_msg_with_reasons(unscanned_msg): + pass + @classmethod def technique_title(cls): """ From f730e75cc80e72767120062cc914d3969b70fec1 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 22 Sep 2021 19:19:35 +0530 Subject: [PATCH 08/26] island: Change `pass` to `...` for abstract properties in cc/services/attack/technique_reports/ See https://stackoverflow.com/a/58321197/10629482. --- .../services/attack/technique_reports/__init__.py | 14 +++++++------- .../attack/technique_reports/pba_technique.py | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py b/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py index 360288a07..07491fbfc 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py @@ -25,7 +25,7 @@ class AttackTechnique(object, metaclass=abc.ABCMeta): """ :return: Message that will be displayed in case attack technique was not scanned. """ - pass + ... @property @abc.abstractmethod @@ -33,7 +33,7 @@ class AttackTechnique(object, metaclass=abc.ABCMeta): """ :return: Message that will be displayed in case attack technique was scanned. """ - pass + ... @property @abc.abstractmethod @@ -41,7 +41,7 @@ class AttackTechnique(object, metaclass=abc.ABCMeta): """ :return: Message that will be displayed in case attack technique was used by the scanner. """ - pass + ... @property @abc.abstractmethod @@ -49,7 +49,7 @@ class AttackTechnique(object, metaclass=abc.ABCMeta): """ :return: Id of attack technique. E.g. T1003 """ - pass + ... @property @abc.abstractmethod @@ -59,7 +59,7 @@ class AttackTechnique(object, metaclass=abc.ABCMeta): (examples: 1. "Trap Command" PBA (technique T1154) is Linux only. 2. "Job Scheduling" PBA has different techniques for Windows and Linux. """ - pass + ... @staticmethod @abstractstatic @@ -67,7 +67,7 @@ class AttackTechnique(object, metaclass=abc.ABCMeta): """ :return: Report data aggregated from the database. """ - pass + ... @classmethod def technique_status(cls): @@ -124,7 +124,7 @@ class AttackTechnique(object, metaclass=abc.ABCMeta): @staticmethod def _get_unscanned_msg_with_reasons(unscanned_msg): - pass + ... @classmethod def technique_title(cls): diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/pba_technique.py b/monkey/monkey_island/cc/services/attack/technique_reports/pba_technique.py index 9e7324917..07e64566e 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/pba_technique.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/pba_technique.py @@ -15,7 +15,7 @@ class PostBreachTechnique(AttackTechnique, metaclass=abc.ABCMeta): """ :return: names of post breach action """ - pass + ... @classmethod def get_pba_query(cls, post_breach_action_names): From 2cc00205f1163f9582f5278f8fc585a9b5a2d91c Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Thu, 23 Sep 2021 16:39:05 +0530 Subject: [PATCH 09/26] island: Modify ATT&CK report messages to mention reasons 1. not run on relevant system 2. relevant config options were disabled --- .../attack/technique_reports/__init__.py | 38 +++++++++++++++++-- .../config_schema_per_attack_technique.py | 3 ++ 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py b/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py index 07491fbfc..88187c410 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py @@ -7,6 +7,9 @@ from common.utils.code_utils import abstractstatic from monkey_island.cc.database import mongo from monkey_island.cc.models.attack.attack_mitigations import AttackMitigations from monkey_island.cc.services.attack.attack_config import AttackConfig +from monkey_island.cc.services.config_schema.config_schema_per_attack_technique import ( + CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE, +) logger = logging.getLogger(__name__) @@ -115,16 +118,43 @@ class AttackTechnique(object, metaclass=abc.ABCMeta): if status == ScanStatus.DISABLED.value: return disabled_msg if status == ScanStatus.UNSCANNED.value: - unscanned_msg = AttackTechnique._get_unscanned_msg_with_reasons(cls.unscanned_msg) + unscanned_msg = cls._get_unscanned_msg_with_reasons(cls.unscanned_msg) return unscanned_msg elif status == ScanStatus.SCANNED.value: return cls.scanned_msg else: return cls.used_msg - @staticmethod - def _get_unscanned_msg_with_reasons(unscanned_msg): - ... + @classmethod + def _get_unscanned_msg_with_reasons(cls, unscanned_msg): + reasons = [] + if len(cls.relevant_systems) == 1: + reasons.append(f"- The Monkey did not run on any {cls.relevant_systems[0]} systems.") + if cls.tech_id in CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE: + reasons.append( + "- The following configuration options were disabled:
" + f"{cls._get_relevant_config_values()}" + ) + + if reasons: + unscanned_msg = ( + unscanned_msg.strip(".") + + " due to one of the following reasons:\n" + + "\n".join(reasons) + ) + + return unscanned_msg + + @classmethod + def _get_relevant_config_values(cls): + config_options = "" + for config_type in CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE[cls.tech_id]: + config_options += ( + f"- {config_type} — " + f"{', '.join(CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE[cls.tech_id][config_type])}
" + ) + + return config_options @classmethod def technique_title(cls): diff --git a/monkey/monkey_island/cc/services/config_schema/config_schema_per_attack_technique.py b/monkey/monkey_island/cc/services/config_schema/config_schema_per_attack_technique.py index b97a1bf3e..bcaa5a2af 100644 --- a/monkey/monkey_island/cc/services/config_schema/config_schema_per_attack_technique.py +++ b/monkey/monkey_island/cc/services/config_schema/config_schema_per_attack_technique.py @@ -42,3 +42,6 @@ def _add_config_field_to_reverse_schema( technique[definition_type] = [config_field] else: reverse_schema[attack_technique] = {definition_type: [config_field]} + + +CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE = get_config_schema_per_attack_technique() From 4a65ac37efdd503d08e1323b27bdbfb5b91ac96d Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Fri, 24 Sep 2021 12:30:11 +0530 Subject: [PATCH 10/26] island: Use dict's `get()` method to shorten `get_config_schema_per_attack_technique()` in config_schema_per_attack_technique.py --- .../config_schema/config_schema_per_attack_technique.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/monkey/monkey_island/cc/services/config_schema/config_schema_per_attack_technique.py b/monkey/monkey_island/cc/services/config_schema/config_schema_per_attack_technique.py index bcaa5a2af..0ef4ed0a6 100644 --- a/monkey/monkey_island/cc/services/config_schema/config_schema_per_attack_technique.py +++ b/monkey/monkey_island/cc/services/config_schema/config_schema_per_attack_technique.py @@ -22,11 +22,10 @@ def get_config_schema_per_attack_technique() -> Dict[str, Dict[str, List[str]]]: definition_type = definitions[definition]["title"] for field in definitions[definition]["anyOf"]: config_field = field["title"] - if "attack_techniques" in field: - for attack_technique in field["attack_techniques"]: - _add_config_field_to_reverse_schema( - definition_type, config_field, attack_technique, reverse_schema - ) + for attack_technique in field.get("attack_techniques", []): + _add_config_field_to_reverse_schema( + definition_type, config_field, attack_technique, reverse_schema + ) return reverse_schema From f3da34e9696ffd28ced894739737861ab8cdc234 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Fri, 24 Sep 2021 12:39:15 +0530 Subject: [PATCH 11/26] island: Use dict's `setdefault()` to shorten `_add_config_field_to_reverse_schema()` in config_schema_per_attack_technique.py --- .../config_schema/config_schema_per_attack_technique.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/monkey/monkey_island/cc/services/config_schema/config_schema_per_attack_technique.py b/monkey/monkey_island/cc/services/config_schema/config_schema_per_attack_technique.py index 0ef4ed0a6..61fcae807 100644 --- a/monkey/monkey_island/cc/services/config_schema/config_schema_per_attack_technique.py +++ b/monkey/monkey_island/cc/services/config_schema/config_schema_per_attack_technique.py @@ -34,11 +34,7 @@ def _add_config_field_to_reverse_schema( definition_type: str, config_field: str, attack_technique: str, reverse_schema: Dict ) -> None: if attack_technique in reverse_schema: - technique = reverse_schema[attack_technique] - if definition_type in technique: - technique[definition_type].append(config_field) - else: - technique[definition_type] = [config_field] + reverse_schema[attack_technique].setdefault(definition_type, []).append(config_field) else: reverse_schema[attack_technique] = {definition_type: [config_field]} From f2470bb0e90204fcfe85dc452c73e3b78076a88a Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Fri, 24 Sep 2021 15:52:34 +0530 Subject: [PATCH 12/26] tests: Add unit test for `get_config_schema_per_attack_technique()` in config_schema_per_attack_technique.py --- ...test_config_schema_per_attack_technique.py | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 monkey/tests/unit_tests/monkey_island/cc/services/config_schema/test_config_schema_per_attack_technique.py diff --git a/monkey/tests/unit_tests/monkey_island/cc/services/config_schema/test_config_schema_per_attack_technique.py b/monkey/tests/unit_tests/monkey_island/cc/services/config_schema/test_config_schema_per_attack_technique.py new file mode 100644 index 000000000..2827fd302 --- /dev/null +++ b/monkey/tests/unit_tests/monkey_island/cc/services/config_schema/test_config_schema_per_attack_technique.py @@ -0,0 +1,67 @@ +from monkey_island.cc.services.config_schema.config_schema_per_attack_technique import ( + get_config_schema_per_attack_technique, +) + +FAKE_SCHEMA = { + "definitions": { + "definition_type_1": { + "title": "Definition Type 1", + "anyOf": [ + { + "title": "Config Option 1", + "attack_techniques": ["T0000", "T0001"], + }, + { + "title": "Config Option 2", + "attack_techniques": ["T0000"], + }, + { + "title": "Config Option 3", + "attack_techniques": [], + }, + { + "title": "Config Option 4", + }, + ], + }, + "definition_type_2": { + "title": "Definition Type 2", + "anyOf": [ + { + "title": "Config Option 5", + "attack_techniques": ["T0000", "T0001"], + }, + { + "title": "Config Option 6", + "attack_techniques": ["T0000"], + }, + { + "title": "Config Option 7", + "attack_techniques": [], + }, + { + "title": "Config Option 8", + }, + ], + }, + } +} + +REVERSE_FAKE_SCHEMA = { + "T0000": { + "Definition Type 1": ["Config Option 1", "Config Option 2"], + "Definition Type 2": ["Config Option 5", "Config Option 6"], + }, + "T0001": { + "Definition Type 1": ["Config Option 1"], + "Definition Type 2": ["Config Option 5"], + }, +} + + +def test_get_config_schema_per_attack_technique(monkeypatch): + monkeypatch.setattr( + "monkey_island.cc.services.config_schema.config_schema_per_attack_technique.SCHEMA", + FAKE_SCHEMA, + ) + assert get_config_schema_per_attack_technique() == REVERSE_FAKE_SCHEMA From 90f3cff3cdd5f5f3545c199c4af5a323e788b2ca Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Fri, 24 Sep 2021 16:33:57 +0530 Subject: [PATCH 13/26] tests: Add unit tests for `get_message_by_status()` in monkey_island\cc\services\attack\technique_reports\__init__.py --- .../test_technique_reports.py | 174 ++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 monkey/tests/unit_tests/monkey_island/cc/services/attack/technique_reports/test_technique_reports.py diff --git a/monkey/tests/unit_tests/monkey_island/cc/services/attack/technique_reports/test_technique_reports.py b/monkey/tests/unit_tests/monkey_island/cc/services/attack/technique_reports/test_technique_reports.py new file mode 100644 index 000000000..6436d6df3 --- /dev/null +++ b/monkey/tests/unit_tests/monkey_island/cc/services/attack/technique_reports/test_technique_reports.py @@ -0,0 +1,174 @@ +from common.utils.attack_utils import ScanStatus +from monkey_island.cc.services.attack.technique_reports.__init__ import ( + AttackTechnique, + disabled_msg, +) + +FAKE_CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE = { + "T0000": { + "Definition Type 1": ["Config Option 1", "Config Option 2"], + "Definition Type 2": ["Config Option 5", "Config Option 6"], + }, + "T0001": { + "Definition Type 1": ["Config Option 1"], + "Definition Type 2": ["Config Option 5"], + }, +} + + +class FakeAttackTechnique(AttackTechnique): + tech_id = "T0001" + relevant_systems = ["System 1", "System 2"] + unscanned_msg = "UNSCANNED" + scanned_msg = "SCANNED" + used_msg = "USED" + + def get_report_data(): + pass + + +EXPECTED_UNSCANNED_MSG = ( + "UNSCANNED due to one of the following reasons:\n" + "- The following configuration options were disabled:
" + "- Definition Type 1 — Config Option 1
" + "- Definition Type 2 — Config Option 5
" +) + + +EXPECTED_SCANNED_MSG = "SCANNED" + + +EXPECTED_USED_MSG = "USED" + + +def test_get_message_by_status_disabled(monkeypatch): + monkeypatch.setattr( + ( + "monkey_island.cc.services.attack.technique_reports." + "__init__.CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE" + ), + FAKE_CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE, + ) + technique_msg = FakeAttackTechnique.get_message_by_status(ScanStatus.DISABLED.value) + assert technique_msg == disabled_msg + + +def test_get_message_by_status_unscanned(monkeypatch): + monkeypatch.setattr( + ( + "monkey_island.cc.services.attack.technique_reports." + "__init__.CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE" + ), + FAKE_CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE, + ) + technique_msg = FakeAttackTechnique.get_message_by_status(ScanStatus.UNSCANNED.value) + assert technique_msg == EXPECTED_UNSCANNED_MSG + + +def test_get_message_by_status_scanned(monkeypatch): + monkeypatch.setattr( + ( + "monkey_island.cc.services.attack.technique_reports." + "__init__.CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE" + ), + FAKE_CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE, + ) + technique_msg = FakeAttackTechnique.get_message_by_status(ScanStatus.SCANNED.value) + assert technique_msg == EXPECTED_SCANNED_MSG + + +def test_get_message_by_status_used(monkeypatch): + monkeypatch.setattr( + ( + "monkey_island.cc.services.attack.technique_reports." + "__init__.CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE" + ), + FAKE_CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE, + ) + technique_msg = FakeAttackTechnique.get_message_by_status(ScanStatus.USED.value) + assert technique_msg == EXPECTED_USED_MSG + + +### + + +class FakeAttackTechnique_OneRelevantSystem(AttackTechnique): + tech_id = "T0001" + relevant_systems = ["System 1"] + unscanned_msg = "UNSCANNED" + scanned_msg = "SCANNED" + used_msg = "USED" + + def get_report_data(): + pass + + +EXPECTED_UNSCANNED_MSG_ONE_RELEVANT_SYSTEM = ( + "UNSCANNED due to one of the following reasons:\n" + "- The Monkey did not run on any System 1 systems.\n" + "- The following configuration options were disabled:
" + "- Definition Type 1 — Config Option 1
" + "- Definition Type 2 — Config Option 5
" +) + + +EXPECTED_SCANNED_MSG_ONE_RELEVANT_SYSTEM = "SCANNED" + + +EXPECTED_USED_MSG_ONE_RELEVANT_SYSTEM = "USED" + + +def test_get_message_by_status_disabled_one_relevant_system(monkeypatch): + monkeypatch.setattr( + ( + "monkey_island.cc.services.attack.technique_reports." + "__init__.CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE" + ), + FAKE_CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE, + ) + technique_msg = FakeAttackTechnique_OneRelevantSystem.get_message_by_status( + ScanStatus.DISABLED.value + ) + assert technique_msg == disabled_msg + + +def test_get_message_by_status_unscanned_one_relevant_system(monkeypatch): + monkeypatch.setattr( + ( + "monkey_island.cc.services.attack.technique_reports." + "__init__.CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE" + ), + FAKE_CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE, + ) + technique_msg = FakeAttackTechnique_OneRelevantSystem.get_message_by_status( + ScanStatus.UNSCANNED.value + ) + assert technique_msg == EXPECTED_UNSCANNED_MSG_ONE_RELEVANT_SYSTEM + + +def test_get_message_by_status_scanned_one_relevant_system(monkeypatch): + monkeypatch.setattr( + ( + "monkey_island.cc.services.attack.technique_reports." + "__init__.CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE" + ), + FAKE_CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE, + ) + technique_msg = FakeAttackTechnique_OneRelevantSystem.get_message_by_status( + ScanStatus.SCANNED.value + ) + assert technique_msg == EXPECTED_SCANNED_MSG_ONE_RELEVANT_SYSTEM + + +def test_get_message_by_status_used_one_relevant_system(monkeypatch): + monkeypatch.setattr( + ( + "monkey_island.cc.services.attack.technique_reports." + "__init__.CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE" + ), + FAKE_CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE, + ) + technique_msg = FakeAttackTechnique_OneRelevantSystem.get_message_by_status( + ScanStatus.USED.value + ) + assert technique_msg == EXPECTED_USED_MSG_ONE_RELEVANT_SYSTEM From aff2bad7770fcccdaf2be49f56aa4c1504ba3089 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Fri, 24 Sep 2021 16:42:04 +0530 Subject: [PATCH 14/26] tests: Move some code around in test_technique_reports.py so it's easier to read --- .../test_technique_reports.py | 118 ++++++++++-------- 1 file changed, 63 insertions(+), 55 deletions(-) diff --git a/monkey/tests/unit_tests/monkey_island/cc/services/attack/technique_reports/test_technique_reports.py b/monkey/tests/unit_tests/monkey_island/cc/services/attack/technique_reports/test_technique_reports.py index 6436d6df3..67ef6af0d 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/services/attack/technique_reports/test_technique_reports.py +++ b/monkey/tests/unit_tests/monkey_island/cc/services/attack/technique_reports/test_technique_reports.py @@ -16,7 +16,7 @@ FAKE_CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE = { } -class FakeAttackTechnique(AttackTechnique): +class FakeAttackTechnique_TwoRelevantSystems(AttackTechnique): tech_id = "T0001" relevant_systems = ["System 1", "System 2"] unscanned_msg = "UNSCANNED" @@ -27,7 +27,7 @@ class FakeAttackTechnique(AttackTechnique): pass -EXPECTED_UNSCANNED_MSG = ( +EXPECTED_UNSCANNED_MSG_TWO_RELEVANT_SYSTEMS = ( "UNSCANNED due to one of the following reasons:\n" "- The following configuration options were disabled:
" "- Definition Type 1 — Config Option 1
" @@ -35,61 +35,10 @@ EXPECTED_UNSCANNED_MSG = ( ) -EXPECTED_SCANNED_MSG = "SCANNED" +EXPECTED_SCANNED_MSG_TWO_RELEVANT_SYSTEMS = "SCANNED" -EXPECTED_USED_MSG = "USED" - - -def test_get_message_by_status_disabled(monkeypatch): - monkeypatch.setattr( - ( - "monkey_island.cc.services.attack.technique_reports." - "__init__.CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE" - ), - FAKE_CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE, - ) - technique_msg = FakeAttackTechnique.get_message_by_status(ScanStatus.DISABLED.value) - assert technique_msg == disabled_msg - - -def test_get_message_by_status_unscanned(monkeypatch): - monkeypatch.setattr( - ( - "monkey_island.cc.services.attack.technique_reports." - "__init__.CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE" - ), - FAKE_CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE, - ) - technique_msg = FakeAttackTechnique.get_message_by_status(ScanStatus.UNSCANNED.value) - assert technique_msg == EXPECTED_UNSCANNED_MSG - - -def test_get_message_by_status_scanned(monkeypatch): - monkeypatch.setattr( - ( - "monkey_island.cc.services.attack.technique_reports." - "__init__.CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE" - ), - FAKE_CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE, - ) - technique_msg = FakeAttackTechnique.get_message_by_status(ScanStatus.SCANNED.value) - assert technique_msg == EXPECTED_SCANNED_MSG - - -def test_get_message_by_status_used(monkeypatch): - monkeypatch.setattr( - ( - "monkey_island.cc.services.attack.technique_reports." - "__init__.CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE" - ), - FAKE_CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE, - ) - technique_msg = FakeAttackTechnique.get_message_by_status(ScanStatus.USED.value) - assert technique_msg == EXPECTED_USED_MSG - - -### +EXPECTED_USED_MSG_TWO_RELEVANT_SYSTEMS = "USED" class FakeAttackTechnique_OneRelevantSystem(AttackTechnique): @@ -118,6 +67,65 @@ EXPECTED_SCANNED_MSG_ONE_RELEVANT_SYSTEM = "SCANNED" EXPECTED_USED_MSG_ONE_RELEVANT_SYSTEM = "USED" +def test_get_message_by_status_disabled_two_relevant_systems(monkeypatch): + monkeypatch.setattr( + ( + "monkey_island.cc.services.attack.technique_reports." + "__init__.CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE" + ), + FAKE_CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE, + ) + technique_msg = FakeAttackTechnique_TwoRelevantSystems.get_message_by_status( + ScanStatus.DISABLED.value + ) + assert technique_msg == disabled_msg + + +def test_get_message_by_status_unscanned_two_relevant_systems(monkeypatch): + monkeypatch.setattr( + ( + "monkey_island.cc.services.attack.technique_reports." + "__init__.CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE" + ), + FAKE_CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE, + ) + technique_msg = FakeAttackTechnique_TwoRelevantSystems.get_message_by_status( + ScanStatus.UNSCANNED.value + ) + assert technique_msg == EXPECTED_UNSCANNED_MSG_TWO_RELEVANT_SYSTEMS + + +def test_get_message_by_status_scanned_two_relevant_systems(monkeypatch): + monkeypatch.setattr( + ( + "monkey_island.cc.services.attack.technique_reports." + "__init__.CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE" + ), + FAKE_CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE, + ) + technique_msg = FakeAttackTechnique_TwoRelevantSystems.get_message_by_status( + ScanStatus.SCANNED.value + ) + assert technique_msg == EXPECTED_SCANNED_MSG_TWO_RELEVANT_SYSTEMS + + +def test_get_message_by_status_used_two_relevant_systems(monkeypatch): + monkeypatch.setattr( + ( + "monkey_island.cc.services.attack.technique_reports." + "__init__.CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE" + ), + FAKE_CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE, + ) + technique_msg = FakeAttackTechnique_TwoRelevantSystems.get_message_by_status( + ScanStatus.USED.value + ) + assert technique_msg == EXPECTED_USED_MSG_TWO_RELEVANT_SYSTEMS + + +### + + def test_get_message_by_status_disabled_one_relevant_system(monkeypatch): monkeypatch.setattr( ( From 6f903bd8f1b692083024c1293f82cd8c53ff15e5 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Fri, 24 Sep 2021 17:12:03 +0530 Subject: [PATCH 15/26] tests: Use enums for expected msgs for better readibility in test_technique_reports.py --- .../test_technique_reports.py | 58 +++++++++---------- 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/monkey/tests/unit_tests/monkey_island/cc/services/attack/technique_reports/test_technique_reports.py b/monkey/tests/unit_tests/monkey_island/cc/services/attack/technique_reports/test_technique_reports.py index 67ef6af0d..3563c965a 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/services/attack/technique_reports/test_technique_reports.py +++ b/monkey/tests/unit_tests/monkey_island/cc/services/attack/technique_reports/test_technique_reports.py @@ -1,3 +1,5 @@ +from enum import Enum + from common.utils.attack_utils import ScanStatus from monkey_island.cc.services.attack.technique_reports.__init__ import ( AttackTechnique, @@ -27,18 +29,15 @@ class FakeAttackTechnique_TwoRelevantSystems(AttackTechnique): pass -EXPECTED_UNSCANNED_MSG_TWO_RELEVANT_SYSTEMS = ( - "UNSCANNED due to one of the following reasons:\n" - "- The following configuration options were disabled:
" - "- Definition Type 1 — Config Option 1
" - "- Definition Type 2 — Config Option 5
" -) - - -EXPECTED_SCANNED_MSG_TWO_RELEVANT_SYSTEMS = "SCANNED" - - -EXPECTED_USED_MSG_TWO_RELEVANT_SYSTEMS = "USED" +class ExpectedMsgs_TwoRelevantSystems(Enum): + UNSCANNED: str = ( + "UNSCANNED due to one of the following reasons:\n" + "- The following configuration options were disabled:
" + "- Definition Type 1 — Config Option 1
" + "- Definition Type 2 — Config Option 5
" + ) + SCANNED: str = "SCANNED" + USED: str = "USED" class FakeAttackTechnique_OneRelevantSystem(AttackTechnique): @@ -52,19 +51,16 @@ class FakeAttackTechnique_OneRelevantSystem(AttackTechnique): pass -EXPECTED_UNSCANNED_MSG_ONE_RELEVANT_SYSTEM = ( - "UNSCANNED due to one of the following reasons:\n" - "- The Monkey did not run on any System 1 systems.\n" - "- The following configuration options were disabled:
" - "- Definition Type 1 — Config Option 1
" - "- Definition Type 2 — Config Option 5
" -) - - -EXPECTED_SCANNED_MSG_ONE_RELEVANT_SYSTEM = "SCANNED" - - -EXPECTED_USED_MSG_ONE_RELEVANT_SYSTEM = "USED" +class ExpectedMsgs_OneRelevantSystem(Enum): + UNSCANNED: str = ( + "UNSCANNED due to one of the following reasons:\n" + "- The Monkey did not run on any System 1 systems.\n" + "- The following configuration options were disabled:
" + "- Definition Type 1 — Config Option 1
" + "- Definition Type 2 — Config Option 5
" + ) + SCANNED: str = "SCANNED" + USED: str = "USED" def test_get_message_by_status_disabled_two_relevant_systems(monkeypatch): @@ -92,7 +88,7 @@ def test_get_message_by_status_unscanned_two_relevant_systems(monkeypatch): technique_msg = FakeAttackTechnique_TwoRelevantSystems.get_message_by_status( ScanStatus.UNSCANNED.value ) - assert technique_msg == EXPECTED_UNSCANNED_MSG_TWO_RELEVANT_SYSTEMS + assert technique_msg == ExpectedMsgs_TwoRelevantSystems.UNSCANNED.value def test_get_message_by_status_scanned_two_relevant_systems(monkeypatch): @@ -106,7 +102,7 @@ def test_get_message_by_status_scanned_two_relevant_systems(monkeypatch): technique_msg = FakeAttackTechnique_TwoRelevantSystems.get_message_by_status( ScanStatus.SCANNED.value ) - assert technique_msg == EXPECTED_SCANNED_MSG_TWO_RELEVANT_SYSTEMS + assert technique_msg == ExpectedMsgs_TwoRelevantSystems.SCANNED.value def test_get_message_by_status_used_two_relevant_systems(monkeypatch): @@ -120,7 +116,7 @@ def test_get_message_by_status_used_two_relevant_systems(monkeypatch): technique_msg = FakeAttackTechnique_TwoRelevantSystems.get_message_by_status( ScanStatus.USED.value ) - assert technique_msg == EXPECTED_USED_MSG_TWO_RELEVANT_SYSTEMS + assert technique_msg == ExpectedMsgs_TwoRelevantSystems.USED.value ### @@ -151,7 +147,7 @@ def test_get_message_by_status_unscanned_one_relevant_system(monkeypatch): technique_msg = FakeAttackTechnique_OneRelevantSystem.get_message_by_status( ScanStatus.UNSCANNED.value ) - assert technique_msg == EXPECTED_UNSCANNED_MSG_ONE_RELEVANT_SYSTEM + assert technique_msg == ExpectedMsgs_OneRelevantSystem.UNSCANNED.value def test_get_message_by_status_scanned_one_relevant_system(monkeypatch): @@ -165,7 +161,7 @@ def test_get_message_by_status_scanned_one_relevant_system(monkeypatch): technique_msg = FakeAttackTechnique_OneRelevantSystem.get_message_by_status( ScanStatus.SCANNED.value ) - assert technique_msg == EXPECTED_SCANNED_MSG_ONE_RELEVANT_SYSTEM + assert technique_msg == ExpectedMsgs_OneRelevantSystem.SCANNED.value def test_get_message_by_status_used_one_relevant_system(monkeypatch): @@ -179,4 +175,4 @@ def test_get_message_by_status_used_one_relevant_system(monkeypatch): technique_msg = FakeAttackTechnique_OneRelevantSystem.get_message_by_status( ScanStatus.USED.value ) - assert technique_msg == EXPECTED_USED_MSG_ONE_RELEVANT_SYSTEM + assert technique_msg == ExpectedMsgs_OneRelevantSystem.USED.value From 85e54419f3faa281d6887dca5c6cebbf3581a86e Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Fri, 24 Sep 2021 17:23:59 +0530 Subject: [PATCH 16/26] tests: Extract mocking to an autouse, function-scoped fixture to reduce code in test_technique_reports.py --- .../test_technique_reports.py | 88 +++++-------------- 1 file changed, 21 insertions(+), 67 deletions(-) diff --git a/monkey/tests/unit_tests/monkey_island/cc/services/attack/technique_reports/test_technique_reports.py b/monkey/tests/unit_tests/monkey_island/cc/services/attack/technique_reports/test_technique_reports.py index 3563c965a..acd855e71 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/services/attack/technique_reports/test_technique_reports.py +++ b/monkey/tests/unit_tests/monkey_island/cc/services/attack/technique_reports/test_technique_reports.py @@ -1,5 +1,7 @@ from enum import Enum +import pytest + from common.utils.attack_utils import ScanStatus from monkey_island.cc.services.attack.technique_reports.__init__ import ( AttackTechnique, @@ -18,6 +20,17 @@ FAKE_CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE = { } +@pytest.fixture(scope="function", autouse=True) +def mock_config_schema_per_attack_technique(monkeypatch): + monkeypatch.setattr( + ( + "monkey_island.cc.services.attack.technique_reports." + "__init__.CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE" + ), + FAKE_CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE, + ) + + class FakeAttackTechnique_TwoRelevantSystems(AttackTechnique): tech_id = "T0001" relevant_systems = ["System 1", "System 2"] @@ -63,115 +76,56 @@ class ExpectedMsgs_OneRelevantSystem(Enum): USED: str = "USED" -def test_get_message_by_status_disabled_two_relevant_systems(monkeypatch): - monkeypatch.setattr( - ( - "monkey_island.cc.services.attack.technique_reports." - "__init__.CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE" - ), - FAKE_CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE, - ) +def test_get_message_by_status_disabled_two_relevant_systems(): technique_msg = FakeAttackTechnique_TwoRelevantSystems.get_message_by_status( ScanStatus.DISABLED.value ) assert technique_msg == disabled_msg -def test_get_message_by_status_unscanned_two_relevant_systems(monkeypatch): - monkeypatch.setattr( - ( - "monkey_island.cc.services.attack.technique_reports." - "__init__.CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE" - ), - FAKE_CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE, - ) +def test_get_message_by_status_unscanned_two_relevant_systems(): technique_msg = FakeAttackTechnique_TwoRelevantSystems.get_message_by_status( ScanStatus.UNSCANNED.value ) assert technique_msg == ExpectedMsgs_TwoRelevantSystems.UNSCANNED.value -def test_get_message_by_status_scanned_two_relevant_systems(monkeypatch): - monkeypatch.setattr( - ( - "monkey_island.cc.services.attack.technique_reports." - "__init__.CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE" - ), - FAKE_CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE, - ) +def test_get_message_by_status_scanned_two_relevant_systems(): technique_msg = FakeAttackTechnique_TwoRelevantSystems.get_message_by_status( ScanStatus.SCANNED.value ) assert technique_msg == ExpectedMsgs_TwoRelevantSystems.SCANNED.value -def test_get_message_by_status_used_two_relevant_systems(monkeypatch): - monkeypatch.setattr( - ( - "monkey_island.cc.services.attack.technique_reports." - "__init__.CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE" - ), - FAKE_CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE, - ) +def test_get_message_by_status_used_two_relevant_systems(): technique_msg = FakeAttackTechnique_TwoRelevantSystems.get_message_by_status( ScanStatus.USED.value ) assert technique_msg == ExpectedMsgs_TwoRelevantSystems.USED.value -### - - -def test_get_message_by_status_disabled_one_relevant_system(monkeypatch): - monkeypatch.setattr( - ( - "monkey_island.cc.services.attack.technique_reports." - "__init__.CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE" - ), - FAKE_CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE, - ) +def test_get_message_by_status_disabled_one_relevant_system(): technique_msg = FakeAttackTechnique_OneRelevantSystem.get_message_by_status( ScanStatus.DISABLED.value ) assert technique_msg == disabled_msg -def test_get_message_by_status_unscanned_one_relevant_system(monkeypatch): - monkeypatch.setattr( - ( - "monkey_island.cc.services.attack.technique_reports." - "__init__.CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE" - ), - FAKE_CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE, - ) +def test_get_message_by_status_unscanned_one_relevant_system(): technique_msg = FakeAttackTechnique_OneRelevantSystem.get_message_by_status( ScanStatus.UNSCANNED.value ) assert technique_msg == ExpectedMsgs_OneRelevantSystem.UNSCANNED.value -def test_get_message_by_status_scanned_one_relevant_system(monkeypatch): - monkeypatch.setattr( - ( - "monkey_island.cc.services.attack.technique_reports." - "__init__.CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE" - ), - FAKE_CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE, - ) +def test_get_message_by_status_scanned_one_relevant_system(): technique_msg = FakeAttackTechnique_OneRelevantSystem.get_message_by_status( ScanStatus.SCANNED.value ) assert technique_msg == ExpectedMsgs_OneRelevantSystem.SCANNED.value -def test_get_message_by_status_used_one_relevant_system(monkeypatch): - monkeypatch.setattr( - ( - "monkey_island.cc.services.attack.technique_reports." - "__init__.CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE" - ), - FAKE_CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE, - ) +def test_get_message_by_status_used_one_relevant_system(): technique_msg = FakeAttackTechnique_OneRelevantSystem.get_message_by_status( ScanStatus.USED.value ) From a857d291d8e7f98cc6b13e1c6cac88cb9506fc08 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Fri, 24 Sep 2021 17:32:17 +0530 Subject: [PATCH 17/26] CHANGELOG: Add entry for modifying ATT&CK report messages --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e603c37f..1d3d2552f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ Changelog](https://keepachangelog.com/en/1.0.0/). ### Changed - The name of the "Communicate as new user" post-breach action to "Communicate as backdoor user". #1410 +- ATT&CK report messages (more accurate now). #1483 ### Removed - Internet access check on agent start. #1402 From d6f91e45f721c98e3048a82a529d12e1a14976da Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Fri, 24 Sep 2021 17:35:36 +0530 Subject: [PATCH 18/26] swimm: update exercise Add details about your new PBA JFXftJml8DpmuCPBA9rL --- .swm/JFXftJml8DpmuCPBA9rL.swm | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/.swm/JFXftJml8DpmuCPBA9rL.swm b/.swm/JFXftJml8DpmuCPBA9rL.swm index 925e662f9..096224cd6 100644 --- a/.swm/JFXftJml8DpmuCPBA9rL.swm +++ b/.swm/JFXftJml8DpmuCPBA9rL.swm @@ -17,16 +17,15 @@ "type": "snippet", "path": "monkey/monkey_island/cc/services/config_schema/definitions/post_breach_actions.py", "comments": [], - "firstLineNumber": 56, + "firstLineNumber": 52, "lines": [ " \"Removes the file afterwards.\",", " \"attack_techniques\": [\"T1166\"],", " },", "* {", - "+ # Swimmer: ADD DETAILS HERE!", "* \"type\": \"string\",", "* \"enum\": [\"ScheduleJobs\"],", - "* \"title\": \"Job scheduling\",", + "* \"title\": \"Job Scheduling\",", "* \"safe\": True,", "* \"info\": \"Attempts to create a scheduled job on the system and remove it.\",", "* \"attack_techniques\": [\"T1168\", \"T1053\"],", @@ -42,11 +41,11 @@ } ], "symbols": {}, - "file_version": "2.0.1", + "file_version": "2.0.3", "meta": { - "app_version": "0.4.1-1", + "app_version": "0.5.7-0", "file_blobs": { - "monkey/monkey_island/cc/services/config_schema/definitions/post_breach_actions.py": "ea9b18aba7f71da12c9c82ac39d8a0cf2c472a9c" + "monkey/monkey_island/cc/services/config_schema/definitions/post_breach_actions.py": "7d62ac36e875ca3c249d808250cb3268e4d3d68d" } } } From 1807bfcb3e195c9ad6697fe4eb486329243b6a1a Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Fri, 24 Sep 2021 17:37:59 +0530 Subject: [PATCH 19/26] swimm: update exercise Add a new System Info Collector OwcKMnALpn7tuBaJY1US --- .swm/OwcKMnALpn7tuBaJY1US.swm | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/.swm/OwcKMnALpn7tuBaJY1US.swm b/.swm/OwcKMnALpn7tuBaJY1US.swm index 7c3a32862..0e87dd5e9 100644 --- a/.swm/OwcKMnALpn7tuBaJY1US.swm +++ b/.swm/OwcKMnALpn7tuBaJY1US.swm @@ -77,10 +77,9 @@ " \"attack_techniques\": [\"T1082\"],", " },", "* {", - "+ # SWIMMER: Collector config goes here. Tip: Hostname collection relates to the T1082 and T1016 techniques.", "* \"type\": \"string\",", "* \"enum\": [HOSTNAME_COLLECTOR],", - "* \"title\": \"Hostname collector\",", + "* \"title\": \"Hostname Collector\",", "* \"safe\": True,", "* \"info\": \"Collects machine's hostname.\",", "* \"attack_techniques\": [\"T1082\", \"T1016\"],", @@ -110,7 +109,7 @@ "type": "snippet", "path": "monkey/monkey_island/cc/services/config_schema/monkey.py", "comments": [], - "firstLineNumber": 92, + "firstLineNumber": 91, "lines": [ " \"default\": [", " ENVIRONMENT_COLLECTOR,", @@ -195,14 +194,14 @@ } ], "symbols": {}, - "file_version": "2.0.1", + "file_version": "2.0.3", "meta": { - "app_version": "0.4.4-0", + "app_version": "0.5.7-0", "file_blobs": { "monkey/common/common_consts/system_info_collectors_names.py": "175a054e1408805a4cebbe27e2f9616db40988cf", "monkey/infection_monkey/system_info/collectors/hostname_collector.py": "0aeecd9fb7bde83cccd4501ec03e0da199ec5fc3", - "monkey/monkey_island/cc/services/config_schema/definitions/system_info_collector_classes.py": "9a4a39050eb088876df4fa629e14faf820e714a0", - "monkey/monkey_island/cc/services/config_schema/monkey.py": "e745da5828c63e975625ac2e9b80ce9626324970", + "monkey/monkey_island/cc/services/config_schema/definitions/system_info_collector_classes.py": "072640352fc9d50fe09752cfc951dab7d99271af", + "monkey/monkey_island/cc/services/config_schema/monkey.py": "da06123a95eebf7f0a68861815ee644bb37c8db6", "monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/hostname.py": "e2de4519cbd71bba70e81cf3ff61817437d95a21", "monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py": "7ce4b6fcfbce0d6cd8a60297213c5be1699b22df" } From c2c5710dfad25169542de42bd597bc37a82fec8d Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Fri, 24 Sep 2021 17:41:08 +0530 Subject: [PATCH 20/26] swimm: update exercise Add details about your new PBA JFXftJml8DpmuCPBA9rL --- .swm/JFXftJml8DpmuCPBA9rL.swm | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.swm/JFXftJml8DpmuCPBA9rL.swm b/.swm/JFXftJml8DpmuCPBA9rL.swm index 096224cd6..510b9a2b0 100644 --- a/.swm/JFXftJml8DpmuCPBA9rL.swm +++ b/.swm/JFXftJml8DpmuCPBA9rL.swm @@ -15,14 +15,12 @@ }, { "type": "snippet", - "path": "monkey/monkey_island/cc/services/config_schema/definitions/post_breach_actions.py", - "comments": [], - "firstLineNumber": 52, "lines": [ " \"Removes the file afterwards.\",", " \"attack_techniques\": [\"T1166\"],", " },", "* {", + "+ # Swimmer: ADD DETAILS HERE!", "* \"type\": \"string\",", "* \"enum\": [\"ScheduleJobs\"],", "* \"title\": \"Job Scheduling\",", @@ -33,7 +31,10 @@ " {", " \"type\": \"string\",", " \"enum\": [\"Timestomping\"]," - ] + ], + "firstLineNumber": 52, + "path": "monkey/monkey_island/cc/services/config_schema/definitions/post_breach_actions.py", + "comments": [] }, { "type": "text", From afedde8c052543cf6e89a23f3c3f58bd99629e12 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 27 Sep 2021 20:20:04 +0530 Subject: [PATCH 21/26] island, tests: Pass schema as arg to generate reverse schema instead of generating reverse schema at runtime --- .../config_schema_per_attack_technique.py | 9 +--- ...test_config_schema_per_attack_technique.py | 53 +------------------ .../monkey_island/cc/services/conftest.py | 48 +++++++++++++++++ 3 files changed, 52 insertions(+), 58 deletions(-) diff --git a/monkey/monkey_island/cc/services/config_schema/config_schema_per_attack_technique.py b/monkey/monkey_island/cc/services/config_schema/config_schema_per_attack_technique.py index 61fcae807..4aeab0085 100644 --- a/monkey/monkey_island/cc/services/config_schema/config_schema_per_attack_technique.py +++ b/monkey/monkey_island/cc/services/config_schema/config_schema_per_attack_technique.py @@ -1,9 +1,7 @@ from typing import Dict, List -from monkey_island.cc.services.config_schema.config_schema import SCHEMA - -def get_config_schema_per_attack_technique() -> Dict[str, Dict[str, List[str]]]: +def get_config_schema_per_attack_technique(schema: Dict) -> Dict[str, Dict[str, List[str]]]: """ :return: dictionary mapping each attack technique to relevant config fields; example - { @@ -17,7 +15,7 @@ def get_config_schema_per_attack_technique() -> Dict[str, Dict[str, List[str]]]: """ reverse_schema = {} - definitions = SCHEMA["definitions"] + definitions = schema["definitions"] for definition in definitions: definition_type = definitions[definition]["title"] for field in definitions[definition]["anyOf"]: @@ -37,6 +35,3 @@ def _add_config_field_to_reverse_schema( reverse_schema[attack_technique].setdefault(definition_type, []).append(config_field) else: reverse_schema[attack_technique] = {definition_type: [config_field]} - - -CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE = get_config_schema_per_attack_technique() diff --git a/monkey/tests/unit_tests/monkey_island/cc/services/config_schema/test_config_schema_per_attack_technique.py b/monkey/tests/unit_tests/monkey_island/cc/services/config_schema/test_config_schema_per_attack_technique.py index 2827fd302..bacdae5dd 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/services/config_schema/test_config_schema_per_attack_technique.py +++ b/monkey/tests/unit_tests/monkey_island/cc/services/config_schema/test_config_schema_per_attack_technique.py @@ -2,51 +2,6 @@ from monkey_island.cc.services.config_schema.config_schema_per_attack_technique get_config_schema_per_attack_technique, ) -FAKE_SCHEMA = { - "definitions": { - "definition_type_1": { - "title": "Definition Type 1", - "anyOf": [ - { - "title": "Config Option 1", - "attack_techniques": ["T0000", "T0001"], - }, - { - "title": "Config Option 2", - "attack_techniques": ["T0000"], - }, - { - "title": "Config Option 3", - "attack_techniques": [], - }, - { - "title": "Config Option 4", - }, - ], - }, - "definition_type_2": { - "title": "Definition Type 2", - "anyOf": [ - { - "title": "Config Option 5", - "attack_techniques": ["T0000", "T0001"], - }, - { - "title": "Config Option 6", - "attack_techniques": ["T0000"], - }, - { - "title": "Config Option 7", - "attack_techniques": [], - }, - { - "title": "Config Option 8", - }, - ], - }, - } -} - REVERSE_FAKE_SCHEMA = { "T0000": { "Definition Type 1": ["Config Option 1", "Config Option 2"], @@ -59,9 +14,5 @@ REVERSE_FAKE_SCHEMA = { } -def test_get_config_schema_per_attack_technique(monkeypatch): - monkeypatch.setattr( - "monkey_island.cc.services.config_schema.config_schema_per_attack_technique.SCHEMA", - FAKE_SCHEMA, - ) - assert get_config_schema_per_attack_technique() == REVERSE_FAKE_SCHEMA +def test_get_config_schema_per_attack_technique(monkeypatch, fake_schema): + assert get_config_schema_per_attack_technique(fake_schema) == REVERSE_FAKE_SCHEMA diff --git a/monkey/tests/unit_tests/monkey_island/cc/services/conftest.py b/monkey/tests/unit_tests/monkey_island/cc/services/conftest.py index 7b56c0c13..b89be55f9 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/services/conftest.py +++ b/monkey/tests/unit_tests/monkey_island/cc/services/conftest.py @@ -20,3 +20,51 @@ def config(monkeypatch, IPS, PORT): monkeypatch.setattr(Environment, "_ISLAND_PORT", PORT) config = ConfigService.get_default_config(True) return config + + +@pytest.fixture +def fake_schema(): + return { + "definitions": { + "definition_type_1": { + "title": "Definition Type 1", + "anyOf": [ + { + "title": "Config Option 1", + "attack_techniques": ["T0000", "T0001"], + }, + { + "title": "Config Option 2", + "attack_techniques": ["T0000"], + }, + { + "title": "Config Option 3", + "attack_techniques": [], + }, + { + "title": "Config Option 4", + }, + ], + }, + "definition_type_2": { + "title": "Definition Type 2", + "anyOf": [ + { + "title": "Config Option 5", + "attack_techniques": ["T0000", "T0001"], + }, + { + "title": "Config Option 6", + "attack_techniques": ["T0000"], + }, + { + "title": "Config Option 7", + "attack_techniques": [], + }, + { + "title": "Config Option 8", + }, + ], + }, + } + } From 0804cecb64e8b2fa316eacb54d1dfcafe156fbcb Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 27 Sep 2021 20:29:30 +0530 Subject: [PATCH 22/26] island, tests: Make config_schema_per_attack_technique a class variable instead of generating it every time --- .../attack/technique_reports/__init__.py | 29 +++++++++++++------ .../test_technique_reports.py | 9 ++---- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py b/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py index 88187c410..6d3186e73 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py @@ -1,14 +1,15 @@ import abc import logging -from typing import List +from typing import Dict, List from common.utils.attack_utils import ScanStatus from common.utils.code_utils import abstractstatic from monkey_island.cc.database import mongo from monkey_island.cc.models.attack.attack_mitigations import AttackMitigations from monkey_island.cc.services.attack.attack_config import AttackConfig +from monkey_island.cc.services.config_schema.config_schema import SCHEMA from monkey_island.cc.services.config_schema.config_schema_per_attack_technique import ( - CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE, + get_config_schema_per_attack_technique, ) logger = logging.getLogger(__name__) @@ -108,6 +109,8 @@ class AttackTechnique(object, metaclass=abc.ABCMeta): """ return {"message": cls.get_message_by_status(status), "status": status} + config_schema_per_attack_technique = None + @classmethod def get_message_by_status(cls, status): """ @@ -118,7 +121,13 @@ class AttackTechnique(object, metaclass=abc.ABCMeta): if status == ScanStatus.DISABLED.value: return disabled_msg if status == ScanStatus.UNSCANNED.value: - unscanned_msg = cls._get_unscanned_msg_with_reasons(cls.unscanned_msg) + if not cls.config_schema_per_attack_technique: + cls.config_schema_per_attack_technique = get_config_schema_per_attack_technique( + SCHEMA + ) + unscanned_msg = cls._get_unscanned_msg_with_reasons( + cls.unscanned_msg, cls.config_schema_per_attack_technique + ) return unscanned_msg elif status == ScanStatus.SCANNED.value: return cls.scanned_msg @@ -126,14 +135,16 @@ class AttackTechnique(object, metaclass=abc.ABCMeta): return cls.used_msg @classmethod - def _get_unscanned_msg_with_reasons(cls, unscanned_msg): + def _get_unscanned_msg_with_reasons( + cls, unscanned_msg: str, config_schema_per_attack_technique: Dict + ): reasons = [] if len(cls.relevant_systems) == 1: reasons.append(f"- The Monkey did not run on any {cls.relevant_systems[0]} systems.") - if cls.tech_id in CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE: + if cls.tech_id in config_schema_per_attack_technique: reasons.append( "- The following configuration options were disabled:
" - f"{cls._get_relevant_config_values()}" + f"{cls._get_relevant_config_values(config_schema_per_attack_technique)}" ) if reasons: @@ -146,12 +157,12 @@ class AttackTechnique(object, metaclass=abc.ABCMeta): return unscanned_msg @classmethod - def _get_relevant_config_values(cls): + def _get_relevant_config_values(cls, config_schema_per_attack_technique: Dict): config_options = "" - for config_type in CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE[cls.tech_id]: + for config_type in config_schema_per_attack_technique[cls.tech_id]: config_options += ( f"- {config_type} — " - f"{', '.join(CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE[cls.tech_id][config_type])}
" + f"{', '.join(config_schema_per_attack_technique[cls.tech_id][config_type])}
" ) return config_options diff --git a/monkey/tests/unit_tests/monkey_island/cc/services/attack/technique_reports/test_technique_reports.py b/monkey/tests/unit_tests/monkey_island/cc/services/attack/technique_reports/test_technique_reports.py index acd855e71..40a627e3c 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/services/attack/technique_reports/test_technique_reports.py +++ b/monkey/tests/unit_tests/monkey_island/cc/services/attack/technique_reports/test_technique_reports.py @@ -21,13 +21,10 @@ FAKE_CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE = { @pytest.fixture(scope="function", autouse=True) -def mock_config_schema_per_attack_technique(monkeypatch): +def mock_config_schema_per_attack_technique(monkeypatch, fake_schema): monkeypatch.setattr( - ( - "monkey_island.cc.services.attack.technique_reports." - "__init__.CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE" - ), - FAKE_CONFIG_SCHEMA_PER_ATTACK_TECHNIQUE, + ("monkey_island.cc.services.attack.technique_reports." "__init__.SCHEMA"), + fake_schema, ) From 72caf5a80ae2f06fecdb8d27441692a0910fcd04 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 27 Sep 2021 22:13:37 +0530 Subject: [PATCH 23/26] island: Simplify logic when creating reverse schema Co-authored-by: Mike Salvatore --- .../config_schema/config_schema_per_attack_technique.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/monkey/monkey_island/cc/services/config_schema/config_schema_per_attack_technique.py b/monkey/monkey_island/cc/services/config_schema/config_schema_per_attack_technique.py index 4aeab0085..9b7cd6bb2 100644 --- a/monkey/monkey_island/cc/services/config_schema/config_schema_per_attack_technique.py +++ b/monkey/monkey_island/cc/services/config_schema/config_schema_per_attack_technique.py @@ -31,7 +31,6 @@ def get_config_schema_per_attack_technique(schema: Dict) -> Dict[str, Dict[str, def _add_config_field_to_reverse_schema( definition_type: str, config_field: str, attack_technique: str, reverse_schema: Dict ) -> None: - if attack_technique in reverse_schema: - reverse_schema[attack_technique].setdefault(definition_type, []).append(config_field) - else: - reverse_schema[attack_technique] = {definition_type: [config_field]} + reverse_schema.setdefault(attack_technique, {}) + reverse_schema[attack_technique].setdefault(definition_type, []) + reverse_schema[attack_technique][definition_type].append(config_field) From 6def66cfaf2842eca4eeb1339c4f73521d2fad8d Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 28 Sep 2021 11:45:53 +0530 Subject: [PATCH 24/26] island: Move class variable `config_schema_per_attack_technique` to the top of its class `AttackTechnique` --- .../cc/services/attack/technique_reports/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py b/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py index 6d3186e73..7dcf7a146 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py @@ -23,6 +23,8 @@ disabled_msg = ( class AttackTechnique(object, metaclass=abc.ABCMeta): """ Abstract class for ATT&CK report components """ + config_schema_per_attack_technique = None + @property @abc.abstractmethod def unscanned_msg(self): @@ -109,8 +111,6 @@ class AttackTechnique(object, metaclass=abc.ABCMeta): """ return {"message": cls.get_message_by_status(status), "status": status} - config_schema_per_attack_technique = None - @classmethod def get_message_by_status(cls, status): """ From e5b9f964472a09eee8bbf60d541dce680ed440f6 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 28 Sep 2021 11:49:13 +0530 Subject: [PATCH 25/26] island: Remove 'The' from text to be shown in report, for consistency --- .../cc/services/attack/technique_reports/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py b/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py index 7dcf7a146..30405dd69 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py @@ -140,7 +140,7 @@ class AttackTechnique(object, metaclass=abc.ABCMeta): ): reasons = [] if len(cls.relevant_systems) == 1: - reasons.append(f"- The Monkey did not run on any {cls.relevant_systems[0]} systems.") + reasons.append(f"- Monkey did not run on any {cls.relevant_systems[0]} systems.") if cls.tech_id in config_schema_per_attack_technique: reasons.append( "- The following configuration options were disabled:
" From cb4b845eafb0ab3a50fd739fcd261c260fbb8c56 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 28 Sep 2021 11:51:00 +0530 Subject: [PATCH 26/26] tests: Fix unit test (remove 'The'; see previous commit) --- .../services/attack/technique_reports/test_technique_reports.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/tests/unit_tests/monkey_island/cc/services/attack/technique_reports/test_technique_reports.py b/monkey/tests/unit_tests/monkey_island/cc/services/attack/technique_reports/test_technique_reports.py index 40a627e3c..82a23a9ae 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/services/attack/technique_reports/test_technique_reports.py +++ b/monkey/tests/unit_tests/monkey_island/cc/services/attack/technique_reports/test_technique_reports.py @@ -64,7 +64,7 @@ class FakeAttackTechnique_OneRelevantSystem(AttackTechnique): class ExpectedMsgs_OneRelevantSystem(Enum): UNSCANNED: str = ( "UNSCANNED due to one of the following reasons:\n" - "- The Monkey did not run on any System 1 systems.\n" + "- Monkey did not run on any System 1 systems.\n" "- The following configuration options were disabled:
" "- Definition Type 1 — Config Option 1
" "- Definition Type 2 — Config Option 5
"