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..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 @@ -1,23 +1,25 @@ const CONFIGURATION_TABS = { - BASIC: 'basic', - BASIC_NETWORK: 'basic_network', - RANSOMWARE: 'ransomware', - MONKEY: 'monkey', - INTERNAL: 'internal' + PROPAGATION: 'propagation', + PAYLOADS: 'payloads', + PBA: 'post_breach_actions', + CUSTOM_PBA: 'custom_pbas', + 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.CUSTOM_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 = { 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 632076921..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 @@ -1,139 +1,140 @@ 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'; -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: { + propagation: { + exploitation: { + brute_force: { classNames: 'config-template-no-header', - 'ui:widget': AdvancedMultiSelect - } - }, - credentials: { - exploit_user_list: { - items: { + 'ui:widget': AdvancedMultiSelect, + brute_force_classes: { 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: { + vulnerability: { + classNames: 'config-template-no-header', + 'ui:widget': AdvancedMultiSelect, + vulnerability_classes: { classNames: 'config-template-no-header' } }, - subnet_scan_list: { - format: 'ip-list', - items: { - classNames: 'config-template-no-header' + options: { + http_ports: { + items: { + classNames: 'config-template-no-header' + } } } }, - network_analysis: { - inaccessible_subnets: { - items: { + 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:{ + classNames: 'config-template-no-header', + 'ui:widget': AdvancedMultiSelect, + fingerprinter_classes: { 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: { + payloads: { + classNames: 'config-template-no-header', encryption: { - info_box: { + info_box : { 'ui:field': InfoBox }, directories: { - // Directory inputs are dynamically hidden + // Directory inputs are dynamically hidden }, text_box: { 'ui:field': TextBox }, - enabled: {'ui:widget': 'hidden'} + enabled: { + 'ui:widget': 'hidden' + } }, - other_behaviors : {'ui:widget': 'hidden'} + other_behaviors : { + 'ui:widget': 'hidden' + } }, - internal: { - classes: { - finger_classes: { - classNames: 'config-template-no-header', - 'ui:widget': AdvancedMultiSelect + custom_pbas: { + 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 } }, - exploits: { - exploit_lm_hash_list:{ - items: { - 'ui:widget': SensitiveTextInput - } - }, - exploit_ntlm_hash_list: { - items: { - 'ui:widget': SensitiveTextInput - } + 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', + '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' } } }; 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 49b46cc43..8bcad002b 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'; @@ -18,6 +17,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 +68,28 @@ 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); + // TODO: Fix when we add plugins + monkeyConfig['payloads'] = monkeyConfig['payloads'][0]['options']; + + 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] }) }); }; @@ -266,9 +270,11 @@ class ConfigurePageComponent extends AuthComponent { this.updateConfigSection(); this.currentSection = key; + let selectedSectionData = this.state.configuration[key]; + this.setState({ selectedSection: key, - currentFormData: this.state.configuration[key] + currentFormData: selectedSectionData }); }; @@ -337,11 +343,11 @@ 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, + 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, - selectedSection: this.state.selectedSection + setPbaFilenameLinux: this.setPbaFilenameLinux }) formProperties['fields'] = {DescriptionField: HtmlFieldDescription}; formProperties['formData'] = this.state.currentFormData; @@ -355,22 +361,18 @@ class ConfigurePageComponent extends AuthComponent { formProperties['formData'], formProperties['uiSchema']); - if (this.state.selectedSection === 'internal') { - return () - } else { - return ( -
-
- -
-
- ) - } + return ( +
+
+ +
+
+ ) }; 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 }) @@ -378,7 +380,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 }) @@ -391,7 +393,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} 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..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 @@ -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,12 +17,13 @@ function AdvancedMultiSelectHeader(props) { onResetClick } = props; + return ( ); @@ -32,22 +33,47 @@ 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); + let selectedPluginNames = this.props.value.map(v => v.name); + let allPluginNames = this.props.options.enumOptions.map(v => v.value); this.state = { - masterCheckboxState: this.getMasterCheckboxState(props.value), - hideReset: this.getHideResetState(props.value), infoPaneParams: getDefaultPaneParams( - this.infoPaneRefString, - this.registry, - this.isUnsafeOptionSelected(props.value) - ) + this.props.schema.items.$ref, + this.props.registry, + this.isUnsafeOptionSelected(selectedPluginNames) + ), + allPluginNames: allPluginNames, + masterCheckboxState: this.getMasterCheckboxState(selectedPluginNames), + pluginDefinitions: getObjectFromRegistryByRef(this.props.schema.items.$ref, + this.props.registry).pluginDefs, + selectedPluginNames: selectedPluginNames }; } + getOptionList = () => { + return this.props.options.enumOptions.sort(this.compareOptions); + } + + onChange = (strValues) => { + let newValues = []; + for (let j = 0; j < strValues.length; j++) { + let found = false; + 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; + } + } + if (!found) { + newValues.push(this.state.pluginDefinitions[strValues[j]]); + } + } + newValues = JSON.parse(JSON.stringify(newValues)); + this.props.onChange(newValues) + this.setState({selectedPluginNames: 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) => { @@ -62,28 +88,23 @@ class AdvancedMultiSelect extends React.Component { } onMasterCheckboxClick = () => { - if (this.state.masterCheckboxState === MasterCheckboxState.ALL) { + let checkboxState = this.getMasterCheckboxState(this.state.selectedPluginNames); + if (checkboxState === MasterCheckboxState.ALL) { var newValues = []; } else { - newValues = this.enumOptions.map(({value}) => value); + newValues = this.getOptionList().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.props.onChange(selectValues); - - this.setMasterCheckboxState(selectValues); - this.setHideResetState(selectValues); + this.onChange(selectValues); } getSelectValuesAfterClick(clickedValue) { - const valueArray = cloneDeep(this.props.value); + const valueArray = cloneDeep(this.state.selectedPluginNames); if (valueArray.includes(clickedValue)) { return valueArray.filter(e => e !== clickedValue); @@ -95,8 +116,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}); } } @@ -106,7 +126,7 @@ class AdvancedMultiSelect extends React.Component { return MasterCheckboxState.NONE; } - if (selectValues.length !== this.enumOptions.length) { + if (selectValues.length !== this.getOptionList().length) { return MasterCheckboxState.MIXED; } @@ -114,16 +134,7 @@ class AdvancedMultiSelect extends React.Component { } onResetClick = () => { - this.props.onChange(this.defaultValues); - this.setHideResetState(this.defaultValues); - this.setMasterCheckboxState(this.defaultValues); - this.setPaneInfoToDefault(this.isUnsafeOptionSelected(this.defaultValues)); - } - - setHideResetState(selectValues) { - this.setState(() => ({ - hideReset: this.getHideResetState(selectValues) - })); + this.setPaneInfoToSafe(); } getHideResetState(selectValues) { @@ -135,11 +146,14 @@ class AdvancedMultiSelect extends React.Component { } isSafe = (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); + setPaneInfo = (itemKey) => { + let definitionObj = getFullDefinitionByKey(this.props.schema.items.$ref, + this.props.registry, itemKey); this.setState( { infoPaneParams: { @@ -152,14 +166,10 @@ class AdvancedMultiSelect extends React.Component { ); } - setPaneInfoToDefault(isUnsafeOptionSelected) { - this.setState(() => ({ - infoPaneParams: getDefaultPaneParams( - this.props.schema.items.$ref, - this.props.registry, - isUnsafeOptionSelected - ) - })); + setPaneInfoToSafe() { + let safePluginNames = this.state.allPluginNames.filter(pluginName => this.isSafe(pluginName)); + this.setState({selectedPluginNames: safePluginNames}); + this.onChange(safePluginNames); } render() { @@ -168,33 +178,33 @@ class AdvancedMultiSelect extends React.Component { id, multiple, required, - schema, - value + schema } = this.props; return (
+ onCheckboxClick={this.onMasterCheckboxClick} + checkboxState={this.getMasterCheckboxState( + this.state.selectedPluginNames)} + hideReset={this.getHideResetState( + this.state.selectedPluginNames)} + onResetClick={this.onResetClick}/> + autoFocus={autofocus} isSafe={this.isSafe} + onPaneClick={this.setPaneInfo} + onCheckboxClick={this.onChildCheckboxClick} + selectedValues={this.state.selectedPluginNames} + enumOptions={this.getOptionList()}/> + body={this.state.infoPaneParams.content} + link={this.state.infoPaneParams.link} + warningType={this.state.infoPaneParams.warningType}/>
); } - - componentDidUpdate(_prevProps) { - this.setMasterCheckboxState(this.props.value); - } } export default AdvancedMultiSelect; 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; } } 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..6700e5e4a --- /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 {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'; +import {postBreachActions} from './definitions/post_breach_actions.js'; +import {fingerprinterClasses} from './definitions/fingerprinter_classes.js' + +export const SCHEMA = { + 'title': 'Monkey', + 'type': 'object', + 'definitions': { + 'brute_force_classes': bruteForceExploiters, + 'vulnerability_classes': vulnerabilityExploiters, + 'credential_collectors_classes': credentialCollectors, + 'post_breach_actions': postBreachActions, + 'fingerprinter_classes': fingerprinterClasses + }, + 'properties': { + 'propagation': propagationConfigurationSchema, + 'post_breach_actions': { + 'title': 'Post-breach actions', + 'type': 'array', + 'uniqueItems': true, + 'items': { + '$ref': '#/definitions/post_breach_actions' + } + }, + 'custom_pbas': customPBAConfigurationSchema, + 'payloads': ransomwareSchema, + 'credential_collectors': { + 'title': 'Credential collectors', + 'type': 'array', + 'uniqueItems': true, + 'items': { + '$ref': '#/definitions/credential_collectors_classes' + }, + 'default': [ + 'MimikatzCollector', + 'SSHCollector' + ] + }, + '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/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.' + } + ] +} 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..06d51a304 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/custom_pbas.js @@ -0,0 +1,51 @@ +export const customPBAConfigurationSchema = { + 'title': 'Custom PBA', + '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 the uploaded ' + + 'file on exploited machines.\nExample: ' + + '"chmod +x ./my_script.sh; ./my_script.sh ; rm ./my_script.sh"' + }, + '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', + 'default': '', + 'description': 'Command to be executed after breaching. ' + + 'Use this field to run custom commands or execute the uploaded ' + + 'file on exploited machine.\nExample: ' + + '"my_script.bat & del my_script.bat"' + }, + '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': '' + } + } +} 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..fdbd04401 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/exploitation.js @@ -0,0 +1,26 @@ +import {exploitationOptionsConfigurationSchema} from './exploitation_options.js'; + +export const exploitationConfigurationSchema = { + 'title': 'Exploiters', + 'type': 'object', + 'description': 'Choose which exploiters the Monkey will attempt.', + 'properties': { + 'brute_force': { + 'title': 'Brute force exploiters', + 'type': 'array', + 'uniqueItems': true, + 'items': { + '$ref': '#/definitions/brute_force_classes' + } + }, + 'vulnerability': { + 'title': 'Vulnerability Exploiters', + 'type': 'array', + 'uniqueItems': true, + 'items': { + '$ref': '#/definitions/vulnerability_classes' + } + }, + '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..e13d4ef7d --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/exploitation_options.js @@ -0,0 +1,15 @@ +export const exploitationOptionsConfigurationSchema = { + 'title': 'Exploiters Options', + '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/exploiter_classes.js b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/exploiter_classes.js new file mode 100644 index 000000000..bc7137fa1 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/exploiter_classes.js @@ -0,0 +1,121 @@ +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', + 'pluginDefs': { + 'SmbExploiter': {'name': 'SmbExploiter', 'options': {}}, + 'PowerShellExploiter': {'name': 'PowerShellExploiter', 'options': {}}, + 'WmiExploiter': {'name': 'WmiExploiter', 'options': {}}, + 'MSSQLExploiter': {'name': 'MSSQLExploiter', 'options': {}}, + 'SSHExploiter': {'name': 'SSHExploiter', 'options': {}} + }, + 'anyOf': [ + { + 'type': 'string', + 'enum': ['SmbExploiter'], + 'title': 'SMB Exploiter', + 'safe': true, + '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': ['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': ['WmiExploiter'], + 'title': 'WMI Exploiter', + 'safe': true, + '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, + '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, + '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', + 'pluginDefs': { + 'ZerologonExploiter': {'name': 'ZerologonExploiter', 'options':{}}, + 'Log4ShellExploiter': {'name': 'Log4ShellExploiter', 'options': {}}, + 'HadoopExploiter': {'name': 'HadoopExploiter', 'options': {}} + }, + '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': ['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/' + }, + { + '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/' + } + ] +} 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/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..713ac1c82 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/services/configuration/definitions/network_scan.js @@ -0,0 +1,21 @@ +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', + 'properties': { + 'fingerprinters': { + 'title': 'Fingerprinters', + 'type': 'array', + 'uniqueItems': true, + 'items': { + '$ref': '#/definitions/fingerprinter_classes' + } + }, + '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/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.' + } + ] + + +} 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..3099876dc --- /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 allowed 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/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.' + } + } + } + } +} 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..ba2c769e6 --- /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_subnets': { + '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.' + } + } +}