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.'
+ }
+ }
+}