diff --git a/.github/ISSUE_TEMPLATE/spike.md b/.github/ISSUE_TEMPLATE/spike.md index 1060ccef8..d42784cba 100644 --- a/.github/ISSUE_TEMPLATE/spike.md +++ b/.github/ISSUE_TEMPLATE/spike.md @@ -1,6 +1,6 @@ --- name: "⌛Spike" -about: Create a spike. +about: Create a spike to investigate a cool idea. title: '' labels: Spike assignees: '' @@ -9,6 +9,11 @@ assignees: '' # Spike + + ## Objective _A description of this spike's objective._ diff --git a/.swm/AzD8XysWg1BBXCjCDkfq.swm b/.swm/AzD8XysWg1BBXCjCDkfq.swm index 6eeb46b0e..83958e466 100644 --- a/.swm/AzD8XysWg1BBXCjCDkfq.swm +++ b/.swm/AzD8XysWg1BBXCjCDkfq.swm @@ -4,31 +4,35 @@ "dod": "Make the max victim number that Monkey will find before stopping configurable by the user instead of constant.", "description": "# Make something configurable\n\nIn this unit, you will learn how to add a configuration option to Monkey and how to use it in the Monkey Agent code. \n\n![computer fire](https://media.giphy.com/media/7J4P7cUur2DlErijp3/giphy.gif \"computer fire\")\n\n## Why is this important?\n\nEnabling users to configure the Monkey's behaviour gives them a lot more freedom in how they want to use the Monkey and enables more use cases.\n\n## What is \"Max victims to find\"?\n\nThe Monkey has a function which finds \"victim\" machines on the network for the Monkey to try and exploit. It's called `get_victim_machines`. This function accepts an argument which limits how many machines the Monkey should find.\n\nWe want to make that value editable by the user instead of constant in the code.\n\n## Manual testing\n\n1. After you've performed the required changes, reload the Server and check your value exists in the Internal tab of the config (see image).\n\n![](https://i.imgur.com/e0XAxuV.png)\n\n2. Set the new value to 1, and run Monkey locally (from source). See that the Monkey only scans one machine.", "summary": "* When changing config schema by adding or deleting keys, you need to update the Blackbox Test configurations as well [here](https://github.com/guardicore/monkey/tree/develop/envs/monkey_zoo/blackbox/island_configs).", - "diff": "diff --git a/monkey/infection_monkey/config.py b/monkey/infection_monkey/config.py\nindex 1fbcb876..67ed19de 100644\n--- a/monkey/infection_monkey/config.py\n+++ b/monkey/infection_monkey/config.py\n@@ -120,9 +120,6 @@\n exploiter_classes = []\n system_info_collector_classes = []\n \n- # how many victims to look for in a single scan iteration\n- victims_max_find = 100\n-\n # how many victims to exploit before stopping\n victims_max_exploit = 100\n \ndiff --git a/monkey/infection_monkey/monkey.py b/monkey/infection_monkey/monkey.py\nindex 444bde45..ff23f671 100644\n--- a/monkey/infection_monkey/monkey.py\n+++ b/monkey/infection_monkey/monkey.py\n@@ -154,7 +154,7 @@\n if not self._keep_running or not WormConfiguration.alive:\n break\n \n- machines = self._network.get_victim_machines(max_find=WormConfiguration.victims_max_find,\n+ machines = self._network.get_victim_machines(max_find=100,\n stop_callback=ControlClient.check_for_stop)\n is_empty = True\n for machine in machines:\ndiff --git a/monkey/monkey_island/cc/services/config_schema/internal.py b/monkey/monkey_island/cc/services/config_schema/internal.py\nindex bdbae246..d6042d35 100644\n--- a/monkey/monkey_island/cc/services/config_schema/internal.py\n+++ b/monkey/monkey_island/cc/services/config_schema/internal.py\n@@ -40,12 +40,6 @@\n \"title\": \"Monkey\",\n \"type\": \"object\",\n \"properties\": {\n- \"victims_max_find\": {\n- \"title\": \"Max victims to find\",\n- \"type\": \"integer\",\n- \"default\": 100,\n- \"description\": \"Determines the maximum number of machines the monkey is allowed to scan\"\n- },\n \"victims_max_exploit\": {\n \"title\": \"Max victims to exploit\",\n \"type\": \"integer\",\n", + "hunksOrder": [ + "monkey/infection_monkey/config.py_0", + "monkey/infection_monkey/monkey.py_0", + "monkey/monkey_island/cc/services/config_schema/internal.py_0" + ], "tests": [], "hints": [ "Look for `victims_max_exploit` - it's rather similar." ], - "app_version": "0.2.1", - "file_version": "1.0.3", + "play_mode": "all", "swimmPatch": { "monkey/infection_monkey/config.py": { "diffType": "MODIFIED", "fileDiffHeader": "diff --git a/monkey/infection_monkey/config.py b/monkey/infection_monkey/config.py\nindex 1fbcb876..67ed19de 100644\n--- a/monkey/infection_monkey/config.py\n+++ b/monkey/infection_monkey/config.py", "hunks": [ { - "swimmHunkMetadata": {}, + "swimmHunkMetadata": { + "hunkComments": [] + }, "hunkDiffLines": [ - "@@ -120,9 +120,6 @@", - " exploiter_classes = []", - " system_info_collector_classes = []", - " ", - "- # how many victims to look for in a single scan iteration", - "- victims_max_find = 100", - "-", - " # how many victims to exploit before stopping", - " victims_max_exploit = 100", - " " + "@@ -131,8 +131,6 @@", + " exploiter_classes = []\r", + " system_info_collector_classes = []\r", + " \r", + "- # how many victims to look for in a single scan iteration\r", + "- victims_max_find = 100\r", + " \r", + " # how many victims to exploit before stopping\r", + " victims_max_exploit = 100\r" ] } ] @@ -38,17 +42,19 @@ "fileDiffHeader": "diff --git a/monkey/infection_monkey/monkey.py b/monkey/infection_monkey/monkey.py\nindex 444bde45..ff23f671 100644\n--- a/monkey/infection_monkey/monkey.py\n+++ b/monkey/infection_monkey/monkey.py", "hunks": [ { - "swimmHunkMetadata": {}, + "swimmHunkMetadata": { + "hunkComments": [] + }, "hunkDiffLines": [ - "@@ -154,7 +154,7 @@", - " if not self._keep_running or not WormConfiguration.alive:", - " break", - " ", - "- machines = self._network.get_victim_machines(max_find=WormConfiguration.victims_max_find,", - "+ machines = self._network.get_victim_machines(max_find=100,", - " stop_callback=ControlClient.check_for_stop)", - " is_empty = True", - " for machine in machines:" + "@@ -159,8 +159,6 @@", + " if not self._keep_running or not WormConfiguration.alive:\r", + " break\r", + " \r", + "- machines = self._network.get_victim_machines(max_find=WormConfiguration.victims_max_find,\r", + "- stop_callback=ControlClient.check_for_stop)\r", + " is_empty = True\r", + " for machine in machines:\r", + " if ControlClient.check_for_stop():\r" ] } ] @@ -58,24 +64,29 @@ "fileDiffHeader": "diff --git a/monkey/monkey_island/cc/services/config_schema/internal.py b/monkey/monkey_island/cc/services/config_schema/internal.py\nindex bdbae246..d6042d35 100644\n--- a/monkey/monkey_island/cc/services/config_schema/internal.py\n+++ b/monkey/monkey_island/cc/services/config_schema/internal.py", "hunks": [ { - "swimmHunkMetadata": {}, + "swimmHunkMetadata": { + "hunkComments": [] + }, "hunkDiffLines": [ "@@ -40,12 +40,6 @@", - " \"title\": \"Monkey\",", - " \"type\": \"object\",", - " \"properties\": {", - "- \"victims_max_find\": {", - "- \"title\": \"Max victims to find\",", - "- \"type\": \"integer\",", - "- \"default\": 100,", - "- \"description\": \"Determines the maximum number of machines the monkey is allowed to scan\"", - "- },", - " \"victims_max_exploit\": {", - " \"title\": \"Max victims to exploit\",", - " \"type\": \"integer\"," + " \"title\": \"Monkey\",\r", + " \"type\": \"object\",\r", + " \"properties\": {\r", + "- \"victims_max_find\": {\r", + "- \"title\": \"Max victims to find\",\r", + "- \"type\": \"integer\",\r", + "- \"default\": 100,\r", + "- \"description\": \"Determines the maximum number of machines the monkey is allowed to scan\"\r", + "- },\r", + " \"victims_max_exploit\": {\r", + " \"title\": \"Max victims to exploit\",\r", + " \"type\": \"integer\",\r" ] } ] } - } + }, + "app_version": "0.3.5-1", + "file_version": "1.0.4", + "last_commit_sha_for_swimm_patch": "17ee823b086f0b027612e2d1864930d2c5593c3e" } \ No newline at end of file diff --git a/.swm/JFXftJml8DpmuCPBA9rL.swm b/.swm/JFXftJml8DpmuCPBA9rL.swm index 7c186126e..d0206a862 100644 --- a/.swm/JFXftJml8DpmuCPBA9rL.swm +++ b/.swm/JFXftJml8DpmuCPBA9rL.swm @@ -1,30 +1,54 @@ { "id": "JFXftJml8DpmuCPBA9rL", "name": "Add details about your new PBA", - "dod": "WW91JTIwc2hvdWxkJTIwYWRkJTIweW91ciUyMG5ldyUyMFBCQSdzJTIwZGV0YWlscyUyMHRvJTIwdGhlJTIwY29uZmlndXJhdGlvbi4=", - "description": "SW4lMjBvcmRlciUyMHRvJTIwbWFrZSUyMHN1cmUlMjB0aGF0JTIwdGhlJTIwbmV3JTIwJTYwU2NoZWR1bGVKb2JzJTYwJTIwUEJBJTIwaXMlMjBzaG93biUyMGluJTIwdGhlJTIwY29uZmlndXJhdGlvbiUyMG9uJTIwdGhlJTIwTW9ua2V5JTIwSXNsYW5kJTJDJTIweW91JTIwbmVlZCUyMHRvJTIwYWRkJTIwaXRzJTIwZGV0YWlscyUyMHRvJTIwdGhlJTIwY29uZmlndXJhdGlvbiUyMGZpbGUocykuJTIwJTNDYnIlM0UlM0NiciUzRSUwQSUwQVNpbmNlJTIwdGhpcyUyMHBhcnRpY3VsYXIlMjBQQkElMjBpcyUyMHJlbGF0ZWQlMjB0byUyMHRoZSUyME1JVFJFJTIwdGVjaG5pcXVlcyUyMCU1QlQxMTY4JTVEKGh0dHBzJTNBJTJGJTJGYXR0YWNrLm1pdHJlLm9yZyUyRnRlY2huaXF1ZXMlMkZUMTE2OCklMjBhbmQlMjAlNUJUMTA1MyU1RChodHRwcyUzQSUyRiUyRmF0dGFjay5taXRyZS5vcmclMkZ0ZWNobmlxdWVzJTJGVDEwNTMpJTJDJTIwbWFrZSUyMHN1cmUlMjB0byUyMGxpbmslMjB0aGUlMjBQQkElMjB3aXRoJTIwdGhlc2UlMjB0ZWNobmlxdWVzJTIwaW4lMjB0aGUlMjBjb25maWd1cmF0aW9uJTIwYXMlMjB3ZWxsLiUyMCUzQ2JyJTNFJTNDYnIlM0UlMEElMEFFYWNoJTIwcGFydCUyMG9mJTIwdGhlJTIwY29uZmlndXJhdGlvbiUyMGhhcyUyMGFuJTIwaW1wb3J0YW50JTIwcm9sZSUyMCUyMCUwQS0lMjAqZW51bSolMjAlRTIlODAlOTQlMjBjb250YWlucyUyMHRoZSUyMHJlbGV2YW50JTIwUEJBJ3MlMjBjbGFzcyUyMG5hbWUocyklMEEtJTIwKnRpdGxlKiUyMCVFMiU4MCU5NCUyMGhvbGRzJTIwdGhlJTIwbmFtZSUyMG9mJTIwdGhlJTIwUEJBJTIwd2hpY2glMjBpcyUyMGRpc3BsYXllZCUyMGluJTIwdGhlJTIwY29uZmlndXJhdGlvbiUyMG9uJTIwdGhlJTIwTW9ua2V5JTIwSXNsYW5kJTBBLSUyMCppbmZvKiUyMCVFMiU4MCU5NCUyMGNvbnNpc3RzJTIwb2YlMjBhbiUyMGVsYWJvcmF0aW9uJTIwb24lMjB0aGUlMjBQQkEncyUyMHdvcmtpbmclMjB3aGljaCUyMGlzJTIwZGlzcGxheWVkJTIwaW4lMjB0aGUlMjBjb25maWd1cmF0aW9uJTIwb24lMjB0aGUlMjBNb25rZXklMjBJc2xhbmQlMEEtJTIwKmF0dGFja190ZWNobmlxdWVzKiUyMCVFMiU4MCU5NCUyMGhhcyUyMHRoZSUyMElEcyUyMG9mJTIwdGhlJTIwTUlUUkUlMjB0ZWNobmlxdWVzJTIwYXNzb2NpYXRlZCUyMHdpdGglMjB0aGUlMjBQQkElMEElMEElMjMlMjMlMjBNYW51YWwlMjB0ZXN0JTIwJTIwJTBBT25jZSUyMHlvdSUyMHRoaW5rJTIweW91J3JlJTIwZG9uZS4uLiUwQS0lMjBSdW4lMjB0aGUlMjBNb25rZXklMjBJc2xhbmQlMEEtJTIwWW91JTIwc2hvdWxkJTIwYmUlMjBhYmxlJTIwdG8lMjBzZWUlMjB5b3VyJTIwbmV3JTIwUEJBJTIwdW5kZXIlMjB0aGUlMjAlMjJNb25rZXklMjIlMjB0YWIlMjBpbiUyMHRoZSUyMGNvbmZpZ3VyYXRpb24lMkMlMjBhbG9uZyUyMHdpdGglMjBpdHMlMjBpbmZvcm1hdGlvbiUyMHdoZW4lMjB5b3UlMjBjbGljayUyMG9uJTIwaXQlMEEtJTIwRnVydGhlciUyQyUyMHdoZW4lMjB5b3UlMjBlbmFibGUlMkZkaXNhYmxlJTIwdGhlJTIwYXNzb2NpYXRlZCUyME1JVFJFJTIwdGVjaG5pcXVlcyUyMHVuZGVyJTIwdGhlJTIwQVRUJTI2Q0slMjB0YWIlMjBpbiUyMHRoZSUyMGNvbmZpZ3VyYXRpb24lMkMlMjB0aGUlMjBQQkElMjBzaG91bGQlMjBhbHNvJTIwYmUlMjBlbmFibGVkJTJGZGlzYWJsZWQlMEElMEElM0NpbWclMjBzcmMlM0QlMjJodHRwcyUzQSUyRiUyRmkuaW1ndXIuY29tJTJGYTVWU2tMNS5naWYlMjIlMjBoZWlnaHQlM0Q0MDAlM0U=", - "summary": "LSUyMFRoZSUyMFBCQSUyMGRldGFpbHMlMjBpbiUyMHRoaXMlMjBmaWxlJTIwYXJlJTIwcmVmbGVjdGVkJTIwb24lMjB0aGUlMjBNb25rZXklMjBJc2xhbmQlMjBpbiUyMHRoZSUyMFBCQSUyMGNvbmZpZ3VyYXRpb24uJTBBLSUyMFBCQXMlMjBhcmUlMjBhbHNvJTIwbGlua2VkJTIwdG8lMjB0aGUlMjByZWxldmFudCUyME1JVFJFJTIwdGVjaG5pcXVlcyUyMGluJTIwdGhpcyUyMGZpbGUlMkMlMjB3aG9zZSUyMHJlc3VsdHMlMjBjYW4lMjB0aGVuJTIwYmUlMjBzZWVuJTIwaW4lMjB0aGUlMjBNSVRSRSUyMEFUVCUyNkNLJTIwcmVwb3J0JTIwb24lMjB0aGUlMjBNb25rZXklMjBJc2xhbmQu", - "diff": "ZGlmZiUyMC0tZ2l0JTIwYSUyRm1vbmtleSUyRm1vbmtleV9pc2xhbmQlMkZjYyUyRnNlcnZpY2VzJTJGY29uZmlnX3NjaGVtYSUyRmRlZmluaXRpb25zJTJGcG9zdF9icmVhY2hfYWN0aW9ucy5weSUyMGIlMkZtb25rZXklMkZtb25rZXlfaXNsYW5kJTJGY2MlMkZzZXJ2aWNlcyUyRmNvbmZpZ19zY2hlbWElMkZkZWZpbml0aW9ucyUyRnBvc3RfYnJlYWNoX2FjdGlvbnMucHklMEFpbmRleCUyMGYxZmUwZjZmLi5jY2UzN2IyNCUyMDEwMDY0NCUwQS0tLSUyMGElMkZtb25rZXklMkZtb25rZXlfaXNsYW5kJTJGY2MlMkZzZXJ2aWNlcyUyRmNvbmZpZ19zY2hlbWElMkZkZWZpbml0aW9ucyUyRnBvc3RfYnJlYWNoX2FjdGlvbnMucHklMEElMkIlMkIlMkIlMjBiJTJGbW9ua2V5JTJGbW9ua2V5X2lzbGFuZCUyRmNjJTJGc2VydmljZXMlMkZjb25maWdfc2NoZW1hJTJGZGVmaW5pdGlvbnMlMkZwb3N0X2JyZWFjaF9hY3Rpb25zLnB5JTBBJTQwJTQwJTIwLTYyJTJDMTUlMjAlMkI2MiUyQzclMjAlNDAlNDAlMjBQT1NUX0JSRUFDSF9BQ1RJT05TJTIwJTNEJTIwJTdCJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIyUmVtb3ZlcyUyMHRoZSUyMGZpbGUlMjBhZnRlcndhcmRzLiUyMiUyQyUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMmF0dGFja190ZWNobmlxdWVzJTIyJTNBJTIwJTVCJTIyVDExNjYlMjIlNUQlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlN0QlMkMlMEEtJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTdCJTBBLSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMnR5cGUlMjIlM0ElMjAlMjJzdHJpbmclMjIlMkMlMEEtJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIyZW51bSUyMiUzQSUyMCU1QiUwQS0lMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjJTY2hlZHVsZUpvYnMlMjIlMEEtJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTVEJTJDJTBBLSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMnRpdGxlJTIyJTNBJTIwJTIySm9iJTIwc2NoZWR1bGluZyUyMiUyQyUwQS0lMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjJpbmZvJTIyJTNBJTIwJTIyQXR0ZW1wdHMlMjB0byUyMGNyZWF0ZSUyMGElMjBzY2hlZHVsZWQlMjBqb2IlMjBvbiUyMHRoZSUyMHN5c3RlbSUyMGFuZCUyMHJlbW92ZSUyMGl0LiUyMiUyQyUwQS0lMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjJhdHRhY2tfdGVjaG5pcXVlcyUyMiUzQSUyMCU1QiUyMlQxMTY4JTIyJTJDJTIwJTIyVDEwNTMlMjIlNUQlMEEtJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTdEJTJDJTBBJTJCJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIzJTIwU3dpbW1lciUzQSUyMEFERCUyMERFVEFJTFMlMjBIRVJFISUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCU3QiUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMnR5cGUlMjIlM0ElMjAlMjJzdHJpbmclMjIlMkMlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjJlbnVtJTIyJTNBJTIwJTVCJTBB", + "dod": "You should add your new PBA's details to the configuration.", + "description": "In order to make sure that the new `ScheduleJobs` PBA is shown in the configuration on the Monkey Island, you need to add its details to the configuration file(s).

\n\nSince this particular PBA is related to the MITRE techniques [T1168](https://attack.mitre.org/techniques/T1168) and [T1053](https://attack.mitre.org/techniques/T1053), make sure to link the PBA with these techniques in the configuration as well.

\n\nEach part of the configuration has an important role \n- *enum* — contains the relevant PBA's class name(s)\n- *title* — holds the name of the PBA which is displayed in the configuration on the Monkey Island\n- *info* — consists of an elaboration on the PBA's working which is displayed in the configuration on the Monkey Island\n- *attack_techniques* — has the IDs of the MITRE techniques associated with the PBA\n\n## Manual test \nOnce you think you're done...\n- Run the Monkey Island\n- You should be able to see your new PBA under the \"Monkey\" tab in the configuration, along with its information when you click on it\n- Further, when you enable/disable the associated MITRE techniques under the ATT&CK tab in the configuration, the PBA should also be enabled/disabled\n\n", + "summary": "- The PBA details in this file are reflected on the Monkey Island in the PBA configuration.\n- PBAs are also linked to the relevant MITRE techniques in this file, whose results can then be seen in the MITRE ATT&CK report on the Monkey Island.", + "hunksOrder": [ + "monkey/monkey_island/cc/services/config_schema/definitions/post_breach_actions.py_0" + ], "tests": [], "hints": [ "Have a look at the details of the other techniques." ], - "files": { + "play_mode": "all", + "swimmPatch": { "monkey/monkey_island/cc/services/config_schema/definitions/post_breach_actions.py": { - "index": [ - "f1fe0f6f..cce37b24", - "100644" - ], - "fileA": "monkey/monkey_island/cc/services/config_schema/definitions/post_breach_actions.py", - "fileB": "monkey/monkey_island/cc/services/config_schema/definitions/post_breach_actions.py", - "status": "MODIFIED", - "numLineDeletions": 9, - "numLineAdditions": 1, - "hunkContainers": [ - "JTdCJTIyaHVuayUyMiUzQSU3QiUyMmhlYWRlciUyMiUzQSUyMiU0MCU0MCUyMC02MiUyQzE1JTIwJTJCNjIlMkM3JTIwJTQwJTQwJTIwUE9TVF9CUkVBQ0hfQUNUSU9OUyUyMCUzRCUyMCU3QiUyMiUyQyUyMmNoYW5nZXMlMjIlM0ElNUIlN0IlMjJ0eXBlJTIyJTNBJTIyY29udGV4dCUyMiUyQyUyMmRhdGElMjIlM0ElMjIlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlNUMlMjJSZW1vdmVzJTIwdGhlJTIwZmlsZSUyMGFmdGVyd2FyZHMuJTVDJTIyJTJDJTIyJTJDJTIybGluZU51bWJlcnMlMjIlM0ElN0IlMjJhJTIyJTNBNjIlMkMlMjJiJTIyJTNBNjIlN0QlN0QlMkMlN0IlMjJ0eXBlJTIyJTNBJTIyY29udGV4dCUyMiUyQyUyMmRhdGElMjIlM0ElMjIlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlNUMlMjJhdHRhY2tfdGVjaG5pcXVlcyU1QyUyMiUzQSUyMCU1QiU1QyUyMlQxMTY2JTVDJTIyJTVEJTIyJTJDJTIybGluZU51bWJlcnMlMjIlM0ElN0IlMjJhJTIyJTNBNjMlMkMlMjJiJTIyJTNBNjMlN0QlN0QlMkMlN0IlMjJ0eXBlJTIyJTNBJTIyY29udGV4dCUyMiUyQyUyMmRhdGElMjIlM0ElMjIlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlN0QlMkMlMjIlMkMlMjJsaW5lTnVtYmVycyUyMiUzQSU3QiUyMmElMjIlM0E2NCUyQyUyMmIlMjIlM0E2NCU3RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJkZWwlMjIlMkMlMjJtYXJrJTIyJTNBJTIyLSUyMiUyQyUyMmRhdGElMjIlM0ElMjIlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlN0IlMjIlMkMlMjJsaW5lTnVtYmVycyUyMiUzQSU3QiUyMmElMjIlM0E2NSU3RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJkZWwlMjIlMkMlMjJtYXJrJTIyJTNBJTIyLSUyMiUyQyUyMmRhdGElMjIlM0ElMjIlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlNUMlMjJ0eXBlJTVDJTIyJTNBJTIwJTVDJTIyc3RyaW5nJTVDJTIyJTJDJTIyJTJDJTIybGluZU51bWJlcnMlMjIlM0ElN0IlMjJhJTIyJTNBNjYlN0QlN0QlMkMlN0IlMjJ0eXBlJTIyJTNBJTIyZGVsJTIyJTJDJTIybWFyayUyMiUzQSUyMi0lMjIlMkMlMjJkYXRhJTIyJTNBJTIyJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTVDJTIyZW51bSU1QyUyMiUzQSUyMCU1QiUyMiUyQyUyMmxpbmVOdW1iZXJzJTIyJTNBJTdCJTIyYSUyMiUzQTY3JTdEJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMmRlbCUyMiUyQyUyMm1hcmslMjIlM0ElMjItJTIyJTJDJTIyZGF0YSUyMiUzQSUyMiUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCU1QyUyMlNjaGVkdWxlSm9icyU1QyUyMiUyMiUyQyUyMmxpbmVOdW1iZXJzJTIyJTNBJTdCJTIyYSUyMiUzQTY4JTdEJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMmRlbCUyMiUyQyUyMm1hcmslMjIlM0ElMjItJTIyJTJDJTIyZGF0YSUyMiUzQSUyMiUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCU1RCUyQyUyMiUyQyUyMmxpbmVOdW1iZXJzJTIyJTNBJTdCJTIyYSUyMiUzQTY5JTdEJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMmRlbCUyMiUyQyUyMm1hcmslMjIlM0ElMjItJTIyJTJDJTIyZGF0YSUyMiUzQSUyMiUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCU1QyUyMnRpdGxlJTVDJTIyJTNBJTIwJTVDJTIySm9iJTIwc2NoZWR1bGluZyU1QyUyMiUyQyUyMiUyQyUyMmxpbmVOdW1iZXJzJTIyJTNBJTdCJTIyYSUyMiUzQTcwJTdEJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMmRlbCUyMiUyQyUyMm1hcmslMjIlM0ElMjItJTIyJTJDJTIyZGF0YSUyMiUzQSUyMiUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCU1QyUyMmluZm8lNUMlMjIlM0ElMjAlNUMlMjJBdHRlbXB0cyUyMHRvJTIwY3JlYXRlJTIwYSUyMHNjaGVkdWxlZCUyMGpvYiUyMG9uJTIwdGhlJTIwc3lzdGVtJTIwYW5kJTIwcmVtb3ZlJTIwaXQuJTVDJTIyJTJDJTIyJTJDJTIybGluZU51bWJlcnMlMjIlM0ElN0IlMjJhJTIyJTNBNzElN0QlN0QlMkMlN0IlMjJ0eXBlJTIyJTNBJTIyZGVsJTIyJTJDJTIybWFyayUyMiUzQSUyMi0lMjIlMkMlMjJkYXRhJTIyJTNBJTIyJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTVDJTIyYXR0YWNrX3RlY2huaXF1ZXMlNUMlMjIlM0ElMjAlNUIlNUMlMjJUMTE2OCU1QyUyMiUyQyUyMCU1QyUyMlQxMDUzJTVDJTIyJTVEJTIyJTJDJTIybGluZU51bWJlcnMlMjIlM0ElN0IlMjJhJTIyJTNBNzIlN0QlN0QlMkMlN0IlMjJ0eXBlJTIyJTNBJTIyZGVsJTIyJTJDJTIybWFyayUyMiUzQSUyMi0lMjIlMkMlMjJkYXRhJTIyJTNBJTIyJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTdEJTJDJTIyJTJDJTIybGluZU51bWJlcnMlMjIlM0ElN0IlMjJhJTIyJTNBNzMlN0QlN0QlMkMlN0IlMjJ0eXBlJTIyJTNBJTIyYWRkJTIyJTJDJTIybWFyayUyMiUzQSUyMiUyQiUyMiUyQyUyMmRhdGElMjIlM0ElMjIlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjMlMjBTd2ltbWVyJTNBJTIwQUREJTIwREVUQUlMUyUyMEhFUkUhJTIyJTJDJTIybGluZU51bWJlcnMlMjIlM0ElN0IlMjJiJTIyJTNBNjUlN0QlN0QlMkMlN0IlMjJ0eXBlJTIyJTNBJTIyY29udGV4dCUyMiUyQyUyMmRhdGElMjIlM0ElMjIlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlN0IlMjIlMkMlMjJsaW5lTnVtYmVycyUyMiUzQSU3QiUyMmElMjIlM0E3NCUyQyUyMmIlMjIlM0E2NiU3RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJjb250ZXh0JTIyJTJDJTIyZGF0YSUyMiUzQSUyMiUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCU1QyUyMnR5cGUlNUMlMjIlM0ElMjAlNUMlMjJzdHJpbmclNUMlMjIlMkMlMjIlMkMlMjJsaW5lTnVtYmVycyUyMiUzQSU3QiUyMmElMjIlM0E3NSUyQyUyMmIlMjIlM0E2NyU3RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJjb250ZXh0JTIyJTJDJTIyZGF0YSUyMiUzQSUyMiUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCU1QyUyMmVudW0lNUMlMjIlM0ElMjAlNUIlMjIlMkMlMjJsaW5lTnVtYmVycyUyMiUzQSU3QiUyMmElMjIlM0E3NiUyQyUyMmIlMjIlM0E2OCU3RCU3RCU1RCUyQyUyMmxpbmVOdW1iZXJzJTIyJTNBJTdCJTIyYSUyMiUzQSU3QiUyMnN0YXJ0TGluZSUyMiUzQTYyJTJDJTIybGluZXNDb3VudCUyMiUzQTE1JTdEJTJDJTIyYiUyMiUzQSU3QiUyMnN0YXJ0TGluZSUyMiUzQTYyJTJDJTIybGluZXNDb3VudCUyMiUzQTclN0QlN0QlN0QlN0Q=" + "diffType": "MODIFIED", + "fileDiffHeader": "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\nindex f1fe0f6f..b231f96c 100644\n--- a/monkey/monkey_island/cc/services/config_schema/definitions/post_breach_actions.py\n+++ b/monkey/monkey_island/cc/services/config_schema/definitions/post_breach_actions.py", + "hunks": [ + { + "swimmHunkMetadata": { + "hunkComments": [] + }, + "hunkDiffLines": [ + "@@ -68,16 +68,7 @@", + " \"Removes the file afterwards.\",", + " \"attack_techniques\": [\"T1166\"]", + " },", + "- {", + "+ # Swimmer: ADD DETAILS HERE!", + "- \"type\": \"string\",", + "- \"enum\": [", + "- \"ScheduleJobs\"", + "- ],", + "- \"title\": \"Job scheduling\",", + "- \"safe\": True,", + "- \"info\": \"Attempts to create a scheduled job on the system and remove it.\",", + "- \"attack_techniques\": [\"T1168\", \"T1053\"]", + "- },", + " {", + " \"type\": \"string\",", + " \"enum\": [" + ] + } ] } }, - "app_version": "0.1.90", - "file_version": "1.0.2" + "app_version": "0.3.5-1", + "file_version": "1.0.4", + "hunksOrder": [ + "monkey/monkey_island/cc/services/config_schema/definitions/post_breach_actions.py_0" + ], + "last_commit_sha_for_swimm_patch": "9d9e8168fb2c23367b9947273aa1a041687b3e2e" } \ No newline at end of file diff --git a/.swm/OwcKMnALpn7tuBaJY1US.swm b/.swm/OwcKMnALpn7tuBaJY1US.swm index c163bcc98..a243319d2 100644 --- a/.swm/OwcKMnALpn7tuBaJY1US.swm +++ b/.swm/OwcKMnALpn7tuBaJY1US.swm @@ -4,6 +4,17 @@ "dod": "Add a system info collector that collects the machine hostname.", "description": "# What are system info collectors?\n\nWell, the name pretty much explains it. They are Monkey classes which collect various information regarding the victim system, such as Environment, SSH Info, Process List, Netstat and more. \n\n## What should I add? \n\nA system info collector which collects the hostname of the system.\n\n## Test manually\n\nOnce you're done, make sure that your collector:\n* Appears in the Island configuration, and is enabled by default\n* The collector actually runs when executing a Monkey.\n* Results show up in the relevant places:\n * The infection map.\n * The security report.\n * The relevant MITRE techniques.\n\n**There are a lot of hints for this unit - don't be afraid to use them!**", "summary": "System info collectors are useful to get more data for various things, such as ZT tests or MITRE techniques. Take a look at some other techniques!", + "hunksOrder": [ + "monkey/common/data/system_info_collectors_names.py_0", + "monkey/infection_monkey/system_info/collectors/hostname_collector.py_0", + "monkey/monkey_island/cc/services/config_schema/definitions/system_info_collector_classes.py_0", + "monkey/monkey_island/cc/services/config_schema/definitions/system_info_collector_classes.py_1", + "monkey/monkey_island/cc/services/config_schema/monkey.py_0", + "monkey/monkey_island/cc/services/config_schema/monkey.py_1", + "monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/hostname.py_0", + "monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py_0", + "monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py_1" + ], "tests": [], "hints": [ "First thing you should do is take a look at a different collector (like EnvironmentCollector) and 100% understand how it runs, how results are relayed back to the server, and how the server processes the data.", @@ -11,13 +22,16 @@ "Take a look at SystemInfoCollector - that's the base class you'll need to implement.", "Make sure you add the new collector to the configuration in all relevant places, including making it ON by default!" ], + "play_mode": "all", "swimmPatch": { - "monkey/common/common_consts/system_info_collectors_names.py": { + "monkey/common/data/system_info_collectors_names.py": { "diffType": "MODIFIED", - "fileDiffHeader": "diff --git a/monkey/common/common_consts/system_info_collectors_names.py b/monkey/common/common_consts/system_info_collectors_names.py\nindex c93cb253..bce6f86e 100644\n--- a/monkey/common/common_consts/system_info_collectors_names.py\n+++ b/monkey/common/common_consts/system_info_collectors_names.py", + "fileDiffHeader": "diff --git a/monkey/common/data/system_info_collectors_names.py b/monkey/common/data/system_info_collectors_names.py\nindex 175a054e..3b478dc9 100644\n--- a/monkey/common/data/system_info_collectors_names.py\n+++ b/monkey/common/data/system_info_collectors_names.py", "hunks": [ { - "swimmHunkMetadata": {}, + "swimmHunkMetadata": { + "hunkComments": [] + }, "hunkDiffLines": [ "@@ -1,5 +1,5 @@", " AWS_COLLECTOR = \"AwsCollector\"", @@ -32,17 +46,20 @@ }, "monkey/infection_monkey/system_info/collectors/hostname_collector.py": { "diffType": "MODIFIED", - "fileDiffHeader": "diff --git a/monkey/infection_monkey/system_info/collectors/hostname_collector.py b/monkey/infection_monkey/system_info/collectors/hostname_collector.py\nindex 0aeecd9f..4dc6701a 100644\n--- a/monkey/infection_monkey/system_info/collectors/hostname_collector.py\n+++ b/monkey/infection_monkey/system_info/collectors/hostname_collector.py", + "fileDiffHeader": "diff --git a/monkey/infection_monkey/system_info/collectors/hostname_collector.py b/monkey/infection_monkey/system_info/collectors/hostname_collector.py\nindex ae956081..bdeb5033 100644\n--- a/monkey/infection_monkey/system_info/collectors/hostname_collector.py\n+++ b/monkey/infection_monkey/system_info/collectors/hostname_collector.py", "hunks": [ { - "swimmHunkMetadata": {}, + "swimmHunkMetadata": { + "hunkComments": [] + }, "hunkDiffLines": [ - "@@ -1,15 +1,5 @@", + "@@ -1,16 +1,5 @@", " import logging", "-import socket", "-", - "-from common.common_consts.system_info_collectors_names import HOSTNAME_COLLECTOR", - "-from infection_monkey.system_info.system_info_collector import SystemInfoCollector", + "-from common.data.system_info_collectors_names import HOSTNAME_COLLECTOR", + "-from infection_monkey.system_info.system_info_collector import \\", + "- SystemInfoCollector", " ", " logger = logging.getLogger(__name__)", " ", @@ -60,24 +77,29 @@ }, "monkey/monkey_island/cc/services/config_schema/definitions/system_info_collector_classes.py": { "diffType": "MODIFIED", - "fileDiffHeader": "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\nindex 0ea92bea..f4517b90 100644\n--- a/monkey/monkey_island/cc/services/config_schema/definitions/system_info_collector_classes.py\n+++ b/monkey/monkey_island/cc/services/config_schema/definitions/system_info_collector_classes.py", + "fileDiffHeader": "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\nindex 174133f4..de961fbd 100644\n--- a/monkey/monkey_island/cc/services/config_schema/definitions/system_info_collector_classes.py\n+++ b/monkey/monkey_island/cc/services/config_schema/definitions/system_info_collector_classes.py", "hunks": [ { - "swimmHunkMetadata": {}, + "swimmHunkMetadata": { + "hunkComments": [] + }, "hunkDiffLines": [ - "@@ -1,5 +1,5 @@", - " from common.common_consts.system_info_collectors_names import (AWS_COLLECTOR, AZURE_CRED_COLLECTOR,", - "- ENVIRONMENT_COLLECTOR, HOSTNAME_COLLECTOR,", - "+ ENVIRONMENT_COLLECTOR,", - " MIMIKATZ_COLLECTOR, PROCESS_LIST_COLLECTOR)", - " ", - " SYSTEM_INFO_COLLECTOR_CLASSES = {" + "@@ -1,7 +1,6 @@", + " from common.data.system_info_collectors_names import (AWS_COLLECTOR,", + " AZURE_CRED_COLLECTOR,", + " ENVIRONMENT_COLLECTOR,", + "- HOSTNAME_COLLECTOR,", + " MIMIKATZ_COLLECTOR,", + " PROCESS_LIST_COLLECTOR)", + " " ] }, { - "swimmHunkMetadata": {}, + "swimmHunkMetadata": { + "hunkComments": [] + }, "hunkDiffLines": [ - "@@ -34,15 +34,7 @@", + "@@ -40,16 +39,7 @@", " \"info\": \"If on AWS, collects more information about the AWS instance currently running on.\",", " \"attack_techniques\": [\"T1082\"]", " },", @@ -88,6 +110,7 @@ "- HOSTNAME_COLLECTOR", "- ],", "- \"title\": \"Hostname collector\",", + "- \"safe\": True,", "- \"info\": \"Collects machine's hostname.\",", "- \"attack_techniques\": [\"T1082\", \"T1016\"]", "- },", @@ -100,24 +123,29 @@ }, "monkey/monkey_island/cc/services/config_schema/monkey.py": { "diffType": "MODIFIED", - "fileDiffHeader": "diff --git a/monkey/monkey_island/cc/services/config_schema/monkey.py b/monkey/monkey_island/cc/services/config_schema/monkey.py\nindex 01d46367..84cd9123 100644\n--- a/monkey/monkey_island/cc/services/config_schema/monkey.py\n+++ b/monkey/monkey_island/cc/services/config_schema/monkey.py", + "fileDiffHeader": "diff --git a/monkey/monkey_island/cc/services/config_schema/monkey.py b/monkey/monkey_island/cc/services/config_schema/monkey.py\nindex b47d6a15..1b1962a4 100644\n--- a/monkey/monkey_island/cc/services/config_schema/monkey.py\n+++ b/monkey/monkey_island/cc/services/config_schema/monkey.py", "hunks": [ { - "swimmHunkMetadata": {}, + "swimmHunkMetadata": { + "hunkComments": [] + }, "hunkDiffLines": [ - "@@ -1,5 +1,5 @@", - " from common.common_consts.system_info_collectors_names import (AWS_COLLECTOR, AZURE_CRED_COLLECTOR,", - "- ENVIRONMENT_COLLECTOR, HOSTNAME_COLLECTOR,", - "+ ENVIRONMENT_COLLECTOR,", - " MIMIKATZ_COLLECTOR, PROCESS_LIST_COLLECTOR)", - " ", - " MONKEY = {" + "@@ -1,7 +1,6 @@", + " from common.data.system_info_collectors_names import (AWS_COLLECTOR,", + " AZURE_CRED_COLLECTOR,", + " ENVIRONMENT_COLLECTOR,", + "- HOSTNAME_COLLECTOR,", + " MIMIKATZ_COLLECTOR,", + " PROCESS_LIST_COLLECTOR)", + " " ] }, { - "swimmHunkMetadata": {}, + "swimmHunkMetadata": { + "hunkComments": [] + }, "hunkDiffLines": [ - "@@ -85,7 +85,6 @@", + "@@ -88,7 +87,6 @@", " \"default\": [", " ENVIRONMENT_COLLECTOR,", " AWS_COLLECTOR,", @@ -131,17 +159,19 @@ }, "monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/hostname.py": { "diffType": "MODIFIED", - "fileDiffHeader": "diff --git a/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/hostname.py b/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/hostname.py\nindex e2de4519..8764e29d 100644\n--- a/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/hostname.py\n+++ b/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/hostname.py", + "fileDiffHeader": "diff --git a/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/hostname.py b/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/hostname.py\nindex e2de4519..04bc3556 100644\n--- a/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/hostname.py\n+++ b/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/hostname.py", "hunks": [ { - "swimmHunkMetadata": {}, + "swimmHunkMetadata": { + "hunkComments": [] + }, "hunkDiffLines": [ "@@ -1,9 +1,9 @@", " import logging", " ", "-from monkey_island.cc.models.monkey import Monkey", "+# SWIMMER: This will be useful :) monkey_island.cc.models.monkey.Monkey has the useful", - "+# \"get_single_monkey_by_guid\" and \"set_hostname\" methods", + "+# \"get_single_monkey_by_guid\" and \"set_hostname\" methods.", " ", " logger = logging.getLogger(__name__)", " ", @@ -155,42 +185,48 @@ }, "monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py": { "diffType": "MODIFIED", - "fileDiffHeader": "diff --git a/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py b/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py\nindex 1d71c89c..edb1aefa 100644\n--- a/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py\n+++ b/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py", + "fileDiffHeader": "diff --git a/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py b/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py\nindex 639a392c..7aa6d3a6 100644\n--- a/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py\n+++ b/monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/system_info_telemetry_dispatcher.py", "hunks": [ { - "swimmHunkMetadata": {}, + "swimmHunkMetadata": { + "hunkComments": [] + }, "hunkDiffLines": [ - "@@ -2,11 +2,10 @@", - " import typing", + "@@ -3,14 +3,11 @@", " ", - " from common.common_consts.system_info_collectors_names import (", - "- AWS_COLLECTOR, ENVIRONMENT_COLLECTOR, HOSTNAME_COLLECTOR, PROCESS_LIST_COLLECTOR, SCOUTSUITE_COLLECTOR)", - "+ AWS_COLLECTOR, ENVIRONMENT_COLLECTOR, PROCESS_LIST_COLLECTOR, SCOUTSUITE_COLLECTOR)", - " from monkey_island.cc.services.telemetry.processing.system_info_collectors.aws import process_aws_telemetry", + " from common.data.system_info_collectors_names import (AWS_COLLECTOR,", + " ENVIRONMENT_COLLECTOR,", + "- HOSTNAME_COLLECTOR,", + " PROCESS_LIST_COLLECTOR)", + " from monkey_island.cc.services.telemetry.processing.system_info_collectors.aws import \\", + " process_aws_telemetry", " from monkey_island.cc.services.telemetry.processing.system_info_collectors.environment import \\", " process_environment_telemetry", - "-from monkey_island.cc.services.telemetry.processing.system_info_collectors.hostname import process_hostname_telemetry", - " from monkey_island.cc.services.telemetry.processing.system_info_collectors.scoutsuite import \\", - " process_scout_suite_telemetry", - " from monkey_island.cc.services.telemetry.zero_trust_checks.antivirus_existence import check_antivirus_existence" + "-from monkey_island.cc.services.telemetry.processing.system_info_collectors.hostname import \\", + "- process_hostname_telemetry", + " from monkey_island.cc.services.telemetry.zero_trust_tests.antivirus_existence import \\", + " test_antivirus_existence", + " " ] }, { - "swimmHunkMetadata": {}, + "swimmHunkMetadata": { + "hunkComments": [] + }, "hunkDiffLines": [ - "@@ -16,7 +15,6 @@", + "@@ -19,7 +16,6 @@", " SYSTEM_INFO_COLLECTOR_TO_TELEMETRY_PROCESSORS = {", " AWS_COLLECTOR: [process_aws_telemetry],", " ENVIRONMENT_COLLECTOR: [process_environment_telemetry],", "- HOSTNAME_COLLECTOR: [process_hostname_telemetry],", - " PROCESS_LIST_COLLECTOR: [check_antivirus_existence],", - " SCOUTSUITE_COLLECTOR: [process_scout_suite_telemetry]", - " }" + " PROCESS_LIST_COLLECTOR: [test_antivirus_existence]", + " }", + " " ] } ] } }, - "app_version": "0.2.1", - "file_version": "1.0.3" -} + "app_version": "0.3.5-1", + "file_version": "1.0.4" +} \ No newline at end of file diff --git a/.swm/VW4rf3AxRslfT7lwaug7.swm b/.swm/VW4rf3AxRslfT7lwaug7.swm index 743079918..7af1a816c 100644 --- a/.swm/VW4rf3AxRslfT7lwaug7.swm +++ b/.swm/VW4rf3AxRslfT7lwaug7.swm @@ -4,18 +4,19 @@ "dod": "You should implement a new PBA in Monkey which schedules jobs on the machine.", "description": "You need to implement the `ScheduleJobs` PBA which creates scheduled jobs on the machine.

\n

\nThe commands that add scheduled jobs for Windows and Linux can be retrieved from `get_commands_to_schedule_jobs` — make sure you understand how to use this function correctly.\n\n## Manual test \nOnce you think you're done...\n- Run the Monkey Island\n- Make sure the \"Job scheduling\" PBA is enabled in the \"Monkey\" tab in the configuration — for this test, disable network scanning, exploiting, and all other PBAs\n- Run the Monkey\n- Make sure you see the PBA with its results in the Security report as well as in the ATT&CK report under the relevant MITRE technique\n\n\n

\n", "summary": "Many other PBAs are as simple as this one, using shell commands or scripts — see `Timestomping` and `AccountDiscovery`.

\n\nHowever, for less straightforward ones, you can override functions and implement new classes depending on what is required — see `SignedScriptProxyExecution` and `ModifyShellStartupFiles`.

\n\nThis PBA, along with all the other PBAs, will run on a system after it has been breached. The purpose of this code is to test whether target systems allow attackers to schedule jobs, which they could use to run malicious code at some specified date and time.", - "diff": "diff --git a/monkey/infection_monkey/post_breach/actions/schedule_jobs.py b/monkey/infection_monkey/post_breach/actions/schedule_jobs.py\nindex d6cdd276..79a7724d 100644\n--- a/monkey/infection_monkey/post_breach/actions/schedule_jobs.py\n+++ b/monkey/infection_monkey/post_breach/actions/schedule_jobs.py\n@@ -10,11 +10,5 @@\n \"\"\"\n \n def __init__(self):\n- linux_cmds, windows_cmds = get_commands_to_schedule_jobs()\n+ pass\n-\n+ # Swimmer: IMPLEMENT HERE!\n- super(ScheduleJobs, self).__init__(name=POST_BREACH_JOB_SCHEDULING,\n- linux_cmd=' '.join(linux_cmds),\n- windows_cmd=windows_cmds)\n- \n- def run(self):\n- super(ScheduleJobs, self).run()\n", + "hunksOrder": [ + "monkey/infection_monkey/post_breach/actions/schedule_jobs.py_0" + ], "tests": [], "hints": [ "Check out the `Timestomping` PBA to get an idea about the implementation.", "Don't forget to add code to remove the scheduled jobs!" ], - "app_version": "0.2.8", - "file_version": "1.0.4", + "play_mode": "all", "swimmPatch": { "monkey/infection_monkey/post_breach/actions/schedule_jobs.py": { "diffType": "MODIFIED", - "fileDiffHeader": "diff --git a/monkey/infection_monkey/post_breach/actions/schedule_jobs.py b/monkey/infection_monkey/post_breach/actions/schedule_jobs.py\nindex d6cdd276..79a7724d 100644\n--- a/monkey/infection_monkey/post_breach/actions/schedule_jobs.py\n+++ b/monkey/infection_monkey/post_breach/actions/schedule_jobs.py", + "fileDiffHeader": "diff --git a/monkey/infection_monkey/post_breach/actions/schedule_jobs.py b/monkey/infection_monkey/post_breach/actions/schedule_jobs.py\nindex f7d8d805..06839463 100644\n--- a/monkey/infection_monkey/post_breach/actions/schedule_jobs.py\n+++ b/monkey/infection_monkey/post_breach/actions/schedule_jobs.py", "hunks": [ { "swimmHunkMetadata": { @@ -41,6 +42,8 @@ ] } }, + "app_version": "0.3.5-1", + "file_version": "1.0.4", "hunksOrder": [ "monkey/infection_monkey/post_breach/actions/schedule_jobs.py_0" ], diff --git a/.swm/tbxb2cGgUiJQ8Btma0fp.swm b/.swm/tbxb2cGgUiJQ8Btma0fp.swm index 1abf284fe..78a13c872 100644 --- a/.swm/tbxb2cGgUiJQ8Btma0fp.swm +++ b/.swm/tbxb2cGgUiJQ8Btma0fp.swm @@ -4,23 +4,34 @@ "dod": "You should add a new PBA to the Monkey which creates a new user on the machine.", "description": "Read [our documentation about adding a new PBA](https://www.guardicore.com/infectionmonkey/docs/development/adding-post-breach-actions/).\n\nAfter that we want you to add the BackdoorUser PBA. The commands that add users for Win and Linux can be retrieved from `get_commands_to_add_user` - make sure you see how to use this function correctly. \n\nNote that the PBA should impact the T1136 MITRE technique as well! \n\n# Manual test to confirm\n\n1. Run the Monkey Island\n2. Make sure your new PBA is enabled by default in the config - for this test, disable network scanning, exploiting, and all other PBAs\n3. Run Monkey\n4. See the PBA in the security report\n5, See the PBA in the MITRE report in the relevant technique\n", "summary": "Take a look at the configuration of the island again - see the \"command to run after breach\" option we offer the user? It's implemented exactly like you did right now but each user can do it for themselves. \n\nHowever, what if the PBA needs to do stuff which is more complex than just running a few commands? In that case... ", + "hunksOrder": [ + "monkey/common/data/post_breach_consts.py_0", + "monkey/infection_monkey/post_breach/actions/add_user.py_0", + "monkey/monkey_island/cc/services/attack/technique_reports/T1136.py_0", + "monkey/monkey_island/cc/services/attack/technique_reports/T1136.py_1", + "monkey/monkey_island/cc/services/config_schema/definitions/post_breach_actions.py_0" + ], "tests": [], "hints": [ "See `ScheduleJobs` PBA for an example of a PBA which only uses shell commands.", "Make sure to add the PBA to the configuration as well.", "MITRE ATT&CK technique T1136 articulates that adversaries may create an account to maintain access to victim systems, therefore, the BackdoorUser PBA is relevant to it. Make sure to map this PBA to the MITRE ATT&CK configuration and report." ], + "play_mode": "all", "swimmPatch": { - "monkey/common/common_consts/post_breach_consts.py": { + "monkey/common/data/post_breach_consts.py": { "diffType": "MODIFIED", - "fileDiffHeader": "diff --git a/monkey/common/common_consts/post_breach_consts.py b/monkey/common/common_consts/post_breach_consts.py\nindex 25e6679c..5198f006 100644\n--- a/monkey/common/common_consts/post_breach_consts.py\n+++ b/monkey/common/common_consts/post_breach_consts.py", + "fileDiffHeader": "diff --git a/monkey/common/data/post_breach_consts.py b/monkey/common/data/post_breach_consts.py\nindex 25e6679c..05980288 100644\n--- a/monkey/common/data/post_breach_consts.py\n+++ b/monkey/common/data/post_breach_consts.py", "hunks": [ { - "swimmHunkMetadata": {}, + "swimmHunkMetadata": { + "hunkComments": [] + }, "hunkDiffLines": [ - "@@ -1,5 +1,4 @@", + "@@ -1,5 +1,5 @@", " POST_BREACH_COMMUNICATE_AS_NEW_USER = \"Communicate as new user\"", "-POST_BREACH_BACKDOOR_USER = \"Backdoor user\"", + "+# Swimmer: PUT THE NEW CONST HERE!", " POST_BREACH_FILE_EXECUTION = \"File execution\"", " POST_BREACH_SHELL_STARTUP_FILE_MODIFICATION = \"Modify shell startup file\"", " POST_BREACH_HIDDEN_FILES = \"Hide files and directories\"" @@ -30,13 +41,15 @@ }, "monkey/infection_monkey/post_breach/actions/add_user.py": { "diffType": "MODIFIED", - "fileDiffHeader": "diff --git a/monkey/infection_monkey/post_breach/actions/add_user.py b/monkey/infection_monkey/post_breach/actions/add_user.py\nindex a8584584..d8476a97 100644\n--- a/monkey/infection_monkey/post_breach/actions/add_user.py\n+++ b/monkey/infection_monkey/post_breach/actions/add_user.py", + "fileDiffHeader": "diff --git a/monkey/infection_monkey/post_breach/actions/add_user.py b/monkey/infection_monkey/post_breach/actions/add_user.py\nindex 58be89a1..d8476a97 100644\n--- a/monkey/infection_monkey/post_breach/actions/add_user.py\n+++ b/monkey/infection_monkey/post_breach/actions/add_user.py", "hunks": [ { - "swimmHunkMetadata": {}, + "swimmHunkMetadata": { + "hunkComments": [] + }, "hunkDiffLines": [ "@@ -1,15 +1,7 @@", - "-from common.common_consts.post_breach_consts import POST_BREACH_BACKDOOR_USER", + "-from common.data.post_breach_consts import POST_BREACH_BACKDOOR_USER", "-from infection_monkey.config import WormConfiguration", " from infection_monkey.post_breach.pba import PBA", " from infection_monkey.utils.users import get_commands_to_add_user", @@ -58,23 +71,28 @@ }, "monkey/monkey_island/cc/services/attack/technique_reports/T1136.py": { "diffType": "MODIFIED", - "fileDiffHeader": "diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1136.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1136.py\nindex d9d86e08..0abe6a02 100644\n--- a/monkey/monkey_island/cc/services/attack/technique_reports/T1136.py\n+++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1136.py", + "fileDiffHeader": "diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1136.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1136.py\nindex 086a1c13..9f23bb8d 100644\n--- a/monkey/monkey_island/cc/services/attack/technique_reports/T1136.py\n+++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1136.py", "hunks": [ { - "swimmHunkMetadata": {}, + "swimmHunkMetadata": { + "hunkComments": [] + }, "hunkDiffLines": [ - "@@ -1,4 +1,4 @@", - "-from common.common_consts.post_breach_consts import POST_BREACH_BACKDOOR_USER, POST_BREACH_COMMUNICATE_AS_NEW_USER", - "+from common.common_consts.post_breach_consts import POST_BREACH_COMMUNICATE_AS_NEW_USER", - " from monkey_island.cc.services.attack.technique_reports.pba_technique import PostBreachTechnique", - " ", - " __author__ = \"shreyamalviya\"" + "@@ -1,5 +1,5 @@", + " from common.data.post_breach_consts import (", + "- POST_BREACH_BACKDOOR_USER, POST_BREACH_COMMUNICATE_AS_NEW_USER)", + "+ POST_BREACH_COMMUNICATE_AS_NEW_USER)", + " from monkey_island.cc.services.attack.technique_reports.pba_technique import \\", + " PostBreachTechnique", + " " ] }, { - "swimmHunkMetadata": {}, + "swimmHunkMetadata": { + "hunkComments": [] + }, "hunkDiffLines": [ - "@@ -9,4 +9,4 @@", + "@@ -11,4 +11,4 @@", " 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.\"", @@ -89,9 +107,11 @@ "fileDiffHeader": "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\nindex f1fe0f6f..39ebd33a 100644\n--- a/monkey/monkey_island/cc/services/config_schema/definitions/post_breach_actions.py\n+++ b/monkey/monkey_island/cc/services/config_schema/definitions/post_breach_actions.py", "hunks": [ { - "swimmHunkMetadata": {}, + "swimmHunkMetadata": { + "hunkComments": [] + }, "hunkDiffLines": [ - "@@ -4,15 +4,7 @@", + "@@ -4,16 +4,7 @@", " \"might do after breaching a new machine. Used in ATT&CK and Zero trust reports.\",", " \"type\": \"string\",", " \"anyOf\": [", @@ -102,6 +122,7 @@ "- \"BackdoorUser\"", "- ],", "- \"title\": \"Back door user\",", + "- \"safe\": True,", "- \"info\": \"Attempts to create a new user on the system and delete it afterwards.\",", "- \"attack_techniques\": [\"T1136\"]", "- },", @@ -113,6 +134,14 @@ ] } }, - "app_version": "0.2.1", - "file_version": "1.0.3" -} + "app_version": "0.3.5-1", + "file_version": "1.0.4", + "hunksOrder": [ + "monkey/common/data/post_breach_consts.py_0", + "monkey/infection_monkey/post_breach/actions/add_user.py_0", + "monkey/monkey_island/cc/services/attack/technique_reports/T1136.py_0", + "monkey/monkey_island/cc/services/attack/technique_reports/T1136.py_1", + "monkey/monkey_island/cc/services/config_schema/definitions/post_breach_actions.py_0" + ], + "last_commit_sha_for_swimm_patch": "9d9e8168fb2c23367b9947273aa1a041687b3e2e" +} \ No newline at end of file diff --git a/docs/static/images/usage/use-cases/network-breach.PNG b/docs/static/images/usage/use-cases/network-breach.PNG index 5dfd38ffb..871a36bb6 100644 Binary files a/docs/static/images/usage/use-cases/network-breach.PNG and b/docs/static/images/usage/use-cases/network-breach.PNG differ diff --git a/monkey/infection_monkey/model/host.py b/monkey/infection_monkey/model/host.py index 1a4fef1c8..d71446108 100644 --- a/monkey/infection_monkey/model/host.py +++ b/monkey/infection_monkey/model/host.py @@ -7,6 +7,7 @@ class VictimHost(object): self.domain_name = str(domain_name) self.os = {} self.services = {} + self.icmp = False self.monkey_exe = None self.default_tunnel = None self.default_server = None @@ -40,7 +41,7 @@ class VictimHost(object): victim += "] Services - [" for k, v in list(self.services.items()): victim += "%s-%s " % (k, v) - victim += '] ' + victim += '] ICMP: %s ' % (self.icmp) victim += "target monkey: %s" % self.monkey_exe return victim diff --git a/monkey/infection_monkey/network/ping_scanner.py b/monkey/infection_monkey/network/ping_scanner.py index 27c814593..fd19550a3 100644 --- a/monkey/infection_monkey/network/ping_scanner.py +++ b/monkey/infection_monkey/network/ping_scanner.py @@ -62,6 +62,9 @@ class PingScanner(HostScanner, HostFinger): host.os['type'] = 'linux' else: # as far we we know, could also be OSX/BSD but lets handle that when it comes up. host.os['type'] = 'windows' + + host.icmp = True + return True except Exception as exc: LOG.debug("Error parsing ping fingerprint: %s", exc) 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 0a5e671a3..25158d73a 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 @@ -12,6 +12,7 @@ EXPLOITER_CLASSES = { "SmbExploiter" ], "title": "SMB Exploiter", + "safe": True, "attack_techniques": ["T1110", "T1075", "T1035"], "info": "Brute forces using credentials provided by user and" " hashes gathered by mimikatz.", @@ -23,6 +24,7 @@ EXPLOITER_CLASSES = { "WmiExploiter" ], "title": "WMI Exploiter", + "safe": True, "attack_techniques": ["T1110", "T1106"], "info": "Brute forces WMI (Windows Management Instrumentation) " "using credentials provided by user and hashes gathered by mimikatz.", @@ -34,6 +36,7 @@ EXPLOITER_CLASSES = { "MSSQLExploiter" ], "title": "MSSQL Exploiter", + "safe": True, "attack_techniques": ["T1110"], "info": "Tries to brute force into MsSQL server and uses insecure " "configuration to execute commands on server.", @@ -44,7 +47,8 @@ EXPLOITER_CLASSES = { "enum": [ "Ms08_067_Exploiter" ], - "title": "MS08-067 Exploiter (UNSAFE)", + "title": "MS08-067 Exploiter", + "safe": False, "info": "Unsafe exploiter, that might cause system crash due to the use of buffer overflow. " "Uses MS08-067 vulnerability.", "link": "https://www.guardicore.com/infectionmonkey/docs/reference/exploiters/ms08-067/" @@ -55,6 +59,7 @@ EXPLOITER_CLASSES = { "SSHExploiter" ], "title": "SSH Exploiter", + "safe": True, "attack_techniques": ["T1110", "T1145", "T1106"], "info": "Brute forces using credentials provided by user and SSH keys gathered from systems.", "link": "https://www.guardicore.com/infectionmonkey/docs/reference/exploiters/sshexec/" @@ -65,6 +70,7 @@ EXPLOITER_CLASSES = { "ShellShockExploiter" ], "title": "ShellShock Exploiter", + "safe": True, "info": "CVE-2014-6271, based on logic from " "https://github.com/nccgroup/shocker/blob/master/shocker.py .", "link": "https://www.guardicore.com/infectionmonkey/docs/reference/exploiters/shellshock/" @@ -75,6 +81,7 @@ EXPLOITER_CLASSES = { "SambaCryExploiter" ], "title": "SambaCry Exploiter", + "safe": True, "info": "Bruteforces and searches for anonymous shares. Uses Impacket.", "link": "https://www.guardicore.com/infectionmonkey/docs/reference/exploiters/sambacry/" }, @@ -84,6 +91,7 @@ EXPLOITER_CLASSES = { "ElasticGroovyExploiter" ], "title": "ElasticGroovy Exploiter", + "safe": True, "info": "CVE-2015-1427. Logic is based on Metasploit module.", "link": "https://www.guardicore.com/infectionmonkey/docs/reference/exploiters/elasticgroovy/" }, @@ -93,6 +101,7 @@ EXPLOITER_CLASSES = { "Struts2Exploiter" ], "title": "Struts2 Exploiter", + "safe": True, "info": "Exploits struts2 java web framework. CVE-2017-5638. Logic based on " "https://www.exploit-db.com/exploits/41570 .", "link": "https://www.guardicore.com/infectionmonkey/docs/reference/exploiters/struts2/" @@ -103,6 +112,7 @@ EXPLOITER_CLASSES = { "WebLogicExploiter" ], "title": "WebLogic Exploiter", + "safe": True, "info": "Exploits CVE-2017-10271 and CVE-2019-2725 vulnerabilities on WebLogic server.", "link": "https://www.guardicore.com/infectionmonkey/docs/reference/exploiters/weblogic/" }, @@ -112,6 +122,7 @@ EXPLOITER_CLASSES = { "HadoopExploiter" ], "title": "Hadoop/Yarn Exploiter", + "safe": True, "info": "Remote code execution on HADOOP server with YARN and default settings. " "Logic based on https://github.com/vulhub/vulhub/tree/master/hadoop/unauthorized-yarn.", "link": "https://www.guardicore.com/infectionmonkey/docs/reference/exploiters/hadoop/" @@ -122,6 +133,7 @@ EXPLOITER_CLASSES = { "VSFTPDExploiter" ], "title": "VSFTPD Exploiter", + "safe": True, "info": "Exploits a malicious backdoor that was added to the VSFTPD download archive. " "Logic based on Metasploit module.", "link": "https://www.guardicore.com/infectionmonkey/docs/reference/exploiters/vsftpd/" @@ -132,6 +144,7 @@ EXPLOITER_CLASSES = { "DrupalExploiter" ], "title": "Drupal Exploiter", + "safe": True, "info": "Exploits a remote command execution vulnerability in a Drupal server," "for which certain modules (such as RESTful Web Services) are enabled.", "link": "https://www.guardicore.com/infectionmonkey/docs/reference/exploiters/drupal/" 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 405983dc5..5e3f75f33 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 @@ -10,6 +10,7 @@ FINGER_CLASSES = { "SMBFinger" ], "title": "SMBFinger", + "safe": True, "info": "Figures out if SMB is running and what's the version of it.", "attack_techniques": ["T1210"] }, @@ -19,6 +20,7 @@ FINGER_CLASSES = { "SSHFinger" ], "title": "SSHFinger", + "safe": True, "info": "Figures out if SSH is running.", "attack_techniques": ["T1210"] }, @@ -28,6 +30,7 @@ FINGER_CLASSES = { "PingScanner" ], "title": "PingScanner", + "safe": True, "info": "Tries to identify if host is alive and which OS it's running by ping scan." }, { @@ -36,6 +39,7 @@ FINGER_CLASSES = { "HTTPFinger" ], "title": "HTTPFinger", + "safe": True, "info": "Checks if host has HTTP/HTTPS ports open." }, { @@ -44,6 +48,7 @@ FINGER_CLASSES = { "MySQLFinger" ], "title": "MySQLFinger", + "safe": True, "info": "Checks if MySQL server is running and tries to get it's version.", "attack_techniques": ["T1210"] }, @@ -53,6 +58,7 @@ FINGER_CLASSES = { "MSSQLFinger" ], "title": "MSSQLFinger", + "safe": True, "info": "Checks if Microsoft SQL service is running and tries to gather information about it.", "attack_techniques": ["T1210"] }, @@ -62,6 +68,7 @@ FINGER_CLASSES = { "ElasticFinger" ], "title": "ElasticFinger", + "safe": True, "info": "Checks if ElasticSearch is running and attempts to find it's version.", "attack_techniques": ["T1210"] }, @@ -71,6 +78,7 @@ FINGER_CLASSES = { "WindowsServerFinger" ], "title": "WindowsServerFinger", + "safe": True, "info": "Checks if server is a Windows Server and tests if it is vulnerable to Zerologon.", "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 f1fe0f6f2..857e80da4 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 @@ -10,6 +10,7 @@ POST_BREACH_ACTIONS = { "BackdoorUser" ], "title": "Back door user", + "safe": True, "info": "Attempts to create a new user on the system and delete it afterwards.", "attack_techniques": ["T1136"] }, @@ -19,6 +20,7 @@ POST_BREACH_ACTIONS = { "CommunicateAsNewUser" ], "title": "Communicate as new user", + "safe": True, "info": "Attempts to create a new user, create HTTPS requests as that user and delete the user " "afterwards.", "attack_techniques": ["T1136"] @@ -29,6 +31,7 @@ POST_BREACH_ACTIONS = { "ModifyShellStartupFiles" ], "title": "Modify shell startup files", + "safe": True, "info": "Attempts to modify shell startup files, like ~/.profile, ~/.bashrc, ~/.bash_profile " "in linux, and profile.ps1 in windows. Reverts modifications done afterwards.", "attack_techniques": ["T1156", "T1504"] @@ -39,6 +42,7 @@ POST_BREACH_ACTIONS = { "HiddenFiles" ], "title": "Hidden files and directories", + "safe": True, "info": "Attempts to create a hidden file and remove it afterward.", "attack_techniques": ["T1158"] }, @@ -48,6 +52,7 @@ POST_BREACH_ACTIONS = { "TrapCommand" ], "title": "Trap", + "safe": True, "info": "On Linux systems, attempts to trap an interrupt signal in order to execute a command " "upon receiving that signal. Removes the trap afterwards.", "attack_techniques": ["T1154"] @@ -58,6 +63,7 @@ POST_BREACH_ACTIONS = { "ChangeSetuidSetgid" ], "title": "Setuid and Setgid", + "safe": True, "info": "On Linux systems, attempts to set the setuid and setgid bits of a new file. " "Removes the file afterwards.", "attack_techniques": ["T1166"] @@ -68,6 +74,7 @@ POST_BREACH_ACTIONS = { "ScheduleJobs" ], "title": "Job scheduling", + "safe": True, "info": "Attempts to create a scheduled job on the system and remove it.", "attack_techniques": ["T1168", "T1053"] }, @@ -77,6 +84,7 @@ POST_BREACH_ACTIONS = { "Timestomping" ], "title": "Timestomping", + "safe": True, "info": "Creates a temporary file and attempts to modify its time attributes. Removes the file afterwards.", "attack_techniques": ["T1099"] }, @@ -86,7 +94,8 @@ POST_BREACH_ACTIONS = { "SignedScriptProxyExecution" ], "title": "Signed script proxy execution", - "info": "On Windows systems, attemps to execute an arbitrary file " + "safe": False, + "info": "On Windows systems, attempts to execute an arbitrary file " "with the help of a pre-existing signed script.", "attack_techniques": ["T1216"] }, @@ -96,6 +105,7 @@ POST_BREACH_ACTIONS = { "AccountDiscovery" ], "title": "Account Discovery", + "safe": True, "info": "Attempts to get a listing of user accounts on the system.", "attack_techniques": ["T1087"] }, @@ -105,6 +115,7 @@ POST_BREACH_ACTIONS = { "ClearCommandHistory" ], "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 306f1efc3..cd756ed61 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 @@ -13,6 +13,7 @@ SYSTEM_INFO_COLLECTOR_CLASSES = { ENVIRONMENT_COLLECTOR ], "title": "Environment collector", + "safe": True, "info": "Collects information about machine's environment (on premise/GCP/AWS).", "attack_techniques": ["T1082"] }, @@ -22,6 +23,7 @@ SYSTEM_INFO_COLLECTOR_CLASSES = { MIMIKATZ_COLLECTOR ], "title": "Mimikatz collector", + "safe": True, "info": "Collects credentials from Windows credential manager.", "attack_techniques": ["T1003", "T1005"] }, @@ -31,8 +33,8 @@ SYSTEM_INFO_COLLECTOR_CLASSES = { AWS_COLLECTOR ], "title": "AWS collector", - "info": "If on AWS, collects more information about the AWS instance currently running on. " - "Also responsible for running ScoutSuite cloud security check.", + "safe": True, + "info": "If on AWS, collects more information about the AWS instance currently running on.", "attack_techniques": ["T1082"] }, { @@ -41,6 +43,7 @@ SYSTEM_INFO_COLLECTOR_CLASSES = { HOSTNAME_COLLECTOR ], "title": "Hostname collector", + "safe": True, "info": "Collects machine's hostname.", "attack_techniques": ["T1082", "T1016"] }, @@ -50,6 +53,7 @@ SYSTEM_INFO_COLLECTOR_CLASSES = { PROCESS_LIST_COLLECTOR ], "title": "Process list collector", + "safe": True, "info": "Collects a list of running processes on the machine.", "attack_techniques": ["T1082"] }, @@ -59,6 +63,7 @@ SYSTEM_INFO_COLLECTOR_CLASSES = { AZURE_CRED_COLLECTOR ], "title": "Azure credential collector", + "safe": True, "info": "Collects password credentials from Azure VMs", "attack_techniques": ["T1003", "T1005"] } diff --git a/monkey/monkey_island/cc/services/reporting/report.py b/monkey/monkey_island/cc/services/reporting/report.py index 99a28d029..bc192a5bc 100644 --- a/monkey/monkey_island/cc/services/reporting/report.py +++ b/monkey/monkey_island/cc/services/reporting/report.py @@ -510,6 +510,7 @@ class ReportService: 'hostname': monkey['hostname'], 'target': target_ip, 'services': scan['data']['machine']['services'], + 'icmp': scan['data']['machine']['icmp'], 'is_self': False }) @@ -544,7 +545,7 @@ class ReportService: @staticmethod def get_cross_segment_issues(): scans = mongo.db.telemetry.find({'telem_category': 'scan'}, - {'monkey_guid': 1, 'data.machine.ip_addr': 1, 'data.machine.services': 1}) + {'monkey_guid': 1, 'data.machine.ip_addr': 1, 'data.machine.services': 1, 'data.machine.icmp': 1}) cross_segment_issues = [] diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1003.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1003.js index f58f870c1..1a93c8e06 100644 --- a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1003.js +++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1003.js @@ -14,7 +14,7 @@ class T1003 extends React.Component { render() { return (
-
{this.props.data.message}
+
{this.props.data.message_html}

{this.props.data.status === ScanStatus.USED ? -
{this.props.data.message}
+
{this.props.data.message_html}

{this.props.data.status === ScanStatus.USED ? -
{this.props.data.message}
+
{this.props.data.message_html}

{this.props.data.status === ScanStatus.USED ? -
{this.props.data.message}
+
{this.props.data.message_html}

{this.props.data.status === ScanStatus.USED ? -
{this.props.data.message}
+
{this.props.data.message_html}

{this.props.data.status === ScanStatus.USED ? -
{this.props.data.message}
+
{this.props.data.message_html}

{this.props.data.services.length !== 0 ? -
{this.props.data.message}
+
{this.props.data.message_html}

{this.props.data.status === ScanStatus.USED ? -
{this.props.data.message}
+
{this.props.data.message_html}

{this.props.data.status === ScanStatus.USED ? -
{this.props.data.message}
+
{this.props.data.message_html}

{this.props.data.status === ScanStatus.USED ? -
{this.props.data.message}
+
{this.props.data.message_html}

{this.props.data.scripts.length !== 0 ? -
{this.props.data.message}
+
{this.props.data.message_html}
); diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1075.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1075.js index 330f7d129..9b2850dfa 100644 --- a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1075.js +++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1075.js @@ -33,7 +33,7 @@ class T1075 extends React.Component { render() { return (
-
{this.props.data.message}
+
{this.props.data.message_html}

{this.props.data.status === ScanStatus.USED ? -
{this.props.data.message}
+
{this.props.data.message_html}

{this.props.data.status === ScanStatus.USED ? -
{this.props.data.message}
+
{this.props.data.message_html}

{this.props.data.status === ScanStatus.USED ? -
{this.props.data.message}
+
{this.props.data.message_html}

{this.props.data.status === ScanStatus.USED ? -
{this.props.data.message}
+
{this.props.data.message_html}

{this.props.data.status === ScanStatus.USED ? -
{this.props.data.message}
+
{this.props.data.message_html}

{this.props.data.status === ScanStatus.USED ? -
{this.props.data.message}
+
{this.props.data.message_html}

{this.props.data.status !== ScanStatus.UNSCANNED ? -
{this.props.data.message}
+
{this.props.data.message_html}

{this.props.data.api_uses.length !== 0 ? -
{this.props.data.message}
+
{this.props.data.message_html}

{this.props.data.deleted_files.length !== 0 ? -
{this.props.data.message}
+
{this.props.data.message_html}

{this.props.data.status !== ScanStatus.UNSCANNED ? -
{this.props.data.message}
+
{this.props.data.message_html}

{this.props.data.dlls.length !== 0 ? -
{this.props.data.message}
+
{this.props.data.message_html}

{this.props.data.status === ScanStatus.USED ? -
{this.props.data.message}
+
{this.props.data.message_html}

{this.props.data.status === ScanStatus.USED ? -
{this.props.data.message}
+
{this.props.data.message_html}

{this.props.data.status === ScanStatus.USED ? -
{this.props.data.message}
+
{this.props.data.message_html}

{this.props.data.status === ScanStatus.USED ? -
{this.props.data.message}
+
{this.props.data.message_html}

{this.props.data.status === ScanStatus.USED ? -
{this.props.data.message}
+
{this.props.data.message_html}

{this.props.data.status === ScanStatus.USED ? -
{this.props.data.message}
+
{this.props.data.message_html}

{this.props.data.status === ScanStatus.USED ? -
{this.props.data.message}
+
{this.props.data.message_html}

{this.props.data.status === ScanStatus.USED ? -
{this.props.data.message}
+
{this.props.data.message_html}

{this.props.data.status === ScanStatus.USED ?
-
{this.props.data.message}
+
{this.props.data.message_html}
{this.props.data.bits_jobs.length > 0 ?
BITS jobs were used in these machines:
: ''}

diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1210.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1210.js index 3bb6ad8c9..1a25d2ad5 100644 --- a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1210.js +++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1210.js @@ -95,7 +95,7 @@ class T1210 extends React.Component { let scanned_services = this.props.data.scanned_services.map(T1210.formatScanned).flat(); return (
-
{this.props.data.message}
+
{this.props.data.message_html}
{scanned_services.length > 0 ? this.renderScannedServices(scanned_services) : ''} {this.props.data.exploited_services.length > 0 ? diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1216.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1216.js index e608492a1..d65ab6a42 100644 --- a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1216.js +++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1216.js @@ -27,7 +27,7 @@ class T1216 extends React.Component { render() { return (
-
{this.props.data.message}
+
{this.props.data.message_html}

{this.props.data.status === ScanStatus.USED ? -
{this.props.data.message}
+
{this.props.data.message_html}

{this.props.data.status === ScanStatus.USED ? -
{this.props.data.message}
+
{this.props.data.message_html}

{this.props.data.status === ScanStatus.USED ? val.split('.')[0]; const columns = [ {title: 'Time', prop: 'timestamp', render: renderTime}, {title: 'Monkey', prop: 'monkey'}, - {title: 'Type', prop: 'telem_catagory'}, + {title: 'Type', prop: 'telem_category'}, {title: 'Details', prop: 'data', render: renderJson, width: '40%'} ]; diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/AttackReport.js b/monkey/monkey_island/cc/ui/src/components/report-components/AttackReport.js index 6a6d0c75f..841ae9dfe 100644 --- a/monkey/monkey_island/cc/ui/src/components/report-components/AttackReport.js +++ b/monkey/monkey_island/cc/ui/src/components/report-components/AttackReport.js @@ -157,9 +157,9 @@ class AttackReport extends React.Component { } } } - // modify techniques' messages + // compiles techniques' message string from markdown to HTML for (const tech_id in techniques){ - techniques[tech_id]['message'] =
; + techniques[tech_id]['message_html'] =
; } return techniques diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/SecurityReport.js b/monkey/monkey_island/cc/ui/src/components/report-components/SecurityReport.js index 63749ced1..1d6072ece 100644 --- a/monkey/monkey_island/cc/ui/src/components/report-components/SecurityReport.js +++ b/monkey/monkey_island/cc/ui/src/components/report-components/SecurityReport.js @@ -451,25 +451,64 @@ class ReportPageComponent extends AuthComponent { } generateCrossSegmentIssue(crossSegmentIssue) { - let crossSegmentIssueOverview = 'Communication possible from ' + crossSegmentIssue['source_subnet'] + ' to ' + crossSegmentIssue['target_subnet'] - return
  • - {crossSegmentIssueOverview} - + let crossSegmentIssueOverview = 'Communication possible from ' + + `${crossSegmentIssue['source_subnet']} to ${crossSegmentIssue['target_subnet']}`; + + return ( +
  • + {crossSegmentIssueOverview} + +
      + {crossSegmentIssue['issues'].map( + issue => this.generateCrossSegmentIssueListItem(issue) + )} +
    +
    +
  • + ); + } + + generateCrossSegmentIssueListItem(issue) { + if (issue['is_self']) { + return this.generateCrossSegmentSingleHostMessage(issue); + } + + return this.generateCrossSegmentMultiHostMessage(issue); + } + + generateCrossSegmentSingleHostMessage(issue) { + return ( +
  • + {`Machine ${issue['hostname']} has both ips: ${issue['source']} and ${issue['target']}`} +
  • + ); + } + + generateCrossSegmentMultiHostMessage(issue) { + return ( +
  • + IP {issue['source']} ({issue['hostname']}) was able to communicate with + IP {issue['target']} using:
      - {crossSegmentIssue['issues'].map(x => - x['is_self'] ? -
    • - {'Machine ' + x['hostname'] + ' has both ips: ' + x['source'] + ' and ' + x['target']} -
    • - : -
    • - {'IP ' + x['source'] + ' (' + x['hostname'] + ') connected to IP ' + x['target'] - + ' using the services: ' + Object.keys(x['services']).join(', ')} -
    • - )} + {issue['icmp'] &&
    • ICMP
    • } + {this.generateCrossSegmentServiceListItems(issue)}
    - -
  • ; + + ); + } + + generateCrossSegmentServiceListItems(issue) { + let service_list_items = []; + + for (const [service, info] of Object.entries(issue['services'])) { + service_list_items.push( +
  • + {service} ({info['display_name']}) +
  • + ); + } + + return service_list_items; } generateShellshockPathListBadges(paths) { diff --git a/monkey/monkey_island/cc/ui/src/components/ui-components/AdvancedMultiSelect.js b/monkey/monkey_island/cc/ui/src/components/ui-components/AdvancedMultiSelect.js index 9c1468d8d..670b99cd7 100644 --- a/monkey/monkey_island/cc/ui/src/components/ui-components/AdvancedMultiSelect.js +++ b/monkey/monkey_island/cc/ui/src/components/ui-components/AdvancedMultiSelect.js @@ -1,121 +1,192 @@ -import React, {useState} from 'react'; +import React from 'react'; +import {Button, Card} from 'react-bootstrap'; -import {Card, Button, Form} from 'react-bootstrap'; -import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; -import {faCheckSquare} from '@fortawesome/free-solid-svg-icons'; -import {faSquare} from '@fortawesome/free-regular-svg-icons'; import {cloneDeep} from 'lodash'; -import {getComponentHeight} from './utils/HeightCalculator'; -import {resolveObjectPath} from './utils/ObjectPathResolver'; -import InfoPane from './InfoPane'; +import {getDefaultPaneParams, InfoPane, WarningType} from './InfoPane'; +import {MasterCheckbox, MasterCheckboxState} from './MasterCheckbox'; +import ChildCheckboxContainer from './ChildCheckbox'; +import {getFullDefinitionByKey} from './JsonSchemaHelpers'; - -function getSelectValuesAfterClick(valueArray, clickedValue) { - if (valueArray.includes(clickedValue)) { - return valueArray.filter((e) => { - return e !== clickedValue; - }); - } else { - valueArray.push(clickedValue); - return valueArray; - } -} - -function onMasterCheckboxClick(checkboxValue, defaultArray, onChangeFnc) { - if (checkboxValue) { - onChangeFnc([]); - } else { - onChangeFnc(defaultArray); - } -} - -// Definitions passed to components only contains value and label, -// custom fields like "info" or "links" must be pulled from registry object using this function -function getFullDefinitionsFromRegistry(refString, registry) { - return getObjectFromRegistryByRef(refString, registry).anyOf; -} - -function getObjectFromRegistryByRef(refString, registry) { - let refArray = refString.replace('#', '').split('/'); - return resolveObjectPath(refArray, registry); -} - -function getFullDefinitionByKey(refString, registry, itemKey) { - let fullArray = getFullDefinitionsFromRegistry(refString, registry); - return fullArray.filter(e => (e.enum[0] === itemKey))[0]; -} - -function setPaneInfo(refString, registry, itemKey, setPaneInfoFnc) { - let definitionObj = getFullDefinitionByKey(refString, registry, itemKey); - setPaneInfoFnc({title: definitionObj.title, content: definitionObj.info, link: definitionObj.link}); -} - -function getDefaultPaneParams(refString, registry) { - let configSection = getObjectFromRegistryByRef(refString, registry); - return ({title: configSection.title, content: configSection.description}); -} - -function AdvancedMultiSelect(props) { - const [masterCheckbox, setMasterCheckbox] = useState(true); +function AdvancedMultiSelectHeader(props) { const { - schema, - id, - options, - value, - required, - disabled, - readonly, - multiple, - autofocus, - onChange, - registry + title, + onCheckboxClick, + checkboxState, + hideReset, + onResetClick } = props; - const {enumOptions} = options; - const [infoPaneParams, setInfoPaneParams] = useState(getDefaultPaneParams(schema.items.$ref, registry)); - getDefaultPaneParams(schema.items.$ref, registry); - const selectValue = cloneDeep(value); + return ( -
    - - - {props.schema.title} - - - {enumOptions.map(({value, label}, i) => { - return ( - setPaneInfo(schema.items.$ref, registry, value, setInfoPaneParams)}> - - - {label} - - - ); - })} - - -
    + + + + ); } +class AdvancedMultiSelect extends React.Component { + constructor(props) { + super(props); + + this.defaultValues = props.schema.default; + this.infoPaneRefString = props.schema.items.$ref; + this.registry = props.registry; + this.enumOptions = props.options.enumOptions.sort(this.compareOptions); + + this.state = { + masterCheckboxState: this.getMasterCheckboxState(props.value), + hideReset: this.getHideResetState(props.value), + infoPaneParams: getDefaultPaneParams( + this.infoPaneRefString, + this.registry, + this.isUnsafeOptionSelected(this.props.value) + ) + }; + } + + // Sort options alphabetically. "Unsafe" options float to the bottom" + compareOptions = (a, b) => { + // Apparently, you can use additive operators with boolean types. Ultimately, + // the ToNumber() abstraction operation is called to convert the booleans to + // numbers: https://tc39.es/ecma262/#sec-tonumeric + if (this.isSafe(b.value) - this.isSafe(a.value) !== 0) { + return this.isSafe(b.value) - this.isSafe(a.value); + } + + return a.value.localeCompare(b.value); + } + + onMasterCheckboxClick = () => { + if (this.state.masterCheckboxState === MasterCheckboxState.ALL) { + var newValues = []; + } else { + newValues = this.enumOptions.map(({value}) => value); + } + + this.props.onChange(newValues); + this.setMasterCheckboxState(newValues); + this.setHideResetState(newValues); + this.setPaneInfoToDefault(this.isUnsafeOptionSelected(newValues)); + } + + onChildCheckboxClick = (value) => { + let selectValues = this.getSelectValuesAfterClick(value); + this.props.onChange(selectValues); + + this.setMasterCheckboxState(selectValues); + this.setHideResetState(selectValues); + } + + getSelectValuesAfterClick(clickedValue) { + const valueArray = cloneDeep(this.props.value); + + if (valueArray.includes(clickedValue)) { + return valueArray.filter(e => e !== clickedValue); + } else { + valueArray.push(clickedValue); + return valueArray; + } + } + + setMasterCheckboxState(selectValues) { + this.setState(() => ({ + masterCheckboxState: this.getMasterCheckboxState(selectValues) + })); + } + + getMasterCheckboxState(selectValues) { + if (selectValues.length === 0) { + return MasterCheckboxState.NONE; + } + + if (selectValues.length !== this.enumOptions.length) { + return MasterCheckboxState.MIXED; + } + + return MasterCheckboxState.ALL; + } + + onResetClick = () => { + this.props.onChange(this.defaultValues); + this.setHideResetState(this.defaultValues); + this.setMasterCheckboxState(this.defaultValues); + this.setPaneInfoToDefault(this.isUnsafeOptionSelected(this.defaultValues)); + } + + setHideResetState(selectValues) { + this.setState(() => ({ + hideReset: this.getHideResetState(selectValues) + })); + } + + getHideResetState(selectValues) { + return !(this.isUnsafeOptionSelected(selectValues)) + } + + isUnsafeOptionSelected(selectValues) { + return !(selectValues.every((value) => this.isSafe(value))); + } + + isSafe = (itemKey) => { + return getFullDefinitionByKey(this.infoPaneRefString, this.registry, itemKey).safe; + } + + setPaneInfo = (itemKey) => { + let definitionObj = getFullDefinitionByKey(this.infoPaneRefString, this.registry, itemKey); + this.setState( + { + infoPaneParams: { + title: definitionObj.title, + content: definitionObj.info, + link: definitionObj.link, + warningType: this.isSafe(itemKey) ? WarningType.NONE : WarningType.SINGLE + } + } + ); + } + + setPaneInfoToDefault(isUnsafeOptionSelected) { + this.setState(() => ({ + infoPaneParams: getDefaultPaneParams( + this.props.schema.items.$ref, + this.props.registry, + isUnsafeOptionSelected + ) + })); + } + + render() { + const { + schema, + id, + required, + multiple, + autofocus + } = this.props; + + return ( +
    + + + + + +
    + ); + } +} + export default AdvancedMultiSelect; diff --git a/monkey/monkey_island/cc/ui/src/components/ui-components/ChildCheckbox.js b/monkey/monkey_island/cc/ui/src/components/ui-components/ChildCheckbox.js new file mode 100644 index 000000000..055087e42 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/ui-components/ChildCheckbox.js @@ -0,0 +1,64 @@ +import React from 'react'; +import {Button, Form} from 'react-bootstrap'; + +import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; +import {faCheckSquare} from '@fortawesome/free-solid-svg-icons'; +import {faSquare} from '@fortawesome/free-regular-svg-icons'; + +import {getComponentHeight} from './utils/HeightCalculator'; +import WarningIcon from './WarningIcon'; + +function ChildCheckboxContainer(props) { + const { + enumOptions, + id, + multiple, + required, + autofocus, + onPaneClick, + onCheckboxClick, + selectedValues, + isSafe + } = props; + + return( + + { + enumOptions.map(({value, label}, i) => { + return ( + + ); + } + )} + + ); +} + +function ChildCheckbox(props) { + const { + onPaneClick, + onClick, + value, + label, + checkboxState, + safe + } = props; + + return ( + onPaneClick(value)}> + + {label} + {!safe && } + + ); +} + +export default ChildCheckboxContainer; diff --git a/monkey/monkey_island/cc/ui/src/components/ui-components/InfoPane.js b/monkey/monkey_island/cc/ui/src/components/ui-components/InfoPane.js index 5c963d87e..21e71e29f 100644 --- a/monkey/monkey_island/cc/ui/src/components/ui-components/InfoPane.js +++ b/monkey/monkey_island/cc/ui/src/components/ui-components/InfoPane.js @@ -3,6 +3,24 @@ import React from 'react'; import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; import {faQuestionCircle} from '@fortawesome/free-solid-svg-icons'; +import {getObjectFromRegistryByRef} from './JsonSchemaHelpers'; +import WarningIcon from './WarningIcon'; + +const WarningType = { + NONE: 0, + SINGLE: 1, + MULTIPLE: 2 +} + +function getDefaultPaneParams(refString, registry, isUnsafeOptionSelected) { + let configSection = getObjectFromRegistryByRef(refString, registry); + return ( + { + title: configSection.title, + content: configSection.description, + warningType: isUnsafeOptionSelected ? WarningType.Multiple : WarningType.NONE + }); +} function InfoPane(props) { return ( @@ -44,9 +62,36 @@ function getSubtitle(props) { function getBody(props) { return ( - {props.body} + {props.body} + {props.warningType !== WarningType.NONE && getWarning(props.warningType)} ) } -export default InfoPane +function getWarning(warningType) { + return ( +
    + {warningType === WarningType.SINGLE ? getSingleOptionWarning() : getMultipleOptionsWarning()} +
    + ); +} + +function getSingleOptionWarning() { + return ( + This option may cause a system to become unstable or + may change a system's state in undesirable ways. Therefore, this option + is not recommended for use in production or other sensitive + environments. + ); +} + +function getMultipleOptionsWarning() { + return ( + Some options have been selected that may cause a system + to become unstable or may change a system's state in undesirable ways. + Running Infection Monkey in a production or other sensitive environment + with this configuration is not recommended. + ); +} + +export {getDefaultPaneParams, InfoPane, WarningType} diff --git a/monkey/monkey_island/cc/ui/src/components/ui-components/JsonSchemaHelpers.js b/monkey/monkey_island/cc/ui/src/components/ui-components/JsonSchemaHelpers.js new file mode 100644 index 000000000..9a3d9c66b --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/ui-components/JsonSchemaHelpers.js @@ -0,0 +1,19 @@ +import {resolveObjectPath} from './utils/ObjectPathResolver'; + +function getFullDefinitionByKey(refString, registry, itemKey) { + let fullArray = getFullDefinitionsFromRegistry(refString, registry); + return fullArray.filter(e => (e.enum[0] === itemKey))[0]; +} + +// Definitions passed to components only contains value and label, +// custom fields like "info" or "links" must be pulled from registry object using this function +function getFullDefinitionsFromRegistry(refString, registry) { + return getObjectFromRegistryByRef(refString, registry).anyOf; +} + +function getObjectFromRegistryByRef(refString, registry) { + let refArray = refString.replace('#', '').split('/'); + return resolveObjectPath(refArray, registry); +} + +export {getFullDefinitionByKey, getObjectFromRegistryByRef}; diff --git a/monkey/monkey_island/cc/ui/src/components/ui-components/MasterCheckbox.js b/monkey/monkey_island/cc/ui/src/components/ui-components/MasterCheckbox.js new file mode 100644 index 000000000..907ccf08f --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/ui-components/MasterCheckbox.js @@ -0,0 +1,40 @@ +import React from 'react'; +import {Button} from 'react-bootstrap'; + +import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; +import {faCheckSquare} from '@fortawesome/free-solid-svg-icons'; +import {faMinusSquare} from '@fortawesome/free-solid-svg-icons'; +import {faSquare} from '@fortawesome/free-regular-svg-icons'; + +const MasterCheckboxState = { + NONE: 0, + MIXED: 1, + ALL: 2 +} + +function MasterCheckbox(props) { + const { + title, + onClick, + checkboxState + } = props; + + let newCheckboxIcon = faCheckSquare; + + if (checkboxState === MasterCheckboxState.NONE) { + newCheckboxIcon = faSquare; + } else if (checkboxState === MasterCheckboxState.MIXED) { + newCheckboxIcon = faMinusSquare; + } + + return ( +
    + + {title} +
    + ); +} + +export {MasterCheckboxState, MasterCheckbox}; diff --git a/monkey/monkey_island/cc/ui/src/components/ui-components/WarningIcon.js b/monkey/monkey_island/cc/ui/src/components/ui-components/WarningIcon.js new file mode 100644 index 000000000..e06f00ec9 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/ui-components/WarningIcon.js @@ -0,0 +1,11 @@ +import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; +import {faExclamationTriangle} from '@fortawesome/free-solid-svg-icons'; +import React from 'react'; + +function WarningIcon() { + return ( + + ); +} + +export default WarningIcon; diff --git a/monkey/monkey_island/cc/ui/src/styles/components/AdvancedMultiSelect.scss b/monkey/monkey_island/cc/ui/src/styles/components/AdvancedMultiSelect.scss index 3dc1fe9a5..cd1297f54 100644 --- a/monkey/monkey_island/cc/ui/src/styles/components/AdvancedMultiSelect.scss +++ b/monkey/monkey_island/cc/ui/src/styles/components/AdvancedMultiSelect.scss @@ -18,12 +18,14 @@ padding-bottom: 5px; } -.advanced-multi-select .card-header button { - padding-top: 0; +.advanced-multi-select .card-header .master-checkbox span { + padding-bottom: 0.188rem; } .advanced-multi-select .card-header .header-title { font-size: 1.2em; + display: inline-block; + vertical-align: middle; } .advanced-multi-select .choice-block .form-group { diff --git a/monkey/monkey_island/cc/ui/src/styles/components/InfoPane.scss b/monkey/monkey_island/cc/ui/src/styles/components/InfoPane.scss index 8c61d873f..976246cb6 100644 --- a/monkey/monkey_island/cc/ui/src/styles/components/InfoPane.scss +++ b/monkey/monkey_island/cc/ui/src/styles/components/InfoPane.scss @@ -27,3 +27,14 @@ margin: 10px 15px; padding: 0; } + +.info-pane-warning { + margin-top: 1em; + display: flex; +} + +.info-pane-warning .warning-icon { + margin-top: .188em; + margin-left: 0em; + margin-right: .75em; +} diff --git a/monkey/monkey_island/cc/ui/src/styles/pages/ConfigurationPage.scss b/monkey/monkey_island/cc/ui/src/styles/pages/ConfigurationPage.scss index e5c6c08bc..18e09d37b 100644 --- a/monkey/monkey_island/cc/ui/src/styles/pages/ConfigurationPage.scss +++ b/monkey/monkey_island/cc/ui/src/styles/pages/ConfigurationPage.scss @@ -57,3 +57,8 @@ white-space: pre-wrap; } +.warning-icon { + text-transform: uppercase; + color: #FFC107; + margin-left: .75em; +} diff --git a/monkey/monkey_island/cc/ui/src/styles/pages/report/ReportPage.scss b/monkey/monkey_island/cc/ui/src/styles/pages/report/ReportPage.scss index 5fb8252fe..088e012f3 100644 --- a/monkey/monkey_island/cc/ui/src/styles/pages/report/ReportPage.scss +++ b/monkey/monkey_island/cc/ui/src/styles/pages/report/ReportPage.scss @@ -76,3 +76,12 @@ div.report-wrapper .nav-tabs > .nav-item > a:hover:not(.active), .nav-tabs > .n text-decoration: none; background-color: $light-gray; } + +ul.cross-segment-issues { + list-style-type: none; + padding: 0px; + margin: 0px; +} +span.cross-segment-service { + text-transform: uppercase; +}