From f6d0482c2e8576df24b0fe4c431bf150c5ee2105 Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Wed, 29 Jun 2022 18:31:19 +0200 Subject: [PATCH 01/33] UI: Initialize a new json schema --- .../services/configuration/config_schema.js | 58 +++++++++++++++ .../configuration/definitions/custom_pbas.js | 42 +++++++++++ .../configuration/definitions/exploitation.js | 37 ++++++++++ .../definitions/exploitation_options.js | 14 ++++ .../configuration/definitions/icmp_scan.js | 12 ++++ .../configuration/definitions/network_scan.js | 26 +++++++ .../configuration/definitions/plugins.js | 15 ++++ .../configuration/definitions/propagation.js | 23 ++++++ .../configuration/definitions/scan_target.js | 70 +++++++++++++++++++ .../configuration/definitions/tcp_scan.js | 21 ++++++ 10 files changed, 318 insertions(+) create mode 100644 monkey/monkey_island/cc/ui/src/services/configuration/config_schema.js create mode 100644 monkey/monkey_island/cc/ui/src/services/configuration/definitions/custom_pbas.js create mode 100644 monkey/monkey_island/cc/ui/src/services/configuration/definitions/exploitation.js create mode 100644 monkey/monkey_island/cc/ui/src/services/configuration/definitions/exploitation_options.js create mode 100644 monkey/monkey_island/cc/ui/src/services/configuration/definitions/icmp_scan.js create mode 100644 monkey/monkey_island/cc/ui/src/services/configuration/definitions/network_scan.js create mode 100644 monkey/monkey_island/cc/ui/src/services/configuration/definitions/plugins.js create mode 100644 monkey/monkey_island/cc/ui/src/services/configuration/definitions/propagation.js create mode 100644 monkey/monkey_island/cc/ui/src/services/configuration/definitions/scan_target.js create mode 100644 monkey/monkey_island/cc/ui/src/services/configuration/definitions/tcp_scan.js diff --git a/monkey/monkey_island/cc/ui/src/services/configuration/config_schema.js b/monkey/monkey_island/cc/ui/src/services/configuration/config_schema.js new file mode 100644 index 000000000..dc73e9d8b --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/services/configuration/config_schema.js @@ -0,0 +1,58 @@ +import {customPBAConfigurationSchema} from './definitions/custom_pbas.js'; +import {pluginConfigurationSchema} from './definitions/plugins.js'; +import {propagationConfigurationSchema} from './definitions/propagation.js'; + +export const SCHEMA = { + 'title': 'Monkey', + 'type': 'object', + 'properties': { + 'propagation': propagationConfigurationSchema, + 'post_breach_actions': { + 'title': 'Post-breach actions', + 'type': 'object', + 'properties': { + 'pba_list': { + 'title': 'PBAs', + 'type': 'array', + 'items': pluginConfigurationSchema, + 'default': [ + {'name': 'CommunicateAsBackdoorUser','safe': true, 'options': {}}, + {'name': 'ModifyShellStartupFiles', 'safe': true, 'options': {}} + ] + }, + 'custom_pbas': customPBAConfigurationSchema + } + }, + 'payloads': { + 'title': 'Payloads', + 'type': 'array', + 'items': pluginConfigurationSchema, + 'default': [ + {'name': 'ransomware', 'safe': true, 'options': {}} + ] + }, + 'credential_collectors': { + 'title': 'Credential collectors', + 'type': 'array', + 'items': pluginConfigurationSchema, + 'default': [ + {'name': 'MimikatzCollector', 'safe': true, 'options':{}}, + {'name': 'SSHCollector', 'safe': true, 'options':{}} + ] + }, + 'advanced': { + 'title': 'Advanced', + 'type': 'object', + 'properties':{ + 'keep_tunnel_open_time': { + 'title': 'Keep tunnel open time', + 'format': 'float', + 'type': 'number', + 'default': 30, + 'description': 'Time to keep tunnel open before going down after last exploit (in seconds)' + } + } + } + }, + 'options': {'collapsed': true} +} diff --git a/monkey/monkey_island/cc/ui/src/services/configuration/definitions/custom_pbas.js b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/custom_pbas.js new file mode 100644 index 000000000..1a4aa13ea --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/custom_pbas.js @@ -0,0 +1,42 @@ +export const customPBAConfigurationSchema = { + 'title': 'Custom post-breach action', + 'type': 'object', + 'properties': { + 'linux_command': { + 'title': 'Linux post-breach command', + 'type': 'string', + 'default': '', + 'description': 'Command to be executed after breaching. ' + + 'Use this field to run custom commands or execute uploaded ' + + 'files on exploited machines.\nExample: ' + + '"chmod +x ./my_script.sh; ./my_script.sh ; rm ./my_script.sh"' + }, + 'linux_filename': { + 'title': 'Linux post-breach file', + 'type': 'string', + 'format': 'data-url', + 'description': 'File to be uploaded after braeaching. ' + + 'Use the "Linux post-breach command" field to ' + + 'change permissions, run, or delete the file. ' + + 'Reference your file by filename.' + }, + 'windows_command': { + 'title': 'Windows post-breach command', + 'type': 'string', + 'default': '', + 'description': 'Command to be executed after breaching. ' + + 'Use this field to run custom commands or execute uploaded ' + + 'file on exploited machine.\nExample: ' + + '"my_script.bat & del my_script.bat"' + }, + 'windows_filename':{ + 'title': 'Windows post-breach file', + 'type': 'string', + 'format': 'data-url', + 'description': 'File to be uploaded after breaching. ' + + 'Use the "Windows post-breach command" filed to ' + + 'change permissions, run or delete the file. ' + + 'Reference your file by filename.' + } + } +} diff --git a/monkey/monkey_island/cc/ui/src/services/configuration/definitions/exploitation.js b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/exploitation.js new file mode 100644 index 000000000..08cc926bc --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/exploitation.js @@ -0,0 +1,37 @@ +import {exploitationOptionsConfigurationSchema} from './exploitation_options.js'; +import {pluginConfigurationSchema} from './plugins.js'; + +export const exploitationConfigurationSchema = { + 'type': 'object', + 'properties': { + 'brute_force': { + 'title': 'Brute force exploiters', + 'type': 'string', + 'anyOf': [ + { + 'type': 'string', + 'enum': ['SmbExploiter'], + 'info': 'bla', + 'link': 'link' + }, + { + 'type': 'string', + 'enum': ['SmbExploiter'], + 'info': 'bla', + 'link': 'link' + } + + ] + }, + 'vulnerability': { + 'title': 'Vulnerability exploiters', + 'type': 'string', + 'items': pluginConfigurationSchema, + 'default': [ + {'name': 'Log4ShellExploiter', 'safe': true, 'options': {}}, + {'name': 'HadoopExploiter', 'safe': true, 'options': {}} + ] + }, + 'options': exploitationOptionsConfigurationSchema + } +} diff --git a/monkey/monkey_island/cc/ui/src/services/configuration/definitions/exploitation_options.js b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/exploitation_options.js new file mode 100644 index 000000000..6d6834ba1 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/exploitation_options.js @@ -0,0 +1,14 @@ +export const exploitationOptionsConfigurationSchema = { + 'type': 'object', + 'properties': { + 'http_ports': { + 'title': 'HTTP Ports', + 'type': 'array', + 'items': { + 'type': 'integer' + }, + 'default': [80, 8080, 443, 8008, 7001, 9200, 8983, 9600], + 'description': 'List of ports the monkey will check if are being used for HTTP' + } + } +} diff --git a/monkey/monkey_island/cc/ui/src/services/configuration/definitions/icmp_scan.js b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/icmp_scan.js new file mode 100644 index 000000000..25d72b21c --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/icmp_scan.js @@ -0,0 +1,12 @@ +export const icmpScanConfigurationSchema = { + 'title': 'Ping scanner', + 'type': 'object', + 'properties': { + 'timeout': { + 'format': 'float', + 'title': 'Ping scan timeout', + 'type': 'number', + 'description': 'Maximum time to wait for ping response' + } + } +} diff --git a/monkey/monkey_island/cc/ui/src/services/configuration/definitions/network_scan.js b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/network_scan.js new file mode 100644 index 000000000..8b91a3cec --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/network_scan.js @@ -0,0 +1,26 @@ +import {pluginConfigurationSchema} from './plugins.js'; +import {icmpScanConfigurationSchema} from './icmp_scan.js'; +import {scanTargetConfigurationSchema} from './scan_target.js'; +import {tcpScanConfigurationSchema} from './tcp_scan.js'; + +export const networkScanConfigurationSchema = { + 'type': 'object', + 'additionalProperties': false, + 'properties': { + 'fingerprinters': { + 'title': 'Fingerprinters', + 'type': 'array', + 'items': pluginConfigurationSchema, + 'default': [ + {'name': 'SMBFinger', 'safe': true, 'options': {}}, + {'name': 'SSHFinger', 'safe': true, 'options': {}}, + {'name': 'HTTPFinger', 'safe': true, 'options': {}}, + {'name': 'MSSQLFinger', 'safe': true, 'options': {}}, + {'name': 'ElasticFinger', 'safe': true, 'options': {}} + ] + }, + 'icmp': icmpScanConfigurationSchema, + 'targets': scanTargetConfigurationSchema, + 'tcp': tcpScanConfigurationSchema + } +} diff --git a/monkey/monkey_island/cc/ui/src/services/configuration/definitions/plugins.js b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/plugins.js new file mode 100644 index 000000000..9dc28b268 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/plugins.js @@ -0,0 +1,15 @@ +export const pluginConfigurationSchema = { + 'type': 'object', + 'properties': { + 'name': { + 'title': 'Name', + 'type': 'string' + }, + 'safe': { + 'type': 'boolean' + }, + 'options': { + 'type': 'object' + } + } +} diff --git a/monkey/monkey_island/cc/ui/src/services/configuration/definitions/propagation.js b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/propagation.js new file mode 100644 index 000000000..0d8944909 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/propagation.js @@ -0,0 +1,23 @@ +import {exploitationConfigurationSchema} from './exploitation.js'; +import {networkScanConfigurationSchema} from './network_scan.js'; + +export const propagationConfigurationSchema = { + 'title': 'Propagation', + 'type': 'object', + 'properties': { + 'exploitation': exploitationConfigurationSchema, + 'maximum_depth': { + 'title': 'Maximum scan depth', + 'type': 'integer', + 'minimum': 1, + 'default': 2, + 'description': 'Amount of hops alloed for the monkey to spread from the ' + + 'Island server. \n' + + ' \u26A0' + + ' Note that setting this value too high may result in the ' + + 'Monkey propagating too far, '+ + 'if the "Local network scan" is enabled' + }, + 'network_scan': networkScanConfigurationSchema + } +} diff --git a/monkey/monkey_island/cc/ui/src/services/configuration/definitions/scan_target.js b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/scan_target.js new file mode 100644 index 000000000..74f0896bb --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/scan_target.js @@ -0,0 +1,70 @@ +export const scanTargetConfigurationSchema = { + 'title': 'Network', + 'type': 'object', + 'properties': { + 'info_box': { + 'info': 'The Monkey scans its subnet if "Local network scan" is checked. '+ + 'Additionally, the Monkey scans machines according to "Scan target list". ' + }, + 'blocked_ips': { + 'title': 'Blocked IPs', + 'type': 'array', + 'uniqueItems': true, + 'items': { + 'type': 'string', + 'format': 'ip' + }, + 'default': [], + 'description': 'List of IPs that the monkey will not scan.' + }, + 'inaccessible_sbunets': { + 'title': 'Network segmentation testing', + 'type': 'array', + 'uniqueItems': true, + 'items': { + 'type': 'string', + 'format': 'ip-range' + }, + 'default': [], + 'description': 'Test for network segmentation by providing a list of network segments that should NOT be accessible to each other.\n\n ' + + 'For example, if you configured the following three segments: ' + + '"10.0.0.0/24", "11.0.0.2/32" and "12.2.3.0/24",' + + 'a Monkey running on 10.0.0.5 will try to access machines in ' + + 'the following subnets: ' + + '11.0.0.2/32, 12.2.3.0/24. An alert on successful cross-segment connections ' + + 'will be shown in the reports. \n\n' + + 'Network segments can be IPs, subnets or hosts. Examples:\n' + + '\tDefine a single-IP segment: "192.168.0.1"\n' + + '\tDefine a segment using a network range: ' + + '"192.168.0.5-192.168.0.20"\n' + + '\tDefine a segment using an subnet IP mask: "192.168.0.5/24"\n' + + '\tDefine a single-host segment: "printer.example"' + }, + 'local_network_scan': { + 'title': 'Local network scan', + 'type': 'boolean', + 'default': true, + 'description': 'Determines whether the Monkey will scan the local subnets of machines it runs on, ' + + 'in addition to the IPs that are configured manually in the "Scan target list"' + }, + 'subnets': { + 'title': 'Scan target list', + 'type': 'array', + 'uniqueItems': true, + 'items': { + 'type': 'string', + 'format': 'ip-range' + }, + 'default': [], + 'description': 'List of targets the Monkey will try to scan. Targets can be ' + + 'IPs, subnets or hosts. ' + + 'Examples:\n' + + '\tTarget a specific IP: "192.168.0.1"\n' + + '\tTarget a subnet using a network range: ' + + '"192.168.0.5-192.168.0.20"\n'+ + '\tTarget a subnet using an IP mask: "192.168.0.5/24"\n' + + '\tTarget a specific host: "printer.example"' + } + + } +} diff --git a/monkey/monkey_island/cc/ui/src/services/configuration/definitions/tcp_scan.js b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/tcp_scan.js new file mode 100644 index 000000000..abfdc709d --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/tcp_scan.js @@ -0,0 +1,21 @@ +export const tcpScanConfigurationSchema = { + 'title': 'TCP scanner', + 'type': 'object', + 'properties': { + 'ports': { + 'title': 'TCP target ports', + 'type': 'array', + 'items': { + 'type': 'integer' + }, + 'default': [22,2222,445,135,389,80,8080,443,8008,3306,7001,8088,5885,5986], + 'description': 'List of TCP ports the monkey will check whether they\'re open' + }, + 'timeout': { + 'title': 'TCP scan timeout', + 'format': 'float', + 'type': 'number', + 'description': 'Maximum time to wait for TCP response.' + } + } +} From 0b18d938698eb8d3b0f6796b30b14d64daf550c1 Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Wed, 29 Jun 2022 18:32:14 +0200 Subject: [PATCH 02/33] UI: Change the configuration tabs per the new schema --- .../ConfigurationTabs.js | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/monkey/monkey_island/cc/ui/src/components/configuration-components/ConfigurationTabs.js b/monkey/monkey_island/cc/ui/src/components/configuration-components/ConfigurationTabs.js index f6057dd6e..dbdb4b5c6 100644 --- a/monkey/monkey_island/cc/ui/src/components/configuration-components/ConfigurationTabs.js +++ b/monkey/monkey_island/cc/ui/src/components/configuration-components/ConfigurationTabs.js @@ -1,23 +1,23 @@ const CONFIGURATION_TABS = { - BASIC: 'basic', - BASIC_NETWORK: 'basic_network', - RANSOMWARE: 'ransomware', - MONKEY: 'monkey', - INTERNAL: 'internal' + PROPAGATION: 'propagation', + PAYLOADS: 'payloads', + PBA: 'post_breach_actions', + CREDENTIALS_COLLECTORS: 'credential_collectors', + ADVANCED: 'advanced' }; const advancedModeConfigTabs = [ - CONFIGURATION_TABS.BASIC, - CONFIGURATION_TABS.BASIC_NETWORK, - CONFIGURATION_TABS.RANSOMWARE, - CONFIGURATION_TABS.MONKEY, - CONFIGURATION_TABS.INTERNAL + CONFIGURATION_TABS.PROPAGATION, + CONFIGURATION_TABS.PAYLOADS, + CONFIGURATION_TABS.PBA, + CONFIGURATION_TABS.CREDENTIALS_COLLECTORS, + CONFIGURATION_TABS.ADVANCED ]; const ransomwareModeConfigTabs = [ - CONFIGURATION_TABS.BASIC, - CONFIGURATION_TABS.BASIC_NETWORK, - CONFIGURATION_TABS.RANSOMWARE + CONFIGURATION_TABS.PROPAGATION, + CONFIGURATION_TABS.PAYLOADS, + CONFIGURATION_TABS.ADVANCED ]; const CONFIGURATION_TABS_PER_MODE = { From 22bb423d0d86157cb39928f94a0dc9d8e929cd54 Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Wed, 29 Jun 2022 18:32:48 +0200 Subject: [PATCH 03/33] UI: Add propagation to the UI schema --- .../configuration-components/UiSchema.js | 137 ++---------------- 1 file changed, 11 insertions(+), 126 deletions(-) diff --git a/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js b/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js index 632076921..bbc55a73e 100644 --- a/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js +++ b/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js @@ -1,137 +1,22 @@ import AdvancedMultiSelect from '../ui-components/AdvancedMultiSelect'; -import PbaInput from './PbaInput'; -import {API_PBA_LINUX, API_PBA_WINDOWS} from '../pages/ConfigurePage'; import InfoBox from './InfoBox'; -import TextBox from './TextBox'; -import SensitiveTextInput from '../ui-components/SensitiveTextInput'; export default function UiSchema(props) { const UiSchema = { - basic: { - 'ui:order': ['exploiters', 'credentials'], - exploiters: { - exploiter_classes: { - classNames: 'config-template-no-header', + propagation: { + 'ui:order': ['exploitation', 'maximum_depth', 'network_scan'], + exploitation: { + brute_force: { + 'ui:widget': AdvancedMultiSelect + }, + vulnerability: { 'ui:widget': AdvancedMultiSelect } }, - credentials: { - exploit_user_list: { - items: { - classNames: 'config-template-no-header' - } - }, - exploit_password_list: { - items: { - classNames: 'config-template-no-header', - 'ui:widget': SensitiveTextInput - } - } - } - }, - basic_network: { - 'ui:order': ['scope', 'network_analysis'], - scope: { - info_box: { - 'ui:field': InfoBox - }, - blocked_ips: { - items: { - classNames: 'config-template-no-header' - } - }, - subnet_scan_list: { - format: 'ip-list', - items: { - classNames: 'config-template-no-header' - } - } - }, - network_analysis: { - inaccessible_subnets: { - items: { - classNames: 'config-template-no-header' - } - } - } - }, - monkey: { - post_breach: { - post_breach_actions: { - classNames: 'config-template-no-header', - 'ui:widget': AdvancedMultiSelect - }, - custom_PBA_linux_cmd: { - 'ui:widget': 'textarea', - 'ui:emptyValue': '' - }, - PBA_linux_file: { - 'ui:widget': PbaInput, - 'ui:options': { - filename: props.PBA_linux_filename, - apiEndpoint: API_PBA_LINUX, - setPbaFilename: props.setPbaFilenameLinux - } - }, - custom_PBA_windows_cmd: { - 'ui:widget': 'textarea', - 'ui:emptyValue': '' - }, - PBA_windows_file: { - 'ui:widget': PbaInput, - 'ui:options': { - filename: props.PBA_windows_filename, - apiEndpoint: API_PBA_WINDOWS, - setPbaFilename: props.setPbaFilenameWindows - } - }, - PBA_linux_filename: { - classNames: 'linux-pba-file-info', - 'ui:emptyValue': '' - }, - PBA_windows_filename: { - classNames: 'windows-pba-file-info', - 'ui:emptyValue': '' - } - }, - credential_collectors: { - credential_collectors: { - classNames: 'config-template-no-header', - 'ui:widget': AdvancedMultiSelect - } - } - }, - ransomware: { - encryption: { - info_box: { - 'ui:field': InfoBox - }, - directories: { - // Directory inputs are dynamically hidden - }, - text_box: { - 'ui:field': TextBox - }, - enabled: {'ui:widget': 'hidden'} - }, - other_behaviors : {'ui:widget': 'hidden'} - }, - internal: { - classes: { - finger_classes: { - classNames: 'config-template-no-header', - 'ui:widget': AdvancedMultiSelect - } - }, - exploits: { - exploit_lm_hash_list:{ - items: { - 'ui:widget': SensitiveTextInput - } - }, - exploit_ntlm_hash_list: { - items: { - 'ui:widget': SensitiveTextInput + network_scan: { + targets: { + info_box: { + 'ui:field': InfoBox } } } From afbd3789e873e7d5b0fafff03984ac3c9341bce1 Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Wed, 29 Jun 2022 18:33:38 +0200 Subject: [PATCH 04/33] UI: Use the new JSON schema in the Configure page --- .../ui/src/components/pages/ConfigurePage.js | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/monkey/monkey_island/cc/ui/src/components/pages/ConfigurePage.js b/monkey/monkey_island/cc/ui/src/components/pages/ConfigurePage.js index b59659ba8..a6c36182a 100644 --- a/monkey/monkey_island/cc/ui/src/components/pages/ConfigurePage.js +++ b/monkey/monkey_island/cc/ui/src/components/pages/ConfigurePage.js @@ -18,6 +18,7 @@ import ConfigImportModal from '../configuration-components/ImportConfigModal'; import applyUiSchemaManipulators from '../configuration-components/UISchemaManipulators.tsx'; import HtmlFieldDescription from '../configuration-components/HtmlFieldDescription.js'; import CONFIGURATION_TABS_PER_MODE from '../configuration-components/ConfigurationTabs.js'; +import {SCHEMA} from '../../services/configuration/config_schema.js'; const CONFIG_URL = '/api/configuration/island'; export const API_PBA_LINUX = '/api/file-upload/PBAlinux'; @@ -68,24 +69,25 @@ class ConfigurePageComponent extends AuthComponent { } componentDidMount = () => { - let urls = [CONFIG_URL]; + let urls = ['/api/agent-configuration']; // ??? Why fetch config here and not in `render()`? Promise.all(urls.map(url => this.authFetch(url).then(res => res.json()))) .then(data => { let sections = []; let monkeyConfig = data[0]; - this.setInitialConfig(monkeyConfig.configuration); + this.setInitialConfig(monkeyConfig); for (let sectionKey of this.getSectionsOrder()) { sections.push({ key: sectionKey, - title: monkeyConfig.schema.properties[sectionKey].title + title: SCHEMA.properties[sectionKey].title }); } + this.setState({ - schema: monkeyConfig.schema, - configuration: monkeyConfig.configuration, + schema: SCHEMA, + configuration: monkeyConfig, sections: sections, - currentFormData: monkeyConfig.configuration[this.state.selectedSection] + currentFormData: monkeyConfig[this.state.selectedSection] }) }); }; @@ -337,10 +339,6 @@ class ConfigurePageComponent extends AuthComponent { let formProperties = {}; formProperties['schema'] = displayedSchema formProperties['uiSchema'] = UiSchema({ - PBA_linux_filename: this.state.configuration.monkey.post_breach.PBA_linux_filename, - PBA_windows_filename: this.state.configuration.monkey.post_breach.PBA_windows_filename, - setPbaFilenameWindows: this.setPbaFilenameWindows, - setPbaFilenameLinux: this.setPbaFilenameLinux, selectedSection: this.state.selectedSection }) formProperties['fields'] = {DescriptionField: HtmlFieldDescription}; @@ -391,7 +389,7 @@ class ConfigurePageComponent extends AuthComponent { style={{'marginBottom': '2em'}} className={'config-nav'}> {this.state.sections.map(section => { - let classProp = section.key.startsWith('basic') ? 'tab-primary' : ''; + let classProp = section.key.startsWith('propagation') ? 'tab-primary' : ''; return ( {section.title} From c4f34939ec27ab0609da894a8fef118327896787 Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Thu, 30 Jun 2022 22:45:41 +0200 Subject: [PATCH 05/33] UI: Add exploiter classes to the json schema --- .../services/configuration/config_schema.js | 5 + .../configuration/definitions/exploitation.js | 59 +++++----- .../definitions/exploiter_classes.js | 103 ++++++++++++++++++ 3 files changed, 142 insertions(+), 25 deletions(-) create mode 100644 monkey/monkey_island/cc/ui/src/services/configuration/definitions/exploiter_classes.js diff --git a/monkey/monkey_island/cc/ui/src/services/configuration/config_schema.js b/monkey/monkey_island/cc/ui/src/services/configuration/config_schema.js index dc73e9d8b..a2292ab57 100644 --- a/monkey/monkey_island/cc/ui/src/services/configuration/config_schema.js +++ b/monkey/monkey_island/cc/ui/src/services/configuration/config_schema.js @@ -1,10 +1,15 @@ import {customPBAConfigurationSchema} from './definitions/custom_pbas.js'; import {pluginConfigurationSchema} from './definitions/plugins.js'; import {propagationConfigurationSchema} from './definitions/propagation.js'; +import {bruteForceExploiters, vulnerabilityExploiters} from './definitions/exploiter_classes.js'; export const SCHEMA = { 'title': 'Monkey', 'type': 'object', + 'definitions': { + 'brute_force_classes': bruteForceExploiters, + 'vulnerability_classes': vulnerabilityExploiters + }, 'properties': { 'propagation': propagationConfigurationSchema, 'post_breach_actions': { diff --git a/monkey/monkey_island/cc/ui/src/services/configuration/definitions/exploitation.js b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/exploitation.js index 08cc926bc..d499f6280 100644 --- a/monkey/monkey_island/cc/ui/src/services/configuration/definitions/exploitation.js +++ b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/exploitation.js @@ -1,37 +1,46 @@ import {exploitationOptionsConfigurationSchema} from './exploitation_options.js'; -import {pluginConfigurationSchema} from './plugins.js'; export const exploitationConfigurationSchema = { + 'title': 'Exploiters', 'type': 'object', + 'description': 'Choose which exploiters the Monkey will attempt.', 'properties': { 'brute_force': { - 'title': 'Brute force exploiters', - 'type': 'string', - 'anyOf': [ - { - 'type': 'string', - 'enum': ['SmbExploiter'], - 'info': 'bla', - 'link': 'link' - }, - { - 'type': 'string', - 'enum': ['SmbExploiter'], - 'info': 'bla', - 'link': 'link' + 'title': 'Brute force exploiter', + 'type': 'object', + 'properties': { + 'brute_force_classes': { + 'type': 'array', + 'uniqueItems': true, + 'items': { + '$ref': '#/definitions/brute_force_classes' + }, + 'default' : [ + 'SmbExploiter', + 'WmiExploiter', + 'SSHExploiter', + 'MSSQLExploiter' + ] } - - ] + } }, 'vulnerability': { - 'title': 'Vulnerability exploiters', - 'type': 'string', - 'items': pluginConfigurationSchema, - 'default': [ - {'name': 'Log4ShellExploiter', 'safe': true, 'options': {}}, - {'name': 'HadoopExploiter', 'safe': true, 'options': {}} - ] + 'title': 'Vulnerability Exploiters', + 'type': 'object', + 'properties': { + 'vulnerability_classes': { + 'type': 'array', + 'uniqueItems': true, + 'items': { + '$ref': '#/definitions/vulnerability_classes' + }, + 'default' : [ + 'Log4ShellExploiter', + 'HadoopExploiter' +] + } + } }, 'options': exploitationOptionsConfigurationSchema } -} +}; diff --git a/monkey/monkey_island/cc/ui/src/services/configuration/definitions/exploiter_classes.js b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/exploiter_classes.js new file mode 100644 index 000000000..27aa7a4e9 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/exploiter_classes.js @@ -0,0 +1,103 @@ +export const bruteForceExploiters = { + 'title': 'Brute force exploiters', + 'description': 'Click on exploiter to get more information about it.' + + '\u26A0' + + ' Note that using unsafe exploits may cause crashes of the exploited ' + + 'machine/service.', + 'type': 'string', + 'anyOf': [ + { + 'type': 'string', + 'enum': ['SmbExploiter'], + 'title': 'SMB Exploiter', + 'safe': true, + 'attack_techniques': ['T1110', 'T1075', 'T1035'], + 'info': 'Brute forces using credentials provided by user and' + + ' hashes gathered by mimikatz.', + 'link': 'https://www.guardicore.com/infectionmonkey/docs/reference' + + '/exploiters/smbexec/' + }, + { + 'type': 'string', + 'enum': ['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.', + 'link': 'https://www.guardicore.com/infectionmonkey/docs/reference' + + '/exploiters/wmiexec/' + }, + { + 'type': 'string', + 'enum': ['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.', + 'link': 'https://www.guardicore.com/infectionmonkey/docs/reference' + + '/exploiters/mssql/' + }, + { + 'type': 'string', + 'enum': ['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/' + } + ] +} + +export const vulnerabilityExploiters = { + 'title': 'Vulnerability exploiters', + 'description': 'Click on exploiter to get more information about it.' + + '\u26A0 Note that using unsafe exploits may cause craches of the exploited ' + + 'machine/service.', + 'type': 'string', + 'anyOf': [ + { + 'type': 'string', + 'enum': ['ZerologonExploiter'], + 'title': 'Zerologon Exploiter', + 'safe': false, + 'info': 'Exploits a privilege escalation vulnerability (CVE-2020-1472) in a Windows ' + + 'server domain controller (DC) by using the Netlogon Remote Protocol (MS-NRPC). ' + + 'This exploiter changes the password of a Windows server DC account, steals ' + + 'credentials, and then attempts to restore the original DC password. The victim DC ' + + 'will be unable to communicate with other DCs until the original ' + + 'password has been restored. If Infection Monkey fails to restore the ' + + 'password automatically, you\'ll have to do it manually. For more ' + + 'information, see the documentation.', + 'link': 'https://www.guardicore.com/infectionmonkey' + + '/docs/reference/exploiters/zerologon/' + }, + { + 'type': 'string', + 'enum': ['PowerShellExploiter'], + 'title': 'PowerShell Remoting Exploiter', + 'info': 'Exploits PowerShell remote execution setups. PowerShell Remoting uses Windows ' + + 'Remote Management (WinRM) to allow users to run PowerShell commands on remote ' + + 'computers.', + 'safe': true, + 'link': 'https://www.guardicore.com/infectionmonkey' + + '/docs/reference/exploiters/powershell' + }, + { + 'type': 'string', + 'enum': ['Log4ShellExploiter'], + 'title': 'Log4Shell Exploiter', + 'safe': true, + 'info': 'Exploits a software vulnerability (CVE-2021-44228) in Apache Log4j, a Java ' + + 'logging framework. Exploitation is attempted on the following services — ' + + 'Apache Solr, Apache Tomcat, Logstash.', + 'link': 'https://www.guardicore.com/infectionmonkey/docs/reference' + + '/exploiters/log4shell/' + } + ] +} From 6a7dce50f030d1a3dcee188bb41b1bd94b72d1eb Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Thu, 30 Jun 2022 22:46:15 +0200 Subject: [PATCH 06/33] UI: Use AdvancedMultiSelect on the exploiters --- .../components/configuration-components/UiSchema.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js b/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js index bbc55a73e..20d5ccc84 100644 --- a/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js +++ b/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js @@ -4,13 +4,18 @@ import InfoBox from './InfoBox'; export default function UiSchema(props) { const UiSchema = { propagation: { - 'ui:order': ['exploitation', 'maximum_depth', 'network_scan'], exploitation: { brute_force: { - 'ui:widget': AdvancedMultiSelect + brute_force_classes: { + classNames: 'config-template-no-header', + 'ui:widget': AdvancedMultiSelect + } }, vulnerability: { - 'ui:widget': AdvancedMultiSelect + vulnerability_classes: { + classNames: 'config-template-no-header', + 'ui:widget': AdvancedMultiSelect + } } }, network_scan: { From 3339a2a9577f4ee72c04235fa491978492304aea Mon Sep 17 00:00:00 2001 From: vakarisz Date: Fri, 1 Jul 2022 13:24:57 +0300 Subject: [PATCH 07/33] UI: Change advanced multi select to work with plugins --- .../configuration-components/UiSchema.js | 6 +- .../ui-components/AdvancedMultiSelect.js | 49 ++++++++++--- .../configuration/definitions/exploitation.js | 68 +++++++++---------- .../definitions/exploiter_classes.js | 33 +++++---- 4 files changed, 92 insertions(+), 64 deletions(-) diff --git a/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js b/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js index 20d5ccc84..86e5103f1 100644 --- a/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js +++ b/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js @@ -6,15 +6,17 @@ export default function UiSchema(props) { propagation: { exploitation: { brute_force: { + classNames: 'config-template-no-header', + 'ui:widget': AdvancedMultiSelect, brute_force_classes: { classNames: 'config-template-no-header', - 'ui:widget': AdvancedMultiSelect } }, vulnerability: { + classNames: 'config-template-no-header', vulnerability_classes: { classNames: 'config-template-no-header', - 'ui:widget': AdvancedMultiSelect + //'ui:widget': AdvancedMultiSelect } } }, 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 193cb40b0..f45a1c750 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 @@ -6,7 +6,7 @@ import {cloneDeep} from 'lodash'; import {getDefaultPaneParams, InfoPane, WarningType} from './InfoPane'; import {MasterCheckbox, MasterCheckboxState} from './MasterCheckbox'; import ChildCheckboxContainer from './ChildCheckbox'; -import {getFullDefinitionByKey} from './JsonSchemaHelpers'; +import {getFullDefinitionByKey, getObjectFromRegistryByRef} from './JsonSchemaHelpers'; function AdvancedMultiSelectHeader(props) { const { @@ -17,6 +17,7 @@ function AdvancedMultiSelectHeader(props) { onResetClick } = props; + return ( @@ -31,23 +32,50 @@ function AdvancedMultiSelectHeader(props) { 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.value = JSON.parse(JSON.stringify(props.value)).map(v => v.name); this.state = { - masterCheckboxState: this.getMasterCheckboxState(props.value), - hideReset: this.getHideResetState(props.value), + masterCheckboxState: this.getMasterCheckboxState(this.value), + hideReset: this.getHideResetState(this.value), infoPaneParams: getDefaultPaneParams( this.infoPaneRefString, this.registry, - this.isUnsafeOptionSelected(props.value) - ) + this.isUnsafeOptionSelected(this.value) + ), + pluginDefinitions: getObjectFromRegistryByRef(this.infoPaneRefString, this.registry).pluginDefs, + value: JSON.parse(JSON.stringify(props.value)).map(v => v.name) }; } + onChange = (strValues) => { + console.log("Values"); + console.log(this.props); + console.log(this.state); + console.log(strValues); + let newValues = []; + for (let j = 0; j < strValues.length; j++){ + let found = false; + for (let i = 0; i < this.props.value.length; i++){ + if(strValues[j] === this.props.value[i]['name']){ + newValues.push(JSON.parse(JSON.stringify(this.props.value[i]))) + found = true; + break; + } + } + if(! found){ + newValues.push(this.state.pluginDefinitions[strValues[j]]); + } + } + newValues = JSON.parse(JSON.stringify(newValues)); + console.log(newValues); + this.props.onChange(newValues) + this.setState({value: newValues.map(v => v.name)}); + } + // Sort options alphabetically. "Unsafe" options float to the top so that they // do not get selected and hidden at the bottom of the list. compareOptions = (a, b) => { @@ -76,14 +104,14 @@ class AdvancedMultiSelect extends React.Component { onChildCheckboxClick = (value) => { let selectValues = this.getSelectValuesAfterClick(value); - this.props.onChange(selectValues); + this.onChange(selectValues); this.setMasterCheckboxState(selectValues); this.setHideResetState(selectValues); } getSelectValuesAfterClick(clickedValue) { - const valueArray = cloneDeep(this.props.value); + const valueArray = cloneDeep(this.state.value); if (valueArray.includes(clickedValue)) { return valueArray.filter(e => e !== clickedValue); @@ -169,7 +197,6 @@ class AdvancedMultiSelect extends React.Component { multiple, required, schema, - value } = this.props; return ( @@ -182,7 +209,7 @@ class AdvancedMultiSelect extends React.Component { + selectedValues={this.state.value} enumOptions={this.enumOptions}/> Date: Fri, 1 Jul 2022 11:42:46 +0200 Subject: [PATCH 08/33] UI: Add credential collectors to the json schema --- .../configuration-components/UiSchema.js | 15 ++++++++--- .../ui-components/AdvancedMultiSelect.js | 4 +-- .../services/configuration/config_schema.js | 24 ++++++++++++------ .../definitions/credential_collectors.js | 25 +++++++++++++++++++ 4 files changed, 56 insertions(+), 12 deletions(-) create mode 100644 monkey/monkey_island/cc/ui/src/services/configuration/definitions/credential_collectors.js diff --git a/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js b/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js index 86e5103f1..a4034e35e 100644 --- a/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js +++ b/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js @@ -9,14 +9,14 @@ export default function UiSchema(props) { classNames: 'config-template-no-header', 'ui:widget': AdvancedMultiSelect, brute_force_classes: { - classNames: 'config-template-no-header', + classNames: 'config-template-no-header' } }, vulnerability: { classNames: 'config-template-no-header', + 'ui:widget': AdvancedMultiSelect, vulnerability_classes: { - classNames: 'config-template-no-header', - //'ui:widget': AdvancedMultiSelect + classNames: 'config-template-no-header' } } }, @@ -27,6 +27,15 @@ export default function UiSchema(props) { } } } + }, + credential_collectors: { + collectors: { + classNames: 'config-template-no-header', + 'ui:widget': AdvancedMultiSelect, + credential_collectors_classes :{ + classNames: 'config-template-no-header' + } + } } }; return UiSchema[props.selectedSection] 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 f45a1c750..bcafbc035 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 @@ -52,7 +52,7 @@ class AdvancedMultiSelect extends React.Component { } onChange = (strValues) => { - console.log("Values"); + console.log('Values'); console.log(this.props); console.log(this.state); console.log(strValues); @@ -196,7 +196,7 @@ class AdvancedMultiSelect extends React.Component { id, multiple, required, - schema, + schema } = this.props; return ( diff --git a/monkey/monkey_island/cc/ui/src/services/configuration/config_schema.js b/monkey/monkey_island/cc/ui/src/services/configuration/config_schema.js index a2292ab57..eaa4b395b 100644 --- a/monkey/monkey_island/cc/ui/src/services/configuration/config_schema.js +++ b/monkey/monkey_island/cc/ui/src/services/configuration/config_schema.js @@ -2,13 +2,15 @@ import {customPBAConfigurationSchema} from './definitions/custom_pbas.js'; import {pluginConfigurationSchema} from './definitions/plugins.js'; import {propagationConfigurationSchema} from './definitions/propagation.js'; import {bruteForceExploiters, vulnerabilityExploiters} from './definitions/exploiter_classes.js'; +import {credentialCollectors} from './definitions/credential_collectors.js'; export const SCHEMA = { 'title': 'Monkey', 'type': 'object', 'definitions': { 'brute_force_classes': bruteForceExploiters, - 'vulnerability_classes': vulnerabilityExploiters + 'vulnerability_classes': vulnerabilityExploiters, + 'credential_collectors_classes': credentialCollectors }, 'properties': { 'propagation': propagationConfigurationSchema, @@ -38,12 +40,20 @@ export const SCHEMA = { }, 'credential_collectors': { 'title': 'Credential collectors', - 'type': 'array', - 'items': pluginConfigurationSchema, - 'default': [ - {'name': 'MimikatzCollector', 'safe': true, 'options':{}}, - {'name': 'SSHCollector', 'safe': true, 'options':{}} - ] + 'properties': { + 'collectors': { + 'title': 'Credential collectors', + 'type': 'array', + 'uniqueItems': true, + 'items': { + '$ref': '#/definitions/credential_collectors_classes' + }, + 'default': [ + 'MimikatzCollector', + 'SSHCollector' + ] + } + } }, 'advanced': { 'title': 'Advanced', diff --git a/monkey/monkey_island/cc/ui/src/services/configuration/definitions/credential_collectors.js b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/credential_collectors.js new file mode 100644 index 000000000..5f73c33ac --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/credential_collectors.js @@ -0,0 +1,25 @@ +export const credentialCollectors = { + 'title': 'Credential Collectors', + 'description': 'Click on a credential collector to find out what it collects.', + 'type': 'string', + 'pluginDefs': { + 'MimikatzCollector':{'name': 'MimikatzCollector', 'options': {}}, + 'SSHCollector':{'name': 'SSHCollector', 'options': {}} + }, + 'anyOf': [ + { + 'type': 'string', + 'enum': ['MimikatzCollector'], + 'title': 'Mimikatz Credentials Collector', + 'safe': true, + 'info': 'Collects credentials from Windows credential manager.' + }, + { + 'type': 'string', + 'enum': ['SSHCollector'], + 'title': 'SSH Credentials Collector', + 'safe': true, + 'info': 'Searches users\' home directories and collects SSH keypairs.' + } + ] +} From 67aa7d95a3db42372e13d42aa81f27a1a08158a0 Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Fri, 1 Jul 2022 13:44:48 +0200 Subject: [PATCH 09/33] UI: Add vulnerability exploiters to the schema --- .../configuration/definitions/exploitation.js | 36 ++++++++----------- .../definitions/exploiter_classes.js | 10 ++++++ 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/monkey/monkey_island/cc/ui/src/services/configuration/definitions/exploitation.js b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/exploitation.js index 4b765079d..2f888ef7f 100644 --- a/monkey/monkey_island/cc/ui/src/services/configuration/definitions/exploitation.js +++ b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/exploitation.js @@ -18,25 +18,19 @@ export const exploitationConfigurationSchema = { 'SSHExploiter', 'MSSQLExploiter' ] - } - }, - 'vulnerability': { - 'title': 'Vulnerability Exploiters', - 'type': 'object', - 'properties': { - 'vulnerability_classes': { - 'title': 'Vulnerability Exploiters', - 'type': 'array', - 'uniqueItems': true, - 'items': { - '$ref': '#/definitions/vulnerability_classes' - }, - 'default': [ - 'Log4ShellExploiter', - 'HadoopExploiter' - ] - } - } - }, - 'options': exploitationOptionsConfigurationSchema + }, + 'vulnerability': { + 'title': 'Vulnerability Exploiters', + 'type': 'array', + 'uniqueItems': true, + 'items': { + '$ref': '#/definitions/vulnerability_classes' + }, + 'default': [ + 'Log4ShellExploiter', + 'HadoopExploiter' + ] + }, + 'options': exploitationOptionsConfigurationSchema + } }; diff --git a/monkey/monkey_island/cc/ui/src/services/configuration/definitions/exploiter_classes.js b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/exploiter_classes.js index 328d356f9..12be7c791 100644 --- a/monkey/monkey_island/cc/ui/src/services/configuration/definitions/exploiter_classes.js +++ b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/exploiter_classes.js @@ -101,6 +101,16 @@ export const vulnerabilityExploiters = { 'Apache Solr, Apache Tomcat, Logstash.', 'link': 'https://www.guardicore.com/infectionmonkey/docs/reference' + '/exploiters/log4shell/' + }, + { + 'type': 'string', + 'enum': ['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/' } ] } From 5a367181f9a388c87a596186f9faf7ee6261f8a9 Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Fri, 1 Jul 2022 14:36:58 +0200 Subject: [PATCH 10/33] UI: Add custom PBAs and PBAs to the json schema Remove data-url from the custom-pbas Fix small things the the credential collectors --- .../services/configuration/config_schema.js | 44 +++---- .../configuration/definitions/custom_pbas.js | 5 +- .../configuration/definitions/exploitation.js | 14 +-- .../definitions/post_breach_actions.js | 111 ++++++++++++++++++ 4 files changed, 131 insertions(+), 43 deletions(-) create mode 100644 monkey/monkey_island/cc/ui/src/services/configuration/definitions/post_breach_actions.js diff --git a/monkey/monkey_island/cc/ui/src/services/configuration/config_schema.js b/monkey/monkey_island/cc/ui/src/services/configuration/config_schema.js index eaa4b395b..db3a4de1b 100644 --- a/monkey/monkey_island/cc/ui/src/services/configuration/config_schema.js +++ b/monkey/monkey_island/cc/ui/src/services/configuration/config_schema.js @@ -3,6 +3,7 @@ import {pluginConfigurationSchema} from './definitions/plugins.js'; import {propagationConfigurationSchema} from './definitions/propagation.js'; import {bruteForceExploiters, vulnerabilityExploiters} from './definitions/exploiter_classes.js'; import {credentialCollectors} from './definitions/credential_collectors.js'; +import {postBreachActions} from './definitions/post_breach_actions.js'; export const SCHEMA = { 'title': 'Monkey', @@ -10,26 +11,20 @@ export const SCHEMA = { 'definitions': { 'brute_force_classes': bruteForceExploiters, 'vulnerability_classes': vulnerabilityExploiters, - 'credential_collectors_classes': credentialCollectors + 'credential_collectors_classes': credentialCollectors, + 'post_breach_actions': postBreachActions }, 'properties': { 'propagation': propagationConfigurationSchema, 'post_breach_actions': { 'title': 'Post-breach actions', - 'type': 'object', - 'properties': { - 'pba_list': { - 'title': 'PBAs', - 'type': 'array', - 'items': pluginConfigurationSchema, - 'default': [ - {'name': 'CommunicateAsBackdoorUser','safe': true, 'options': {}}, - {'name': 'ModifyShellStartupFiles', 'safe': true, 'options': {}} - ] - }, - 'custom_pbas': customPBAConfigurationSchema + 'type': 'array', + 'uniqueItems': true, + 'items': { + '$ref': '#/definitions/post_breach_actions' } }, + 'custom_pbas': customPBAConfigurationSchema, 'payloads': { 'title': 'Payloads', 'type': 'array', @@ -40,20 +35,15 @@ export const SCHEMA = { }, 'credential_collectors': { 'title': 'Credential collectors', - 'properties': { - 'collectors': { - 'title': 'Credential collectors', - 'type': 'array', - 'uniqueItems': true, - 'items': { - '$ref': '#/definitions/credential_collectors_classes' - }, - 'default': [ - 'MimikatzCollector', - 'SSHCollector' - ] - } - } + 'type': 'array', + 'uniqueItems': true, + 'items': { + '$ref': '#/definitions/credential_collectors_classes' + }, + 'default': [ + 'MimikatzCollector', + 'SSHCollector' + ] }, 'advanced': { 'title': 'Advanced', diff --git a/monkey/monkey_island/cc/ui/src/services/configuration/definitions/custom_pbas.js b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/custom_pbas.js index 1a4aa13ea..322aaf083 100644 --- a/monkey/monkey_island/cc/ui/src/services/configuration/definitions/custom_pbas.js +++ b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/custom_pbas.js @@ -1,6 +1,5 @@ export const customPBAConfigurationSchema = { - 'title': 'Custom post-breach action', - 'type': 'object', + 'title': 'Custom PBA', 'properties': { 'linux_command': { 'title': 'Linux post-breach command', @@ -14,7 +13,6 @@ export const customPBAConfigurationSchema = { 'linux_filename': { 'title': 'Linux post-breach file', 'type': 'string', - 'format': 'data-url', 'description': 'File to be uploaded after braeaching. ' + 'Use the "Linux post-breach command" field to ' + 'change permissions, run, or delete the file. ' + @@ -32,7 +30,6 @@ export const customPBAConfigurationSchema = { 'windows_filename':{ 'title': 'Windows post-breach file', 'type': 'string', - 'format': 'data-url', 'description': 'File to be uploaded after breaching. ' + 'Use the "Windows post-breach command" filed to ' + 'change permissions, run or delete the file. ' + diff --git a/monkey/monkey_island/cc/ui/src/services/configuration/definitions/exploitation.js b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/exploitation.js index 2f888ef7f..fdbd04401 100644 --- a/monkey/monkey_island/cc/ui/src/services/configuration/definitions/exploitation.js +++ b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/exploitation.js @@ -11,13 +11,7 @@ export const exploitationConfigurationSchema = { 'uniqueItems': true, 'items': { '$ref': '#/definitions/brute_force_classes' - }, - 'default': [ - 'SmbExploiter', - 'WmiExploiter', - 'SSHExploiter', - 'MSSQLExploiter' - ] + } }, 'vulnerability': { 'title': 'Vulnerability Exploiters', @@ -25,11 +19,7 @@ export const exploitationConfigurationSchema = { 'uniqueItems': true, 'items': { '$ref': '#/definitions/vulnerability_classes' - }, - 'default': [ - 'Log4ShellExploiter', - 'HadoopExploiter' - ] + } }, 'options': exploitationOptionsConfigurationSchema } diff --git a/monkey/monkey_island/cc/ui/src/services/configuration/definitions/post_breach_actions.js b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/post_breach_actions.js new file mode 100644 index 000000000..e0606b8d1 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/post_breach_actions.js @@ -0,0 +1,111 @@ +export const postBreachActions = { + '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.', + 'type': 'string', + 'pluginDefs': { + 'CommunicateAsBackdoorUser':{'name': 'CommunicateAsBackdoorUser', 'options':{}}, + 'ModifyShellStartupFiles':{'name': 'ModifyShellStartupFiles', 'options':{}}, + 'HiddenFiles':{'name': 'HiddenFiles', 'options':{}}, + 'TrapCommand':{'name': 'TrapCommand', 'options':{}}, + 'ChangeSetuidSetgid':{'name': 'ChangeSetuidSetgid', 'options':{}}, + 'ScheduleJobs':{'name': 'ScheduleJobs', 'options':{}}, + 'Timestomping':{'name': 'Timestomping', 'options':{}}, + 'SignedScriptProxyExecution':{'name': 'SignedScriptProxyExecution', 'options':{}}, + 'AccountDiscovery':{'name': 'AccountDiscovery', 'options':{}}, + 'ClearCommandHistory':{'name': 'ClearCommandHistory', 'options':{}}, + 'ProcessListCollection':{'name': 'ProcessListCollection', 'options':{}} + }, + 'anyOf': [ + { + 'type': 'string', + 'enum': ['CommunicateAsBackdoorUser'], + 'title': 'Communicate as Backdoor User', + 'safe': true, + 'info': 'Attempts to create a new user, create HTTPS requests as that ' + + 'user and delete the user ' + + 'afterwards.' + }, + { + 'type': 'string', + 'enum': ['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.' + }, + { + 'type': 'string', + 'enum': ['HiddenFiles'], + 'title': 'Hidden Files and Directories', + 'safe': true, + 'info': 'Attempts to create a hidden file and remove it afterward.' + }, + { + 'type': 'string', + 'enum': ['TrapCommand'], + '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.' + }, + { + 'type': 'string', + 'enum': ['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'] + }, + { + 'type': 'string', + 'enum': ['ScheduleJobs'], + 'title': 'Job Scheduling', + 'safe': true, + 'info': 'Attempts to create a scheduled job on the system and remove it.' + }, + { + 'type': 'string', + 'enum': ['Timestomping'], + 'title': 'Timestomping', + 'safe': true, + 'info': 'Creates a temporary file and attempts to modify its time ' + + 'attributes. Removes the file afterwards.' + }, + { + 'type': 'string', + 'enum': ['SignedScriptProxyExecution'], + '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.' + }, + { + 'type': 'string', + 'enum': ['AccountDiscovery'], + 'title': 'Account Discovery', + 'safe': true, + 'info': 'Attempts to get a listing of user accounts on the system.' + }, + { + 'type': 'string', + 'enum': ['ClearCommandHistory'], + 'title': 'Clear Command History', + 'safe': false, + 'info': 'Attempts to clear the command history.' + }, + { + 'type': 'string', + 'enum': ['ProcessListCollection'], + 'title': 'Process List Collector', + 'safe': true, + 'info': 'Collects a list of running processes on the machine.' + } + ] + + +} From b0ca99d1f49b8fe68afa588cbadc1f6d0a413aeb Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Fri, 1 Jul 2022 14:38:16 +0200 Subject: [PATCH 11/33] UI: Add another tab for custom PBAs --- .../components/configuration-components/ConfigurationTabs.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/monkey/monkey_island/cc/ui/src/components/configuration-components/ConfigurationTabs.js b/monkey/monkey_island/cc/ui/src/components/configuration-components/ConfigurationTabs.js index dbdb4b5c6..6df2f088b 100644 --- a/monkey/monkey_island/cc/ui/src/components/configuration-components/ConfigurationTabs.js +++ b/monkey/monkey_island/cc/ui/src/components/configuration-components/ConfigurationTabs.js @@ -2,6 +2,7 @@ const CONFIGURATION_TABS = { PROPAGATION: 'propagation', PAYLOADS: 'payloads', PBA: 'post_breach_actions', + CUSTOM_PBA: 'custom_pbas', CREDENTIALS_COLLECTORS: 'credential_collectors', ADVANCED: 'advanced' }; @@ -10,6 +11,7 @@ const advancedModeConfigTabs = [ CONFIGURATION_TABS.PROPAGATION, CONFIGURATION_TABS.PAYLOADS, CONFIGURATION_TABS.PBA, + CONFIGURATION_TABS.CUSTOM_PBA, CONFIGURATION_TABS.CREDENTIALS_COLLECTORS, CONFIGURATION_TABS.ADVANCED ]; From e28cb3036655dc3c944a210264aa08f98e55e6dc Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Fri, 1 Jul 2022 14:38:55 +0200 Subject: [PATCH 12/33] UI: Add custom pbas and pbas to the UiSchema --- .../configuration-components/UiSchema.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js b/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js index a4034e35e..2f37ae84e 100644 --- a/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js +++ b/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js @@ -28,15 +28,23 @@ export default function UiSchema(props) { } } }, - credential_collectors: { - collectors: { + custom_pbas : { + classNames: 'config-template-no-header' + }, + post_breach_actions: { classNames: 'config-template-no-header', 'ui:widget': AdvancedMultiSelect, + post_breach_actions: { + classNames: 'config-template-no-header' + } + }, + credential_collectors: { + classNames: 'config-template-no-header', + 'ui:widget': AdvancedMultiSelect, credential_collectors_classes :{ classNames: 'config-template-no-header' } } - } }; return UiSchema[props.selectedSection] } From 79afb9bc07ef0c96d904d46fa1e074eb39db7722 Mon Sep 17 00:00:00 2001 From: vakarisz Date: Fri, 1 Jul 2022 16:57:05 +0300 Subject: [PATCH 13/33] UI: Fix master checkbox in AdvancedMultiSelect.js --- .../ui-components/AdvancedMultiSelect.js | 80 ++++++++----------- 1 file changed, 34 insertions(+), 46 deletions(-) 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 bcafbc035..a00f7c9d9 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 @@ -22,8 +22,8 @@ function AdvancedMultiSelectHeader(props) { ); @@ -32,48 +32,42 @@ function AdvancedMultiSelectHeader(props) { 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.value = JSON.parse(JSON.stringify(props.value)).map(v => v.name); + this.pluginNames = props.value.map(v => v.name); this.state = { - masterCheckboxState: this.getMasterCheckboxState(this.value), - hideReset: this.getHideResetState(this.value), + masterCheckboxState: this.getMasterCheckboxState(this.pluginNames), infoPaneParams: getDefaultPaneParams( this.infoPaneRefString, this.registry, - this.isUnsafeOptionSelected(this.value) + this.isUnsafeOptionSelected(this.pluginNames) ), - pluginDefinitions: getObjectFromRegistryByRef(this.infoPaneRefString, this.registry).pluginDefs, - value: JSON.parse(JSON.stringify(props.value)).map(v => v.name) + pluginDefinitions: getObjectFromRegistryByRef(this.infoPaneRefString, + this.registry).pluginDefs, + pluginNames: props.value.map(v => v.name) }; } onChange = (strValues) => { - console.log('Values'); - console.log(this.props); - console.log(this.state); - console.log(strValues); let newValues = []; - for (let j = 0; j < strValues.length; j++){ + for (let j = 0; j < strValues.length; j++) { let found = false; - for (let i = 0; i < this.props.value.length; i++){ - if(strValues[j] === this.props.value[i]['name']){ + for (let i = 0; i < this.props.value.length; i++) { + if (strValues[j] === this.props.value[i]['name']) { newValues.push(JSON.parse(JSON.stringify(this.props.value[i]))) found = true; break; } } - if(! found){ + if (!found) { newValues.push(this.state.pluginDefinitions[strValues[j]]); } } newValues = JSON.parse(JSON.stringify(newValues)); - console.log(newValues); this.props.onChange(newValues) - this.setState({value: newValues.map(v => v.name)}); + this.setState({pluginNames: newValues.map(v => v.name)}); } // Sort options alphabetically. "Unsafe" options float to the top so that they @@ -90,28 +84,25 @@ class AdvancedMultiSelect extends React.Component { } onMasterCheckboxClick = () => { - if (this.state.masterCheckboxState === MasterCheckboxState.ALL) { + let checkboxState = this.getMasterCheckboxState(this.state.pluginNames); + if (checkboxState === 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)); + this.onChange(newValues); } onChildCheckboxClick = (value) => { let selectValues = this.getSelectValuesAfterClick(value); this.onChange(selectValues); - this.setMasterCheckboxState(selectValues); this.setHideResetState(selectValues); } getSelectValuesAfterClick(clickedValue) { - const valueArray = cloneDeep(this.state.value); + const valueArray = cloneDeep(this.state.pluginNames); if (valueArray.includes(clickedValue)) { return valueArray.filter(e => e !== clickedValue); @@ -123,8 +114,7 @@ class AdvancedMultiSelect extends React.Component { setMasterCheckboxState(selectValues) { let newState = this.getMasterCheckboxState(selectValues); - - if (newState != this.state.masterCheckboxState) { + if (newState !== this.state.masterCheckboxState) { this.setState({masterCheckboxState: newState}); } } @@ -142,10 +132,9 @@ class AdvancedMultiSelect extends React.Component { } onResetClick = () => { - this.props.onChange(this.defaultValues); + this.onChange(this.defaultValues); this.setHideResetState(this.defaultValues); - this.setMasterCheckboxState(this.defaultValues); - this.setPaneInfoToDefault(this.isUnsafeOptionSelected(this.defaultValues)); + this.setPaneInfoToSafe(this.isUnsafeOptionSelected(this.defaultValues)); } setHideResetState(selectValues) { @@ -166,7 +155,7 @@ class AdvancedMultiSelect extends React.Component { return getFullDefinitionByKey(this.infoPaneRefString, this.registry, itemKey).safe; } - setPaneInfo = (itemKey) => { + setPaneInfo = (itemKey) => { let definitionObj = getFullDefinitionByKey(this.infoPaneRefString, this.registry, itemKey); this.setState( { @@ -180,7 +169,7 @@ class AdvancedMultiSelect extends React.Component { ); } - setPaneInfoToDefault(isUnsafeOptionSelected) { + setPaneInfoToSafe(isUnsafeOptionSelected) { this.setState(() => ({ infoPaneParams: getDefaultPaneParams( this.props.schema.items.$ref, @@ -202,26 +191,25 @@ class AdvancedMultiSelect extends React.Component { return (
+ onCheckboxClick={this.onMasterCheckboxClick} + checkboxState={this.getMasterCheckboxState(this.state.pluginNames)} + hideReset={this.getHideResetState(this.pluginNames)} + onResetClick={this.onResetClick}/> + autoFocus={autofocus} isSafe={this.isSafe} + onPaneClick={this.setPaneInfo} + onCheckboxClick={this.onChildCheckboxClick} + selectedValues={this.state.pluginNames} + enumOptions={this.enumOptions}/> + body={this.state.infoPaneParams.content} + link={this.state.infoPaneParams.link} + warningType={this.state.infoPaneParams.warningType}/>
); } - - componentDidUpdate(_prevProps) { - this.setMasterCheckboxState(this.value); - } } export default AdvancedMultiSelect; From cb1360f5af54180aae604ca3e4d8a2cc9ec40949 Mon Sep 17 00:00:00 2001 From: vakarisz Date: Fri, 1 Jul 2022 17:26:11 +0300 Subject: [PATCH 14/33] UI: AdvancedMultiSelect.js make option list depend on props --- .../components/ui-components/AdvancedMultiSelect.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) 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 a00f7c9d9..3588c0303 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 @@ -34,7 +34,6 @@ class AdvancedMultiSelect extends React.Component { super(props); this.infoPaneRefString = props.schema.items.$ref; this.registry = props.registry; - this.enumOptions = props.options.enumOptions.sort(this.compareOptions); this.pluginNames = props.value.map(v => v.name); this.state = { @@ -50,6 +49,10 @@ class AdvancedMultiSelect extends React.Component { }; } + getOptionList = () => { + return this.props.options.enumOptions.sort(this.compareOptions); + } + onChange = (strValues) => { let newValues = []; for (let j = 0; j < strValues.length; j++) { @@ -88,7 +91,7 @@ class AdvancedMultiSelect extends React.Component { if (checkboxState === MasterCheckboxState.ALL) { var newValues = []; } else { - newValues = this.enumOptions.map(({value}) => value); + newValues = this.getOptionList().map(({value}) => value); } this.onChange(newValues); @@ -124,7 +127,7 @@ class AdvancedMultiSelect extends React.Component { return MasterCheckboxState.NONE; } - if (selectValues.length !== this.enumOptions.length) { + if (selectValues.length !== this.getOptionList().length) { return MasterCheckboxState.MIXED; } @@ -152,6 +155,7 @@ class AdvancedMultiSelect extends React.Component { } isSafe = (itemKey) => { + console.log(getFullDefinitionByKey(this.infoPaneRefString, this.registry, itemKey)) return getFullDefinitionByKey(this.infoPaneRefString, this.registry, itemKey).safe; } @@ -201,7 +205,7 @@ class AdvancedMultiSelect extends React.Component { onPaneClick={this.setPaneInfo} onCheckboxClick={this.onChildCheckboxClick} selectedValues={this.state.pluginNames} - enumOptions={this.enumOptions}/> + enumOptions={this.getOptionList()}/> Date: Fri, 1 Jul 2022 16:47:04 +0200 Subject: [PATCH 15/33] UI: Add fingerprinters to the schema --- .../configuration-components/UiSchema.js | 8 +++ .../services/configuration/config_schema.js | 4 +- .../definitions/exploitation_options.js | 1 + .../definitions/fingerprinter_classes.js | 52 +++++++++++++++++++ .../configuration/definitions/network_scan.js | 15 ++---- 5 files changed, 69 insertions(+), 11 deletions(-) create mode 100644 monkey/monkey_island/cc/ui/src/services/configuration/definitions/fingerprinter_classes.js diff --git a/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js b/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js index 2f37ae84e..e1134e63c 100644 --- a/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js +++ b/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js @@ -25,6 +25,14 @@ export default function UiSchema(props) { info_box: { 'ui:field': InfoBox } + }, + fingerprinters:{ + classNames: 'config-template-no-header', + 'ui:widget': AdvancedMultiSelect, + fingerprinter_classes: { + classNames: 'config-template-no-header' + } + } } }, diff --git a/monkey/monkey_island/cc/ui/src/services/configuration/config_schema.js b/monkey/monkey_island/cc/ui/src/services/configuration/config_schema.js index db3a4de1b..a0ad4818b 100644 --- a/monkey/monkey_island/cc/ui/src/services/configuration/config_schema.js +++ b/monkey/monkey_island/cc/ui/src/services/configuration/config_schema.js @@ -4,6 +4,7 @@ import {propagationConfigurationSchema} from './definitions/propagation.js'; import {bruteForceExploiters, vulnerabilityExploiters} from './definitions/exploiter_classes.js'; import {credentialCollectors} from './definitions/credential_collectors.js'; import {postBreachActions} from './definitions/post_breach_actions.js'; +import {fingerprinterClasses} from './definitions/fingerprinter_classes.js' export const SCHEMA = { 'title': 'Monkey', @@ -12,7 +13,8 @@ export const SCHEMA = { 'brute_force_classes': bruteForceExploiters, 'vulnerability_classes': vulnerabilityExploiters, 'credential_collectors_classes': credentialCollectors, - 'post_breach_actions': postBreachActions + 'post_breach_actions': postBreachActions, + 'fingerprinter_classes': fingerprinterClasses }, 'properties': { 'propagation': propagationConfigurationSchema, diff --git a/monkey/monkey_island/cc/ui/src/services/configuration/definitions/exploitation_options.js b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/exploitation_options.js index 6d6834ba1..e13d4ef7d 100644 --- a/monkey/monkey_island/cc/ui/src/services/configuration/definitions/exploitation_options.js +++ b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/exploitation_options.js @@ -1,4 +1,5 @@ export const exploitationOptionsConfigurationSchema = { + 'title': 'Exploiters Options', 'type': 'object', 'properties': { 'http_ports': { diff --git a/monkey/monkey_island/cc/ui/src/services/configuration/definitions/fingerprinter_classes.js b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/fingerprinter_classes.js new file mode 100644 index 000000000..1d4621599 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/fingerprinter_classes.js @@ -0,0 +1,52 @@ +export const fingerprinterClasses = { + 'title': 'Fingerprinters', + 'description': 'Fingerprint modules collect info about external services ' + + 'Infection Monkey scans.', + 'type': 'string', + 'pluginDefs': { + 'smb' : {'name':'smb', 'options':''}, + 'ssh' : {'name':'ssh', 'options':''}, + 'http' : {'name':'http', 'options':''}, + 'mssql' : {'name':'mssql', 'options':''}, + 'elastic' : {'name':'elastic', 'options':''} + }, + 'anyOf': [ + { + 'type': 'string', + 'enum': ['smb'], + 'title': 'SMB Fingerprinter', + 'safe': true, + 'info': 'Figures out if SMB is running and what\'s the version of it.' + }, + { + 'type': 'string', + 'enum': ['ssh'], + 'title': 'SSH Fingerprinter', + 'safe': true, + 'info': 'Figures out if SSH is running.' + }, + { + 'type': 'string', + 'enum': ['http'], + 'title': 'HTTP Fingerprinter', + 'safe': true, + 'info': 'Checks if host has HTTP/HTTPS ports open.' + }, + { + 'type': 'string', + 'enum': ['mssql'], + 'title': 'MSSQL Fingerprinter', + 'safe': true, + 'info': 'Checks if Microsoft SQL service is running and tries to gather ' + + 'information about it.' + }, + { + 'type': 'string', + 'enum': ['elastic'], + 'title': 'Elastic Fingerprinter', + 'safe': true, + 'info': 'Checks if ElasticSearch is running and attempts to find it\'s version.' + } + ] + +} diff --git a/monkey/monkey_island/cc/ui/src/services/configuration/definitions/network_scan.js b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/network_scan.js index 8b91a3cec..713ac1c82 100644 --- a/monkey/monkey_island/cc/ui/src/services/configuration/definitions/network_scan.js +++ b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/network_scan.js @@ -1,23 +1,18 @@ -import {pluginConfigurationSchema} from './plugins.js'; import {icmpScanConfigurationSchema} from './icmp_scan.js'; import {scanTargetConfigurationSchema} from './scan_target.js'; import {tcpScanConfigurationSchema} from './tcp_scan.js'; export const networkScanConfigurationSchema = { + 'title': 'Network analysis', 'type': 'object', - 'additionalProperties': false, 'properties': { 'fingerprinters': { 'title': 'Fingerprinters', 'type': 'array', - 'items': pluginConfigurationSchema, - 'default': [ - {'name': 'SMBFinger', 'safe': true, 'options': {}}, - {'name': 'SSHFinger', 'safe': true, 'options': {}}, - {'name': 'HTTPFinger', 'safe': true, 'options': {}}, - {'name': 'MSSQLFinger', 'safe': true, 'options': {}}, - {'name': 'ElasticFinger', 'safe': true, 'options': {}} - ] + 'uniqueItems': true, + 'items': { + '$ref': '#/definitions/fingerprinter_classes' + } }, 'icmp': icmpScanConfigurationSchema, 'targets': scanTargetConfigurationSchema, From 7cf64e798a3f846332a28ae2aafb9c00cf195415 Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Fri, 1 Jul 2022 18:06:42 +0200 Subject: [PATCH 16/33] UI: Add plugin definitions for vulnerability exploiters --- .../services/configuration/definitions/exploiter_classes.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/monkey/monkey_island/cc/ui/src/services/configuration/definitions/exploiter_classes.js b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/exploiter_classes.js index 12be7c791..bc7137fa1 100644 --- a/monkey/monkey_island/cc/ui/src/services/configuration/definitions/exploiter_classes.js +++ b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/exploiter_classes.js @@ -74,6 +74,11 @@ export const vulnerabilityExploiters = { '\u26A0 Note that using unsafe exploits may cause craches of the exploited ' + 'machine/service.', 'type': 'string', + 'pluginDefs': { + 'ZerologonExploiter': {'name': 'ZerologonExploiter', 'options':{}}, + 'Log4ShellExploiter': {'name': 'Log4ShellExploiter', 'options': {}}, + 'HadoopExploiter': {'name': 'HadoopExploiter', 'options': {}} + }, 'anyOf': [ { 'type': 'string', From 611818080ad5816e0e662e5e874a66d258df78ce Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Fri, 1 Jul 2022 18:12:58 +0200 Subject: [PATCH 17/33] UI: Fix some typos in json schema --- .../services/configuration/definitions/custom_pbas.js | 10 +++++----- .../services/configuration/definitions/propagation.js | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/monkey/monkey_island/cc/ui/src/services/configuration/definitions/custom_pbas.js b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/custom_pbas.js index 322aaf083..9ff14d3cc 100644 --- a/monkey/monkey_island/cc/ui/src/services/configuration/definitions/custom_pbas.js +++ b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/custom_pbas.js @@ -6,14 +6,14 @@ export const customPBAConfigurationSchema = { 'type': 'string', 'default': '', 'description': 'Command to be executed after breaching. ' + - 'Use this field to run custom commands or execute uploaded ' + - 'files on exploited machines.\nExample: ' + + 'Use this field to run custom commands or execute the uploaded ' + + 'file on exploited machines.\nExample: ' + '"chmod +x ./my_script.sh; ./my_script.sh ; rm ./my_script.sh"' }, 'linux_filename': { 'title': 'Linux post-breach file', 'type': 'string', - 'description': 'File to be uploaded after braeaching. ' + + 'description': 'File to be uploaded after breaching. ' + 'Use the "Linux post-breach command" field to ' + 'change permissions, run, or delete the file. ' + 'Reference your file by filename.' @@ -23,7 +23,7 @@ export const customPBAConfigurationSchema = { 'type': 'string', 'default': '', 'description': 'Command to be executed after breaching. ' + - 'Use this field to run custom commands or execute uploaded ' + + 'Use this field to run custom commands or execute the uploaded ' + 'file on exploited machine.\nExample: ' + '"my_script.bat & del my_script.bat"' }, @@ -31,7 +31,7 @@ export const customPBAConfigurationSchema = { 'title': 'Windows post-breach file', 'type': 'string', 'description': 'File to be uploaded after breaching. ' + - 'Use the "Windows post-breach command" filed to ' + + 'Use the "Windows post-breach command" field to ' + 'change permissions, run or delete the file. ' + 'Reference your file by filename.' } diff --git a/monkey/monkey_island/cc/ui/src/services/configuration/definitions/propagation.js b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/propagation.js index 0d8944909..3099876dc 100644 --- a/monkey/monkey_island/cc/ui/src/services/configuration/definitions/propagation.js +++ b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/propagation.js @@ -11,7 +11,7 @@ export const propagationConfigurationSchema = { 'type': 'integer', 'minimum': 1, 'default': 2, - 'description': 'Amount of hops alloed for the monkey to spread from the ' + + 'description': 'Amount of hops allowed for the monkey to spread from the ' + 'Island server. \n' + ' \u26A0' + ' Note that setting this value too high may result in the ' + From ab720a5a554e18abf3465bf2d26e38bce73aa4e9 Mon Sep 17 00:00:00 2001 From: vakarisz Date: Mon, 4 Jul 2022 12:16:52 +0300 Subject: [PATCH 18/33] UI: Refactor AdvancedMultiSelect.js to use props more --- .../ui-components/AdvancedMultiSelect.js | 44 ++++++++++--------- 1 file changed, 23 insertions(+), 21 deletions(-) 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 3588c0303..72639874a 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 @@ -32,20 +32,12 @@ function AdvancedMultiSelectHeader(props) { class AdvancedMultiSelect extends React.Component { constructor(props) { super(props); - this.infoPaneRefString = props.schema.items.$ref; - this.registry = props.registry; - this.pluginNames = props.value.map(v => v.name); this.state = { - masterCheckboxState: this.getMasterCheckboxState(this.pluginNames), - infoPaneParams: getDefaultPaneParams( - this.infoPaneRefString, - this.registry, - this.isUnsafeOptionSelected(this.pluginNames) - ), - pluginDefinitions: getObjectFromRegistryByRef(this.infoPaneRefString, - this.registry).pluginDefs, - pluginNames: props.value.map(v => v.name) + masterCheckboxState: this.getMasterCheckboxState(this.props.value.map(v => v.name)), + pluginDefinitions: getObjectFromRegistryByRef(this.props.schema.items.$ref, + this.props.registry).pluginDefs, + pluginNames: this.props.value.map(v => v.name) }; } @@ -155,12 +147,14 @@ class AdvancedMultiSelect extends React.Component { } isSafe = (itemKey) => { - console.log(getFullDefinitionByKey(this.infoPaneRefString, this.registry, itemKey)) - return getFullDefinitionByKey(this.infoPaneRefString, this.registry, itemKey).safe; + let fullDef = getFullDefinitionByKey(this.props.schema.items.$ref, + this.props.registry, itemKey); + return fullDef.safe; } setPaneInfo = (itemKey) => { - let definitionObj = getFullDefinitionByKey(this.infoPaneRefString, this.registry, itemKey); + let definitionObj = getFullDefinitionByKey(this.props.schema.items.$ref, + this.props.registry, itemKey); this.setState( { infoPaneParams: { @@ -192,12 +186,20 @@ class AdvancedMultiSelect extends React.Component { schema } = this.props; + let paneParams = getDefaultPaneParams( + this.props.schema.items.$ref, + this.props.registry, + this.isUnsafeOptionSelected(this.state.pluginNames) + ); + return (
v.name))} onResetClick={this.onResetClick}/> - +
); } From 26f51d15402a0697b60935395f7b0bdb24348228 Mon Sep 17 00:00:00 2001 From: vakarisz Date: Mon, 4 Jul 2022 12:19:16 +0300 Subject: [PATCH 19/33] UI: Fix a bug in ConfigurePage.js responsible for lacking re-render key property makes the component unique and causes a re-construction. This solves a bug where different configuration page tabs remain with the same data on switch --- .../ui/src/components/pages/ConfigurePage.js | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/monkey/monkey_island/cc/ui/src/components/pages/ConfigurePage.js b/monkey/monkey_island/cc/ui/src/components/pages/ConfigurePage.js index a6c36182a..44f080014 100644 --- a/monkey/monkey_island/cc/ui/src/components/pages/ConfigurePage.js +++ b/monkey/monkey_island/cc/ui/src/components/pages/ConfigurePage.js @@ -353,17 +353,14 @@ class ConfigurePageComponent extends AuthComponent { formProperties['formData'], formProperties['uiSchema']); - if (this.state.selectedSection === 'internal') { - return () - } else { - return ( -
-
- -
-
- ) - } + console.log(displayedSchema) + return ( +
+
+ +
+
+ ) }; setPbaFilenameWindows = (filename) => { From 7df10f77303369ae2ec89588b8ec269836c0a76a Mon Sep 17 00:00:00 2001 From: vakarisz Date: Mon, 4 Jul 2022 12:19:26 +0300 Subject: [PATCH 20/33] UI: Fix a bug in ConfigurePage.js responsible for lacking re-render key property makes the component unique and causes a re-construction. This solves a bug where different configuration page tabs remain with the same data on switch --- .../monkey_island/cc/ui/src/components/pages/ConfigurePage.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/monkey/monkey_island/cc/ui/src/components/pages/ConfigurePage.js b/monkey/monkey_island/cc/ui/src/components/pages/ConfigurePage.js index 44f080014..4804f99fc 100644 --- a/monkey/monkey_island/cc/ui/src/components/pages/ConfigurePage.js +++ b/monkey/monkey_island/cc/ui/src/components/pages/ConfigurePage.js @@ -8,7 +8,6 @@ import {faCheck} from '@fortawesome/free-solid-svg-icons/faCheck'; import {faExclamationCircle} from '@fortawesome/free-solid-svg-icons/faExclamationCircle'; import {formValidationFormats} from '../configuration-components/ValidationFormats'; import transformErrors from '../configuration-components/ValidationErrorMessages'; -import InternalConfig from '../configuration-components/InternalConfig'; import UnsafeConfigOptionsConfirmationModal from '../configuration-components/UnsafeConfigOptionsConfirmationModal.js'; import UnsafeOptionsWarningModal from '../configuration-components/UnsafeOptionsWarningModal.js'; @@ -353,7 +352,6 @@ class ConfigurePageComponent extends AuthComponent { formProperties['formData'], formProperties['uiSchema']); - console.log(displayedSchema) return (
From 61eaa4898851f8735041c470bc3e3688e37f6661 Mon Sep 17 00:00:00 2001 From: vakarisz Date: Mon, 4 Jul 2022 12:20:24 +0300 Subject: [PATCH 21/33] UI: Fix formatting in UiSchema.js --- .../configuration-components/UiSchema.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js b/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js index e1134e63c..be1ab6abb 100644 --- a/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js +++ b/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js @@ -36,23 +36,23 @@ export default function UiSchema(props) { } } }, - custom_pbas : { + custom_pbas: { classNames: 'config-template-no-header' }, post_breach_actions: { - classNames: 'config-template-no-header', - 'ui:widget': AdvancedMultiSelect, - post_breach_actions: { - classNames: 'config-template-no-header' - } + classNames: 'config-template-no-header', + 'ui:widget': AdvancedMultiSelect, + post_breach_actions: { + classNames: 'config-template-no-header' + } }, credential_collectors: { classNames: 'config-template-no-header', 'ui:widget': AdvancedMultiSelect, - credential_collectors_classes :{ - classNames: 'config-template-no-header' - } + credential_collectors_classes: { + classNames: 'config-template-no-header' } + } }; return UiSchema[props.selectedSection] } From ed4653813753a8e4cfda2c9c69d7a18f017e5e86 Mon Sep 17 00:00:00 2001 From: vakarisz Date: Mon, 4 Jul 2022 12:37:35 +0300 Subject: [PATCH 22/33] UI: Improve state contents in AdvancedMultiSelect.js --- .../ui-components/AdvancedMultiSelect.js | 26 ++++++++----------- 1 file changed, 11 insertions(+), 15 deletions(-) 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 72639874a..ed112e68d 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 @@ -34,10 +34,11 @@ class AdvancedMultiSelect extends React.Component { super(props); this.state = { + allPluginNames: this.props.value.map(v => v.name), masterCheckboxState: this.getMasterCheckboxState(this.props.value.map(v => v.name)), pluginDefinitions: getObjectFromRegistryByRef(this.props.schema.items.$ref, this.props.registry).pluginDefs, - pluginNames: this.props.value.map(v => v.name) + selectedPluginNames: this.props.value.map(v => v.name) }; } @@ -62,7 +63,7 @@ class AdvancedMultiSelect extends React.Component { } newValues = JSON.parse(JSON.stringify(newValues)); this.props.onChange(newValues) - this.setState({pluginNames: newValues.map(v => v.name)}); + this.setState({selectedPluginNames: newValues.map(v => v.name)}); } // Sort options alphabetically. "Unsafe" options float to the top so that they @@ -79,7 +80,7 @@ class AdvancedMultiSelect extends React.Component { } onMasterCheckboxClick = () => { - let checkboxState = this.getMasterCheckboxState(this.state.pluginNames); + let checkboxState = this.getMasterCheckboxState(this.state.selectedPluginNames); if (checkboxState === MasterCheckboxState.ALL) { var newValues = []; } else { @@ -97,7 +98,7 @@ class AdvancedMultiSelect extends React.Component { } getSelectValuesAfterClick(clickedValue) { - const valueArray = cloneDeep(this.state.pluginNames); + const valueArray = cloneDeep(this.state.selectedPluginNames); if (valueArray.includes(clickedValue)) { return valueArray.filter(e => e !== clickedValue); @@ -168,13 +169,8 @@ class AdvancedMultiSelect extends React.Component { } setPaneInfoToSafe(isUnsafeOptionSelected) { - this.setState(() => ({ - infoPaneParams: getDefaultPaneParams( - this.props.schema.items.$ref, - this.props.registry, - isUnsafeOptionSelected - ) - })); + let safePluginNames = this.state.allPluginNames.filter(pluginName => this.isSafe(pluginName)); + this.setState({selectedPluginNames: safePluginNames}); } render() { @@ -189,7 +185,7 @@ class AdvancedMultiSelect extends React.Component { let paneParams = getDefaultPaneParams( this.props.schema.items.$ref, this.props.registry, - this.isUnsafeOptionSelected(this.state.pluginNames) + this.isUnsafeOptionSelected(this.state.selectedPluginNames) ); return ( @@ -197,16 +193,16 @@ class AdvancedMultiSelect extends React.Component { v.name))} + this.state.allPluginNames)} onResetClick={this.onResetClick}/> Date: Mon, 4 Jul 2022 13:00:36 +0300 Subject: [PATCH 23/33] UI: Fix reset button in AdvancedMultiSelect.js Reset button will reset to all safe values --- .../ui-components/AdvancedMultiSelect.js | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) 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 ed112e68d..46c7d0fb6 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 @@ -93,8 +93,6 @@ class AdvancedMultiSelect extends React.Component { onChildCheckboxClick = (value) => { let selectValues = this.getSelectValuesAfterClick(value); this.onChange(selectValues); - - this.setHideResetState(selectValues); } getSelectValuesAfterClick(clickedValue) { @@ -128,15 +126,7 @@ class AdvancedMultiSelect extends React.Component { } onResetClick = () => { - this.onChange(this.defaultValues); - this.setHideResetState(this.defaultValues); - this.setPaneInfoToSafe(this.isUnsafeOptionSelected(this.defaultValues)); - } - - setHideResetState(selectValues) { - this.setState(() => ({ - hideReset: this.getHideResetState(selectValues) - })); + this.setPaneInfoToSafe(); } getHideResetState(selectValues) { @@ -168,9 +158,10 @@ class AdvancedMultiSelect extends React.Component { ); } - setPaneInfoToSafe(isUnsafeOptionSelected) { + setPaneInfoToSafe() { let safePluginNames = this.state.allPluginNames.filter(pluginName => this.isSafe(pluginName)); this.setState({selectedPluginNames: safePluginNames}); + this.onChange(safePluginNames); } render() { @@ -195,7 +186,7 @@ class AdvancedMultiSelect extends React.Component { checkboxState={this.getMasterCheckboxState( this.state.selectedPluginNames)} hideReset={this.getHideResetState( - this.state.allPluginNames)} + this.state.selectedPluginNames)} onResetClick={this.onResetClick}/> Date: Mon, 4 Jul 2022 13:54:07 +0300 Subject: [PATCH 24/33] UI: Fix info pane in AdvancedMultiSelect.js --- .../ui-components/AdvancedMultiSelect.js | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) 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 46c7d0fb6..5cf4354b1 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 @@ -33,12 +33,19 @@ class AdvancedMultiSelect extends React.Component { constructor(props) { super(props); + let pluginNames = this.props.value.map(v => v.name); + this.state = { - allPluginNames: this.props.value.map(v => v.name), - masterCheckboxState: this.getMasterCheckboxState(this.props.value.map(v => v.name)), + infoPaneParams: getDefaultPaneParams( + this.props.schema.items.$ref, + this.props.registry, + this.isUnsafeOptionSelected(pluginNames) + ), + allPluginNames: pluginNames, + masterCheckboxState: this.getMasterCheckboxState(pluginNames), pluginDefinitions: getObjectFromRegistryByRef(this.props.schema.items.$ref, this.props.registry).pluginDefs, - selectedPluginNames: this.props.value.map(v => v.name) + selectedPluginNames: pluginNames }; } @@ -173,12 +180,6 @@ class AdvancedMultiSelect extends React.Component { schema } = this.props; - let paneParams = getDefaultPaneParams( - this.props.schema.items.$ref, - this.props.registry, - this.isUnsafeOptionSelected(this.state.selectedPluginNames) - ); - return (
- +
); } From a4e66a0c9e586a57980f5c1184f2d38795c287e0 Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Mon, 4 Jul 2022 13:11:30 +0200 Subject: [PATCH 25/33] UI: Add ransomware to config schema --- .../configuration-components/UiSchema.js | 12 ++++ .../services/configuration/config_schema.js | 11 +--- .../configuration/definitions/ransomware.js | 65 +++++++++++++++++++ 3 files changed, 79 insertions(+), 9 deletions(-) create mode 100644 monkey/monkey_island/cc/ui/src/services/configuration/definitions/ransomware.js diff --git a/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js b/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js index be1ab6abb..bc4a72a14 100644 --- a/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js +++ b/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js @@ -1,5 +1,6 @@ import AdvancedMultiSelect from '../ui-components/AdvancedMultiSelect'; import InfoBox from './InfoBox'; +import TextBox from './TextBox.js'; export default function UiSchema(props) { const UiSchema = { @@ -36,6 +37,17 @@ export default function UiSchema(props) { } } }, + payloads: { + classNames: 'config-template-no-header', + encryption: { + info_box : { + 'ui:field': InfoBox + }, + text_box: { + 'ui:field': TextBox + } + } + }, custom_pbas: { classNames: 'config-template-no-header' }, diff --git a/monkey/monkey_island/cc/ui/src/services/configuration/config_schema.js b/monkey/monkey_island/cc/ui/src/services/configuration/config_schema.js index a0ad4818b..6700e5e4a 100644 --- a/monkey/monkey_island/cc/ui/src/services/configuration/config_schema.js +++ b/monkey/monkey_island/cc/ui/src/services/configuration/config_schema.js @@ -1,5 +1,5 @@ import {customPBAConfigurationSchema} from './definitions/custom_pbas.js'; -import {pluginConfigurationSchema} from './definitions/plugins.js'; +import {ransomwareSchema} from './definitions/ransomware.js'; import {propagationConfigurationSchema} from './definitions/propagation.js'; import {bruteForceExploiters, vulnerabilityExploiters} from './definitions/exploiter_classes.js'; import {credentialCollectors} from './definitions/credential_collectors.js'; @@ -27,14 +27,7 @@ export const SCHEMA = { } }, 'custom_pbas': customPBAConfigurationSchema, - 'payloads': { - 'title': 'Payloads', - 'type': 'array', - 'items': pluginConfigurationSchema, - 'default': [ - {'name': 'ransomware', 'safe': true, 'options': {}} - ] - }, + 'payloads': ransomwareSchema, 'credential_collectors': { 'title': 'Credential collectors', 'type': 'array', diff --git a/monkey/monkey_island/cc/ui/src/services/configuration/definitions/ransomware.js b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/ransomware.js new file mode 100644 index 000000000..fa46d03c9 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/ransomware.js @@ -0,0 +1,65 @@ +export const ransomwareSchema = { + 'title': 'Payloads', + 'properties': { + 'encryption': { + 'title': 'Ransomware simulation', + 'type': 'object', + 'description': 'To simulate ransomware encryption, you\'ll need to provide Infection ' + + 'Monkey with files that it can safely encrypt. On each machine where you would like ' + + 'the ransomware simulation to run, create a directory and put some files in it.' + + '\n\nProvide the path to the directory that was created on each machine.', + 'properties': { + 'enabled': { + 'title': 'Encrypt files', + 'type': 'boolean', + 'default': true, + 'description': 'Ransomware encryption will be simulated by flipping every bit ' + + 'in the files contained within the target directories.' + }, + 'info_box': { + 'info': 'No files will be encrypted if a directory is not specified or doesn\'t ' + + 'exist on a victim machine.' + }, + 'directories': { + 'title': 'Directories to encrypt', + 'type': 'object', + 'properties': { + 'linux_target_dir': { + 'title': 'Linux target directory', + 'type': 'string', + 'format': 'valid-ransomware-target-path-linux', + 'default': '', + 'description': 'A path to a directory on Linux systems that contains ' + + 'files that you will allow Infection Monkey to encrypt. If no ' + + 'directory is specified, no files will be encrypted.' + }, + 'windows_target_dir': { + 'title': 'Windows target directory', + 'type': 'string', + 'format': 'valid-ransomware-target-path-windows', + 'default': '', + 'description': 'A path to a directory on Windows systems that contains ' + + 'files that you will allow Infection Monkey to encrypt. If no ' + + 'directory is specified, no files will be encrypted.' + } + } + }, + 'text_box': { + 'text': 'Note: A README.txt will be left in the specified target directory.' + } + } + }, + 'other_behaviors': { + 'title': 'Other ransomware behavior', + 'type': 'object', + 'properties': { + 'readme': { + 'title': 'Create a README.txt file', + 'type': 'boolean', + 'default': true, + 'description': 'Creates a README.txt ransomware note on infected systems.' + } + } + } + } +} From 88663f527609175e5f152088d56f11f5d4b0ad36 Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Mon, 4 Jul 2022 13:11:58 +0200 Subject: [PATCH 26/33] UI: Add defaults for the payloads section --- .../cc/ui/src/components/pages/ConfigurePage.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/monkey/monkey_island/cc/ui/src/components/pages/ConfigurePage.js b/monkey/monkey_island/cc/ui/src/components/pages/ConfigurePage.js index 4804f99fc..ee910cea1 100644 --- a/monkey/monkey_island/cc/ui/src/components/pages/ConfigurePage.js +++ b/monkey/monkey_island/cc/ui/src/components/pages/ConfigurePage.js @@ -64,7 +64,9 @@ class ConfigurePageComponent extends AuthComponent { setInitialConfig(config) { // Sets a reference to know if config was changed + console.log(config, SCHEMA); this.initialConfig = JSON.parse(JSON.stringify(config)); + console.log(this.initialConfig); } componentDidMount = () => { @@ -267,9 +269,15 @@ class ConfigurePageComponent extends AuthComponent { this.updateConfigSection(); this.currentSection = key; + let selectedSectionData = this.state.configuration[key]; + + if(key == 'payloads') { + selectedSectionData = this.state.configuration[key][0]['options']; + } + this.setState({ selectedSection: key, - currentFormData: this.state.configuration[key] + currentFormData: selectedSectionData }); }; From df7e43d79671595dfc73b92d4f8b6388129fe60f Mon Sep 17 00:00:00 2001 From: vakarisz Date: Mon, 4 Jul 2022 14:46:40 +0300 Subject: [PATCH 27/33] UI: Fix SafeOptionValidator.js for the new schema --- .../components/utils/SafeOptionValidator.js | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/monkey/monkey_island/cc/ui/src/components/utils/SafeOptionValidator.js b/monkey/monkey_island/cc/ui/src/components/utils/SafeOptionValidator.js index ac6702328..52aec245d 100644 --- a/monkey/monkey_island/cc/ui/src/components/utils/SafeOptionValidator.js +++ b/monkey/monkey_island/cc/ui/src/components/utils/SafeOptionValidator.js @@ -1,24 +1,29 @@ function getPluginDescriptors(schema, config) { return ([ { - name: 'Exploiters', - allPlugins: schema.definitions.exploiter_classes.anyOf, - selectedPlugins: config.basic.exploiters.exploiter_classes + name: 'Brute force exploiters', + allPlugins: schema.definitions.brute_force_classes.anyOf, + selectedPlugins: config.propagation.exploitation.brute_force + }, + { + name: 'Vulnerability exploiters', + allPlugins: schema.definitions.vulnerability_classes.anyOf, + selectedPlugins: config.propagation.exploitation.vulnerability }, { name: 'Fingerprinters', - allPlugins: schema.definitions.finger_classes.anyOf, - selectedPlugins: config.internal.classes.finger_classes + allPlugins: schema.definitions.fingerprinter_classes.anyOf, + selectedPlugins: config.propagation.network_scan.fingerprinters }, { name: 'PostBreachActions', allPlugins: schema.definitions.post_breach_actions.anyOf, - selectedPlugins: config.monkey.post_breach.post_breach_actions + selectedPlugins: config.post_breach_actions }, { name: 'CredentialCollectors', - allPlugins: schema.definitions.credential_collectors.anyOf, - selectedPlugins: config.monkey.credential_collectors.credential_collectors + allPlugins: schema.definitions.credential_collectors_classes.anyOf, + selectedPlugins: config.credential_collectors } ]); } @@ -40,7 +45,7 @@ function isUnsafePluginSelected(pluginDescriptor) { pluginDescriptor.allPlugins.forEach(i => pluginSafety[i.enum[0]] = i.safe); for (let selected of pluginDescriptor.selectedPlugins) { - if (!pluginSafety[selected]) { + if (!pluginSafety[selected.name]) { return true; } } From 51609e94918deb6ff67dec961cdcbf8d74a6e9fe Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Mon, 4 Jul 2022 13:47:57 +0200 Subject: [PATCH 28/33] UI: Fix missaligned items in propagation --- .../configuration-components/UiSchema.js | 29 +++++++++++++++++++ .../configuration/definitions/scan_target.js | 2 +- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js b/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js index bc4a72a14..78b10276d 100644 --- a/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js +++ b/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js @@ -19,12 +19,41 @@ export default function UiSchema(props) { vulnerability_classes: { classNames: 'config-template-no-header' } + }, + options: { + http_ports: { + items: { + classNames: 'config-template-no-header' + } + } } }, network_scan: { targets: { info_box: { 'ui:field': InfoBox + }, + blocked_ips: { + items: { + classNames: 'config-template-no-header' + } + }, + inaccessible_subnets: { + items: { + classNames: 'config-template-no-header' + } + }, + subnets: { + items: { + classNames: 'config-template-no-header' + } + } + }, + tcp: { + ports: { + items: { + classNames: 'config-template-no-header' + } } }, fingerprinters:{ diff --git a/monkey/monkey_island/cc/ui/src/services/configuration/definitions/scan_target.js b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/scan_target.js index 74f0896bb..ba2c769e6 100644 --- a/monkey/monkey_island/cc/ui/src/services/configuration/definitions/scan_target.js +++ b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/scan_target.js @@ -17,7 +17,7 @@ export const scanTargetConfigurationSchema = { 'default': [], 'description': 'List of IPs that the monkey will not scan.' }, - 'inaccessible_sbunets': { + 'inaccessible_subnets': { 'title': 'Network segmentation testing', 'type': 'array', 'uniqueItems': true, From a1f4a6978a7a0cdfe31906cb0cdbb21122039182 Mon Sep 17 00:00:00 2001 From: vakarisz Date: Mon, 4 Jul 2022 15:23:38 +0300 Subject: [PATCH 29/33] UI: Remove unneeded console logs from ConfigurePage.js --- .../monkey_island/cc/ui/src/components/pages/ConfigurePage.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/monkey/monkey_island/cc/ui/src/components/pages/ConfigurePage.js b/monkey/monkey_island/cc/ui/src/components/pages/ConfigurePage.js index ee910cea1..221aae985 100644 --- a/monkey/monkey_island/cc/ui/src/components/pages/ConfigurePage.js +++ b/monkey/monkey_island/cc/ui/src/components/pages/ConfigurePage.js @@ -64,9 +64,7 @@ class ConfigurePageComponent extends AuthComponent { setInitialConfig(config) { // Sets a reference to know if config was changed - console.log(config, SCHEMA); this.initialConfig = JSON.parse(JSON.stringify(config)); - console.log(this.initialConfig); } componentDidMount = () => { From 66c2bc492cea4e56ac79394a1f282d3fac4f25d6 Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Mon, 4 Jul 2022 14:45:09 +0200 Subject: [PATCH 30/33] UI: Fix custom pbas in the schema --- .../configuration-components/UiSchema.js | 36 ++++++++++++++++++- .../configuration/definitions/custom_pbas.js | 16 +++++++-- 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js b/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js index 78b10276d..43423263f 100644 --- a/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js +++ b/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js @@ -1,6 +1,8 @@ import AdvancedMultiSelect from '../ui-components/AdvancedMultiSelect'; import InfoBox from './InfoBox'; import TextBox from './TextBox.js'; +import PbaInput from './PbaInput'; +import {API_PBA_LINUX, API_PBA_WINDOWS} from '../pages/ConfigurePage'; export default function UiSchema(props) { const UiSchema = { @@ -78,7 +80,39 @@ export default function UiSchema(props) { } }, custom_pbas: { - classNames: 'config-template-no-header' + classNames: 'config-template-no-header', + linux_command: { + 'ui:widget': 'textarea', + 'ui:emptyValue': '' + }, + linux_file: { + 'ui:widget': PbaInput, + 'ui:options': { + filename: props.linux_filename, + apiEndpoint: API_PBA_LINUX, + setPbaFilename: props.setPbaFilenameLinux + } + }, + windows_command: { + 'ui:widget': 'textarea', + 'ui:emptyValue': '' + }, + windows_file: { + 'ui:widget': PbaInput, + 'ui:options': { + filename: props.windows_filename, + apiEndpoint: API_PBA_WINDOWS, + setPbaFilename: props.setPbaFilenameWindows + } + }, + linux_filename: { + classNames: 'linux-pba-file-info', + 'ui:emptyValue': '' + }, + windows_filename: { + classNames: 'windows-pba-file-info', + 'ui:emptyValue': '' + } }, post_breach_actions: { classNames: 'config-template-no-header', diff --git a/monkey/monkey_island/cc/ui/src/services/configuration/definitions/custom_pbas.js b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/custom_pbas.js index 9ff14d3cc..06d51a304 100644 --- a/monkey/monkey_island/cc/ui/src/services/configuration/definitions/custom_pbas.js +++ b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/custom_pbas.js @@ -10,14 +10,20 @@ export const customPBAConfigurationSchema = { 'file on exploited machines.\nExample: ' + '"chmod +x ./my_script.sh; ./my_script.sh ; rm ./my_script.sh"' }, - 'linux_filename': { + 'linux_file': { 'title': 'Linux post-breach file', 'type': 'string', + 'format': 'data-url', 'description': 'File to be uploaded after breaching. ' + 'Use the "Linux post-breach command" field to ' + 'change permissions, run, or delete the file. ' + 'Reference your file by filename.' }, + 'linux_filename': { + 'title': 'Linux PBA filename', + 'type': 'string', + 'default': '' + }, 'windows_command': { 'title': 'Windows post-breach command', 'type': 'string', @@ -27,13 +33,19 @@ export const customPBAConfigurationSchema = { 'file on exploited machine.\nExample: ' + '"my_script.bat & del my_script.bat"' }, - 'windows_filename':{ + 'windows_file':{ 'title': 'Windows post-breach file', 'type': 'string', + 'format': 'data-url', 'description': 'File to be uploaded after breaching. ' + 'Use the "Windows post-breach command" field to ' + 'change permissions, run or delete the file. ' + 'Reference your file by filename.' + }, + 'windows_filename': { + 'title': 'Windows PBA filename', + 'type': 'string', + 'default': '' } } } From a37157b086df96791d6fd8801d3854e64c518256 Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Mon, 4 Jul 2022 14:46:03 +0200 Subject: [PATCH 31/33] UI: Rename custom PBA filename options --- .../cc/ui/src/components/pages/ConfigurePage.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/monkey/monkey_island/cc/ui/src/components/pages/ConfigurePage.js b/monkey/monkey_island/cc/ui/src/components/pages/ConfigurePage.js index 221aae985..f12e95a1c 100644 --- a/monkey/monkey_island/cc/ui/src/components/pages/ConfigurePage.js +++ b/monkey/monkey_island/cc/ui/src/components/pages/ConfigurePage.js @@ -344,7 +344,11 @@ class ConfigurePageComponent extends AuthComponent { let formProperties = {}; formProperties['schema'] = displayedSchema formProperties['uiSchema'] = UiSchema({ - selectedSection: this.state.selectedSection + selectedSection: this.state.selectedSection, + linux_filename: this.state.configuration.custom_pbas.linux_filename, + windows_filename: this.state.configuration.custom_pbas.windows_filename, + setPbaFilenameWindows: this.setPbaFilenameWindows, + setPbaFilenameLinux: this.setPbaFilenameLinux }) formProperties['fields'] = {DescriptionField: HtmlFieldDescription}; formProperties['formData'] = this.state.currentFormData; @@ -369,7 +373,7 @@ class ConfigurePageComponent extends AuthComponent { setPbaFilenameWindows = (filename) => { let config = this.state.configuration - config.monkey.post_breach.PBA_windows_filename = filename + config.custom_pbas.windows_filename = filename this.setState({ configuration: config }) @@ -377,7 +381,7 @@ class ConfigurePageComponent extends AuthComponent { setPbaFilenameLinux = (filename) => { let config = this.state.configuration - config.monkey.post_breach.PBA_linux_filename = filename + config.custom_pbas.linux_filename = filename this.setState({ configuration: config }) From 3bbbca783dc2ecbe1edf116e2a0ff3c836b60c6f Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Mon, 4 Jul 2022 15:04:30 +0200 Subject: [PATCH 32/33] UI: Fix UiSchema manipulators to use payloads section --- .../configuration-components/UISchemaManipulators.tsx | 2 +- .../src/components/configuration-components/UiSchema.js | 9 +++++++++ .../cc/ui/src/components/pages/ConfigurePage.js | 7 +++---- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/monkey/monkey_island/cc/ui/src/components/configuration-components/UISchemaManipulators.tsx b/monkey/monkey_island/cc/ui/src/components/configuration-components/UISchemaManipulators.tsx index 637a128f3..34ceb4ab4 100644 --- a/monkey/monkey_island/cc/ui/src/components/configuration-components/UISchemaManipulators.tsx +++ b/monkey/monkey_island/cc/ui/src/components/configuration-components/UISchemaManipulators.tsx @@ -12,7 +12,7 @@ function applyUiSchemaManipulators(selectedSection, function ransomwareDirManipulator(selectedSection, formData, uiSchema) { - if (selectedSection === 'ransomware'){ + if (selectedSection === 'payloads'){ uiSchema.encryption.directories = {'ui:disabled': !formData['encryption']['enabled']}; } diff --git a/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js b/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js index 43423263f..d70a6f32c 100644 --- a/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js +++ b/monkey/monkey_island/cc/ui/src/components/configuration-components/UiSchema.js @@ -74,9 +74,18 @@ export default function UiSchema(props) { info_box : { 'ui:field': InfoBox }, + directories: { + // Directory inputs are dynamically hidden + }, text_box: { 'ui:field': TextBox + }, + enabled: { + 'ui:widget': 'hidden' } + }, + other_behaviors : { + 'ui:widget': 'hidden' } }, custom_pbas: { diff --git a/monkey/monkey_island/cc/ui/src/components/pages/ConfigurePage.js b/monkey/monkey_island/cc/ui/src/components/pages/ConfigurePage.js index f12e95a1c..23e21bf1a 100644 --- a/monkey/monkey_island/cc/ui/src/components/pages/ConfigurePage.js +++ b/monkey/monkey_island/cc/ui/src/components/pages/ConfigurePage.js @@ -74,6 +74,9 @@ class ConfigurePageComponent extends AuthComponent { .then(data => { let sections = []; let monkeyConfig = data[0]; + // TODO: Fix when we add plugins + monkeyConfig['payloads'] = monkeyConfig['payloads'][0]['options']; + this.setInitialConfig(monkeyConfig); for (let sectionKey of this.getSectionsOrder()) { sections.push({ @@ -269,10 +272,6 @@ class ConfigurePageComponent extends AuthComponent { this.currentSection = key; let selectedSectionData = this.state.configuration[key]; - if(key == 'payloads') { - selectedSectionData = this.state.configuration[key][0]['options']; - } - this.setState({ selectedSection: key, currentFormData: selectedSectionData From d0612f06d86c2de92ffb44ae7e1732c46bdd82ba Mon Sep 17 00:00:00 2001 From: vakarisz Date: Tue, 5 Jul 2022 10:32:07 +0300 Subject: [PATCH 33/33] UI: Fix incorrect allPluginNames in AdvancedMultiSelect.js All plugin names were in fact only the initially selected values --- .../ui-components/AdvancedMultiSelect.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) 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 5cf4354b1..fbef10235 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 @@ -33,19 +33,20 @@ class AdvancedMultiSelect extends React.Component { constructor(props) { super(props); - let pluginNames = this.props.value.map(v => v.name); + let selectedPluginNames = this.props.value.map(v => v.name); + let allPluginNames = this.props.options.enumOptions.map(v => v.value); this.state = { infoPaneParams: getDefaultPaneParams( this.props.schema.items.$ref, this.props.registry, - this.isUnsafeOptionSelected(pluginNames) + this.isUnsafeOptionSelected(selectedPluginNames) ), - allPluginNames: pluginNames, - masterCheckboxState: this.getMasterCheckboxState(pluginNames), + allPluginNames: allPluginNames, + masterCheckboxState: this.getMasterCheckboxState(selectedPluginNames), pluginDefinitions: getObjectFromRegistryByRef(this.props.schema.items.$ref, this.props.registry).pluginDefs, - selectedPluginNames: pluginNames + selectedPluginNames: selectedPluginNames }; } @@ -57,8 +58,8 @@ class AdvancedMultiSelect extends React.Component { let newValues = []; for (let j = 0; j < strValues.length; j++) { let found = false; - for (let i = 0; i < this.props.value.length; i++) { - if (strValues[j] === this.props.value[i]['name']) { + for (let i = 0; i < this.state.allPluginNames.length; i++) { + if (strValues[j] === this.state.allPluginNames[i]['name']) { newValues.push(JSON.parse(JSON.stringify(this.props.value[i]))) found = true; break;