forked from p15670423/monkey
Merge pull request #2051 from guardicore/2003-define-new-json-schema
2003 define new json schema
This commit is contained in:
commit
8873ef891b
|
@ -1,23 +1,25 @@
|
||||||
const CONFIGURATION_TABS = {
|
const CONFIGURATION_TABS = {
|
||||||
BASIC: 'basic',
|
PROPAGATION: 'propagation',
|
||||||
BASIC_NETWORK: 'basic_network',
|
PAYLOADS: 'payloads',
|
||||||
RANSOMWARE: 'ransomware',
|
PBA: 'post_breach_actions',
|
||||||
MONKEY: 'monkey',
|
CUSTOM_PBA: 'custom_pbas',
|
||||||
INTERNAL: 'internal'
|
CREDENTIALS_COLLECTORS: 'credential_collectors',
|
||||||
|
ADVANCED: 'advanced'
|
||||||
};
|
};
|
||||||
|
|
||||||
const advancedModeConfigTabs = [
|
const advancedModeConfigTabs = [
|
||||||
CONFIGURATION_TABS.BASIC,
|
CONFIGURATION_TABS.PROPAGATION,
|
||||||
CONFIGURATION_TABS.BASIC_NETWORK,
|
CONFIGURATION_TABS.PAYLOADS,
|
||||||
CONFIGURATION_TABS.RANSOMWARE,
|
CONFIGURATION_TABS.PBA,
|
||||||
CONFIGURATION_TABS.MONKEY,
|
CONFIGURATION_TABS.CUSTOM_PBA,
|
||||||
CONFIGURATION_TABS.INTERNAL
|
CONFIGURATION_TABS.CREDENTIALS_COLLECTORS,
|
||||||
|
CONFIGURATION_TABS.ADVANCED
|
||||||
];
|
];
|
||||||
|
|
||||||
const ransomwareModeConfigTabs = [
|
const ransomwareModeConfigTabs = [
|
||||||
CONFIGURATION_TABS.BASIC,
|
CONFIGURATION_TABS.PROPAGATION,
|
||||||
CONFIGURATION_TABS.BASIC_NETWORK,
|
CONFIGURATION_TABS.PAYLOADS,
|
||||||
CONFIGURATION_TABS.RANSOMWARE
|
CONFIGURATION_TABS.ADVANCED
|
||||||
];
|
];
|
||||||
|
|
||||||
const CONFIGURATION_TABS_PER_MODE = {
|
const CONFIGURATION_TABS_PER_MODE = {
|
||||||
|
|
|
@ -12,7 +12,7 @@ function applyUiSchemaManipulators(selectedSection,
|
||||||
function ransomwareDirManipulator(selectedSection,
|
function ransomwareDirManipulator(selectedSection,
|
||||||
formData,
|
formData,
|
||||||
uiSchema) {
|
uiSchema) {
|
||||||
if (selectedSection === 'ransomware'){
|
if (selectedSection === 'payloads'){
|
||||||
uiSchema.encryption.directories =
|
uiSchema.encryption.directories =
|
||||||
{'ui:disabled': !formData['encryption']['enabled']};
|
{'ui:disabled': !formData['encryption']['enabled']};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,139 +1,140 @@
|
||||||
import AdvancedMultiSelect from '../ui-components/AdvancedMultiSelect';
|
import AdvancedMultiSelect from '../ui-components/AdvancedMultiSelect';
|
||||||
|
import InfoBox from './InfoBox';
|
||||||
|
import TextBox from './TextBox.js';
|
||||||
import PbaInput from './PbaInput';
|
import PbaInput from './PbaInput';
|
||||||
import {API_PBA_LINUX, API_PBA_WINDOWS} from '../pages/ConfigurePage';
|
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) {
|
export default function UiSchema(props) {
|
||||||
const UiSchema = {
|
const UiSchema = {
|
||||||
basic: {
|
propagation: {
|
||||||
'ui:order': ['exploiters', 'credentials'],
|
exploitation: {
|
||||||
exploiters: {
|
brute_force: {
|
||||||
exploiter_classes: {
|
|
||||||
classNames: 'config-template-no-header',
|
classNames: 'config-template-no-header',
|
||||||
'ui:widget': AdvancedMultiSelect
|
'ui:widget': AdvancedMultiSelect,
|
||||||
}
|
brute_force_classes: {
|
||||||
},
|
|
||||||
credentials: {
|
|
||||||
exploit_user_list: {
|
|
||||||
items: {
|
|
||||||
classNames: 'config-template-no-header'
|
classNames: 'config-template-no-header'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
exploit_password_list: {
|
vulnerability: {
|
||||||
items: {
|
classNames: 'config-template-no-header',
|
||||||
classNames: 'config-template-no-header',
|
'ui:widget': AdvancedMultiSelect,
|
||||||
'ui:widget': SensitiveTextInput
|
vulnerability_classes: {
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
basic_network: {
|
|
||||||
'ui:order': ['scope', 'network_analysis'],
|
|
||||||
scope: {
|
|
||||||
info_box: {
|
|
||||||
'ui:field': InfoBox
|
|
||||||
},
|
|
||||||
blocked_ips: {
|
|
||||||
items: {
|
|
||||||
classNames: 'config-template-no-header'
|
classNames: 'config-template-no-header'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
subnet_scan_list: {
|
options: {
|
||||||
format: 'ip-list',
|
http_ports: {
|
||||||
items: {
|
items: {
|
||||||
classNames: 'config-template-no-header'
|
classNames: 'config-template-no-header'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
network_analysis: {
|
network_scan: {
|
||||||
inaccessible_subnets: {
|
targets: {
|
||||||
items: {
|
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'
|
classNames: 'config-template-no-header'
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
monkey: {
|
payloads: {
|
||||||
post_breach: {
|
classNames: 'config-template-no-header',
|
||||||
post_breach_actions: {
|
|
||||||
classNames: 'config-template-no-header',
|
|
||||||
'ui:widget': AdvancedMultiSelect
|
|
||||||
},
|
|
||||||
custom_PBA_linux_cmd: {
|
|
||||||
'ui:widget': 'textarea',
|
|
||||||
'ui:emptyValue': ''
|
|
||||||
},
|
|
||||||
PBA_linux_file: {
|
|
||||||
'ui:widget': PbaInput,
|
|
||||||
'ui:options': {
|
|
||||||
filename: props.PBA_linux_filename,
|
|
||||||
apiEndpoint: API_PBA_LINUX,
|
|
||||||
setPbaFilename: props.setPbaFilenameLinux
|
|
||||||
}
|
|
||||||
},
|
|
||||||
custom_PBA_windows_cmd: {
|
|
||||||
'ui:widget': 'textarea',
|
|
||||||
'ui:emptyValue': ''
|
|
||||||
},
|
|
||||||
PBA_windows_file: {
|
|
||||||
'ui:widget': PbaInput,
|
|
||||||
'ui:options': {
|
|
||||||
filename: props.PBA_windows_filename,
|
|
||||||
apiEndpoint: API_PBA_WINDOWS,
|
|
||||||
setPbaFilename: props.setPbaFilenameWindows
|
|
||||||
}
|
|
||||||
},
|
|
||||||
PBA_linux_filename: {
|
|
||||||
classNames: 'linux-pba-file-info',
|
|
||||||
'ui:emptyValue': ''
|
|
||||||
},
|
|
||||||
PBA_windows_filename: {
|
|
||||||
classNames: 'windows-pba-file-info',
|
|
||||||
'ui:emptyValue': ''
|
|
||||||
}
|
|
||||||
},
|
|
||||||
credential_collectors: {
|
|
||||||
credential_collectors: {
|
|
||||||
classNames: 'config-template-no-header',
|
|
||||||
'ui:widget': AdvancedMultiSelect
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
ransomware: {
|
|
||||||
encryption: {
|
encryption: {
|
||||||
info_box: {
|
info_box : {
|
||||||
'ui:field': InfoBox
|
'ui:field': InfoBox
|
||||||
},
|
},
|
||||||
directories: {
|
directories: {
|
||||||
// Directory inputs are dynamically hidden
|
// Directory inputs are dynamically hidden
|
||||||
},
|
},
|
||||||
text_box: {
|
text_box: {
|
||||||
'ui:field': TextBox
|
'ui:field': TextBox
|
||||||
},
|
},
|
||||||
enabled: {'ui:widget': 'hidden'}
|
enabled: {
|
||||||
|
'ui:widget': 'hidden'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
other_behaviors : {'ui:widget': 'hidden'}
|
other_behaviors : {
|
||||||
|
'ui:widget': 'hidden'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
internal: {
|
custom_pbas: {
|
||||||
classes: {
|
classNames: 'config-template-no-header',
|
||||||
finger_classes: {
|
linux_command: {
|
||||||
classNames: 'config-template-no-header',
|
'ui:widget': 'textarea',
|
||||||
'ui:widget': AdvancedMultiSelect
|
'ui:emptyValue': ''
|
||||||
|
},
|
||||||
|
linux_file: {
|
||||||
|
'ui:widget': PbaInput,
|
||||||
|
'ui:options': {
|
||||||
|
filename: props.linux_filename,
|
||||||
|
apiEndpoint: API_PBA_LINUX,
|
||||||
|
setPbaFilename: props.setPbaFilenameLinux
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
exploits: {
|
windows_command: {
|
||||||
exploit_lm_hash_list:{
|
'ui:widget': 'textarea',
|
||||||
items: {
|
'ui:emptyValue': ''
|
||||||
'ui:widget': SensitiveTextInput
|
},
|
||||||
}
|
windows_file: {
|
||||||
},
|
'ui:widget': PbaInput,
|
||||||
exploit_ntlm_hash_list: {
|
'ui:options': {
|
||||||
items: {
|
filename: props.windows_filename,
|
||||||
'ui:widget': SensitiveTextInput
|
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'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,7 +8,6 @@ import {faCheck} from '@fortawesome/free-solid-svg-icons/faCheck';
|
||||||
import {faExclamationCircle} from '@fortawesome/free-solid-svg-icons/faExclamationCircle';
|
import {faExclamationCircle} from '@fortawesome/free-solid-svg-icons/faExclamationCircle';
|
||||||
import {formValidationFormats} from '../configuration-components/ValidationFormats';
|
import {formValidationFormats} from '../configuration-components/ValidationFormats';
|
||||||
import transformErrors from '../configuration-components/ValidationErrorMessages';
|
import transformErrors from '../configuration-components/ValidationErrorMessages';
|
||||||
import InternalConfig from '../configuration-components/InternalConfig';
|
|
||||||
import UnsafeConfigOptionsConfirmationModal
|
import UnsafeConfigOptionsConfirmationModal
|
||||||
from '../configuration-components/UnsafeConfigOptionsConfirmationModal.js';
|
from '../configuration-components/UnsafeConfigOptionsConfirmationModal.js';
|
||||||
import UnsafeOptionsWarningModal from '../configuration-components/UnsafeOptionsWarningModal.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 applyUiSchemaManipulators from '../configuration-components/UISchemaManipulators.tsx';
|
||||||
import HtmlFieldDescription from '../configuration-components/HtmlFieldDescription.js';
|
import HtmlFieldDescription from '../configuration-components/HtmlFieldDescription.js';
|
||||||
import CONFIGURATION_TABS_PER_MODE from '../configuration-components/ConfigurationTabs.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';
|
const CONFIG_URL = '/api/configuration/island';
|
||||||
export const API_PBA_LINUX = '/api/file-upload/PBAlinux';
|
export const API_PBA_LINUX = '/api/file-upload/PBAlinux';
|
||||||
|
@ -68,24 +68,28 @@ class ConfigurePageComponent extends AuthComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount = () => {
|
componentDidMount = () => {
|
||||||
let urls = [CONFIG_URL];
|
let urls = ['/api/agent-configuration'];
|
||||||
// ??? Why fetch config here and not in `render()`?
|
// ??? Why fetch config here and not in `render()`?
|
||||||
Promise.all(urls.map(url => this.authFetch(url).then(res => res.json())))
|
Promise.all(urls.map(url => this.authFetch(url).then(res => res.json())))
|
||||||
.then(data => {
|
.then(data => {
|
||||||
let sections = [];
|
let sections = [];
|
||||||
let monkeyConfig = data[0];
|
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()) {
|
for (let sectionKey of this.getSectionsOrder()) {
|
||||||
sections.push({
|
sections.push({
|
||||||
key: sectionKey,
|
key: sectionKey,
|
||||||
title: monkeyConfig.schema.properties[sectionKey].title
|
title: SCHEMA.properties[sectionKey].title
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
schema: monkeyConfig.schema,
|
schema: SCHEMA,
|
||||||
configuration: monkeyConfig.configuration,
|
configuration: monkeyConfig,
|
||||||
sections: sections,
|
sections: sections,
|
||||||
currentFormData: monkeyConfig.configuration[this.state.selectedSection]
|
currentFormData: monkeyConfig[this.state.selectedSection]
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -266,9 +270,11 @@ class ConfigurePageComponent extends AuthComponent {
|
||||||
|
|
||||||
this.updateConfigSection();
|
this.updateConfigSection();
|
||||||
this.currentSection = key;
|
this.currentSection = key;
|
||||||
|
let selectedSectionData = this.state.configuration[key];
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
selectedSection: key,
|
selectedSection: key,
|
||||||
currentFormData: this.state.configuration[key]
|
currentFormData: selectedSectionData
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -337,11 +343,11 @@ class ConfigurePageComponent extends AuthComponent {
|
||||||
let formProperties = {};
|
let formProperties = {};
|
||||||
formProperties['schema'] = displayedSchema
|
formProperties['schema'] = displayedSchema
|
||||||
formProperties['uiSchema'] = UiSchema({
|
formProperties['uiSchema'] = UiSchema({
|
||||||
PBA_linux_filename: this.state.configuration.monkey.post_breach.PBA_linux_filename,
|
selectedSection: this.state.selectedSection,
|
||||||
PBA_windows_filename: this.state.configuration.monkey.post_breach.PBA_windows_filename,
|
linux_filename: this.state.configuration.custom_pbas.linux_filename,
|
||||||
|
windows_filename: this.state.configuration.custom_pbas.windows_filename,
|
||||||
setPbaFilenameWindows: this.setPbaFilenameWindows,
|
setPbaFilenameWindows: this.setPbaFilenameWindows,
|
||||||
setPbaFilenameLinux: this.setPbaFilenameLinux,
|
setPbaFilenameLinux: this.setPbaFilenameLinux
|
||||||
selectedSection: this.state.selectedSection
|
|
||||||
})
|
})
|
||||||
formProperties['fields'] = {DescriptionField: HtmlFieldDescription};
|
formProperties['fields'] = {DescriptionField: HtmlFieldDescription};
|
||||||
formProperties['formData'] = this.state.currentFormData;
|
formProperties['formData'] = this.state.currentFormData;
|
||||||
|
@ -355,22 +361,18 @@ class ConfigurePageComponent extends AuthComponent {
|
||||||
formProperties['formData'],
|
formProperties['formData'],
|
||||||
formProperties['uiSchema']);
|
formProperties['uiSchema']);
|
||||||
|
|
||||||
if (this.state.selectedSection === 'internal') {
|
return (
|
||||||
return (<InternalConfig {...formProperties}/>)
|
<div>
|
||||||
} else {
|
<Form {...formProperties} key={displayedSchema.title}>
|
||||||
return (
|
<button type='submit' className={'hidden'}>Submit</button>
|
||||||
<div>
|
</Form>
|
||||||
<Form {...formProperties}>
|
</div>
|
||||||
<button type='submit' className={'hidden'}>Submit</button>
|
)
|
||||||
</Form>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
setPbaFilenameWindows = (filename) => {
|
setPbaFilenameWindows = (filename) => {
|
||||||
let config = this.state.configuration
|
let config = this.state.configuration
|
||||||
config.monkey.post_breach.PBA_windows_filename = filename
|
config.custom_pbas.windows_filename = filename
|
||||||
this.setState({
|
this.setState({
|
||||||
configuration: config
|
configuration: config
|
||||||
})
|
})
|
||||||
|
@ -378,7 +380,7 @@ class ConfigurePageComponent extends AuthComponent {
|
||||||
|
|
||||||
setPbaFilenameLinux = (filename) => {
|
setPbaFilenameLinux = (filename) => {
|
||||||
let config = this.state.configuration
|
let config = this.state.configuration
|
||||||
config.monkey.post_breach.PBA_linux_filename = filename
|
config.custom_pbas.linux_filename = filename
|
||||||
this.setState({
|
this.setState({
|
||||||
configuration: config
|
configuration: config
|
||||||
})
|
})
|
||||||
|
@ -391,7 +393,7 @@ class ConfigurePageComponent extends AuthComponent {
|
||||||
style={{'marginBottom': '2em'}}
|
style={{'marginBottom': '2em'}}
|
||||||
className={'config-nav'}>
|
className={'config-nav'}>
|
||||||
{this.state.sections.map(section => {
|
{this.state.sections.map(section => {
|
||||||
let classProp = section.key.startsWith('basic') ? 'tab-primary' : '';
|
let classProp = section.key.startsWith('propagation') ? 'tab-primary' : '';
|
||||||
return (
|
return (
|
||||||
<Nav.Item key={section.key}>
|
<Nav.Item key={section.key}>
|
||||||
<Nav.Link className={classProp} eventKey={section.key}>{section.title}</Nav.Link>
|
<Nav.Link className={classProp} eventKey={section.key}>{section.title}</Nav.Link>
|
||||||
|
|
|
@ -6,7 +6,7 @@ import {cloneDeep} from 'lodash';
|
||||||
import {getDefaultPaneParams, InfoPane, WarningType} from './InfoPane';
|
import {getDefaultPaneParams, InfoPane, WarningType} from './InfoPane';
|
||||||
import {MasterCheckbox, MasterCheckboxState} from './MasterCheckbox';
|
import {MasterCheckbox, MasterCheckboxState} from './MasterCheckbox';
|
||||||
import ChildCheckboxContainer from './ChildCheckbox';
|
import ChildCheckboxContainer from './ChildCheckbox';
|
||||||
import {getFullDefinitionByKey} from './JsonSchemaHelpers';
|
import {getFullDefinitionByKey, getObjectFromRegistryByRef} from './JsonSchemaHelpers';
|
||||||
|
|
||||||
function AdvancedMultiSelectHeader(props) {
|
function AdvancedMultiSelectHeader(props) {
|
||||||
const {
|
const {
|
||||||
|
@ -17,12 +17,13 @@ function AdvancedMultiSelectHeader(props) {
|
||||||
onResetClick
|
onResetClick
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card.Header className="d-flex justify-content-between">
|
<Card.Header className="d-flex justify-content-between">
|
||||||
<MasterCheckbox title={title} onClick={onCheckboxClick} checkboxState={checkboxState}/>
|
<MasterCheckbox title={title} onClick={onCheckboxClick} checkboxState={checkboxState}/>
|
||||||
<Button className={'reset-safe-defaults'} type={'reset'} variant={'warning'}
|
<Button className={'reset-safe-defaults'} type={'reset'} variant={'warning'}
|
||||||
hidden={hideReset} onClick={onResetClick}>
|
hidden={hideReset} onClick={onResetClick}>
|
||||||
Reset to safe defaults
|
Reset to safe options
|
||||||
</Button>
|
</Button>
|
||||||
</Card.Header>
|
</Card.Header>
|
||||||
);
|
);
|
||||||
|
@ -32,22 +33,47 @@ class AdvancedMultiSelect extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.defaultValues = props.schema.default;
|
let selectedPluginNames = this.props.value.map(v => v.name);
|
||||||
this.infoPaneRefString = props.schema.items.$ref;
|
let allPluginNames = this.props.options.enumOptions.map(v => v.value);
|
||||||
this.registry = props.registry;
|
|
||||||
this.enumOptions = props.options.enumOptions.sort(this.compareOptions);
|
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
masterCheckboxState: this.getMasterCheckboxState(props.value),
|
|
||||||
hideReset: this.getHideResetState(props.value),
|
|
||||||
infoPaneParams: getDefaultPaneParams(
|
infoPaneParams: getDefaultPaneParams(
|
||||||
this.infoPaneRefString,
|
this.props.schema.items.$ref,
|
||||||
this.registry,
|
this.props.registry,
|
||||||
this.isUnsafeOptionSelected(props.value)
|
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
|
// Sort options alphabetically. "Unsafe" options float to the top so that they
|
||||||
// do not get selected and hidden at the bottom of the list.
|
// do not get selected and hidden at the bottom of the list.
|
||||||
compareOptions = (a, b) => {
|
compareOptions = (a, b) => {
|
||||||
|
@ -62,28 +88,23 @@ class AdvancedMultiSelect extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
onMasterCheckboxClick = () => {
|
onMasterCheckboxClick = () => {
|
||||||
if (this.state.masterCheckboxState === MasterCheckboxState.ALL) {
|
let checkboxState = this.getMasterCheckboxState(this.state.selectedPluginNames);
|
||||||
|
if (checkboxState === MasterCheckboxState.ALL) {
|
||||||
var newValues = [];
|
var newValues = [];
|
||||||
} else {
|
} else {
|
||||||
newValues = this.enumOptions.map(({value}) => value);
|
newValues = this.getOptionList().map(({value}) => value);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.props.onChange(newValues);
|
this.onChange(newValues);
|
||||||
this.setMasterCheckboxState(newValues);
|
|
||||||
this.setHideResetState(newValues);
|
|
||||||
this.setPaneInfoToDefault(this.isUnsafeOptionSelected(newValues));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onChildCheckboxClick = (value) => {
|
onChildCheckboxClick = (value) => {
|
||||||
let selectValues = this.getSelectValuesAfterClick(value);
|
let selectValues = this.getSelectValuesAfterClick(value);
|
||||||
this.props.onChange(selectValues);
|
this.onChange(selectValues);
|
||||||
|
|
||||||
this.setMasterCheckboxState(selectValues);
|
|
||||||
this.setHideResetState(selectValues);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getSelectValuesAfterClick(clickedValue) {
|
getSelectValuesAfterClick(clickedValue) {
|
||||||
const valueArray = cloneDeep(this.props.value);
|
const valueArray = cloneDeep(this.state.selectedPluginNames);
|
||||||
|
|
||||||
if (valueArray.includes(clickedValue)) {
|
if (valueArray.includes(clickedValue)) {
|
||||||
return valueArray.filter(e => e !== clickedValue);
|
return valueArray.filter(e => e !== clickedValue);
|
||||||
|
@ -95,8 +116,7 @@ class AdvancedMultiSelect extends React.Component {
|
||||||
|
|
||||||
setMasterCheckboxState(selectValues) {
|
setMasterCheckboxState(selectValues) {
|
||||||
let newState = this.getMasterCheckboxState(selectValues);
|
let newState = this.getMasterCheckboxState(selectValues);
|
||||||
|
if (newState !== this.state.masterCheckboxState) {
|
||||||
if (newState != this.state.masterCheckboxState) {
|
|
||||||
this.setState({masterCheckboxState: newState});
|
this.setState({masterCheckboxState: newState});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,7 +126,7 @@ class AdvancedMultiSelect extends React.Component {
|
||||||
return MasterCheckboxState.NONE;
|
return MasterCheckboxState.NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selectValues.length !== this.enumOptions.length) {
|
if (selectValues.length !== this.getOptionList().length) {
|
||||||
return MasterCheckboxState.MIXED;
|
return MasterCheckboxState.MIXED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,16 +134,7 @@ class AdvancedMultiSelect extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
onResetClick = () => {
|
onResetClick = () => {
|
||||||
this.props.onChange(this.defaultValues);
|
this.setPaneInfoToSafe();
|
||||||
this.setHideResetState(this.defaultValues);
|
|
||||||
this.setMasterCheckboxState(this.defaultValues);
|
|
||||||
this.setPaneInfoToDefault(this.isUnsafeOptionSelected(this.defaultValues));
|
|
||||||
}
|
|
||||||
|
|
||||||
setHideResetState(selectValues) {
|
|
||||||
this.setState(() => ({
|
|
||||||
hideReset: this.getHideResetState(selectValues)
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getHideResetState(selectValues) {
|
getHideResetState(selectValues) {
|
||||||
|
@ -135,11 +146,14 @@ class AdvancedMultiSelect extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
isSafe = (itemKey) => {
|
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) => {
|
setPaneInfo = (itemKey) => {
|
||||||
let definitionObj = getFullDefinitionByKey(this.infoPaneRefString, this.registry, itemKey);
|
let definitionObj = getFullDefinitionByKey(this.props.schema.items.$ref,
|
||||||
|
this.props.registry, itemKey);
|
||||||
this.setState(
|
this.setState(
|
||||||
{
|
{
|
||||||
infoPaneParams: {
|
infoPaneParams: {
|
||||||
|
@ -152,14 +166,10 @@ class AdvancedMultiSelect extends React.Component {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
setPaneInfoToDefault(isUnsafeOptionSelected) {
|
setPaneInfoToSafe() {
|
||||||
this.setState(() => ({
|
let safePluginNames = this.state.allPluginNames.filter(pluginName => this.isSafe(pluginName));
|
||||||
infoPaneParams: getDefaultPaneParams(
|
this.setState({selectedPluginNames: safePluginNames});
|
||||||
this.props.schema.items.$ref,
|
this.onChange(safePluginNames);
|
||||||
this.props.registry,
|
|
||||||
isUnsafeOptionSelected
|
|
||||||
)
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -168,33 +178,33 @@ class AdvancedMultiSelect extends React.Component {
|
||||||
id,
|
id,
|
||||||
multiple,
|
multiple,
|
||||||
required,
|
required,
|
||||||
schema,
|
schema
|
||||||
value
|
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={'advanced-multi-select'}>
|
<div className={'advanced-multi-select'}>
|
||||||
<AdvancedMultiSelectHeader title={schema.title}
|
<AdvancedMultiSelectHeader title={schema.title}
|
||||||
onCheckboxClick={this.onMasterCheckboxClick}
|
onCheckboxClick={this.onMasterCheckboxClick}
|
||||||
checkboxState={this.state.masterCheckboxState}
|
checkboxState={this.getMasterCheckboxState(
|
||||||
hideReset={this.state.hideReset} onResetClick={this.onResetClick}/>
|
this.state.selectedPluginNames)}
|
||||||
|
hideReset={this.getHideResetState(
|
||||||
|
this.state.selectedPluginNames)}
|
||||||
|
onResetClick={this.onResetClick}/>
|
||||||
|
|
||||||
<ChildCheckboxContainer id={id} multiple={multiple} required={required}
|
<ChildCheckboxContainer id={id} multiple={multiple} required={required}
|
||||||
autoFocus={autofocus} isSafe={this.isSafe}
|
autoFocus={autofocus} isSafe={this.isSafe}
|
||||||
onPaneClick={this.setPaneInfo} onCheckboxClick={this.onChildCheckboxClick}
|
onPaneClick={this.setPaneInfo}
|
||||||
selectedValues={value} enumOptions={this.enumOptions}/>
|
onCheckboxClick={this.onChildCheckboxClick}
|
||||||
|
selectedValues={this.state.selectedPluginNames}
|
||||||
|
enumOptions={this.getOptionList()}/>
|
||||||
|
|
||||||
<InfoPane title={this.state.infoPaneParams.title}
|
<InfoPane title={this.state.infoPaneParams.title}
|
||||||
body={this.state.infoPaneParams.content}
|
body={this.state.infoPaneParams.content}
|
||||||
link={this.state.infoPaneParams.link}
|
link={this.state.infoPaneParams.link}
|
||||||
warningType={this.state.infoPaneParams.warningType}/>
|
warningType={this.state.infoPaneParams.warningType}/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(_prevProps) {
|
|
||||||
this.setMasterCheckboxState(this.props.value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AdvancedMultiSelect;
|
export default AdvancedMultiSelect;
|
||||||
|
|
|
@ -1,24 +1,29 @@
|
||||||
function getPluginDescriptors(schema, config) {
|
function getPluginDescriptors(schema, config) {
|
||||||
return ([
|
return ([
|
||||||
{
|
{
|
||||||
name: 'Exploiters',
|
name: 'Brute force exploiters',
|
||||||
allPlugins: schema.definitions.exploiter_classes.anyOf,
|
allPlugins: schema.definitions.brute_force_classes.anyOf,
|
||||||
selectedPlugins: config.basic.exploiters.exploiter_classes
|
selectedPlugins: config.propagation.exploitation.brute_force
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Vulnerability exploiters',
|
||||||
|
allPlugins: schema.definitions.vulnerability_classes.anyOf,
|
||||||
|
selectedPlugins: config.propagation.exploitation.vulnerability
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Fingerprinters',
|
name: 'Fingerprinters',
|
||||||
allPlugins: schema.definitions.finger_classes.anyOf,
|
allPlugins: schema.definitions.fingerprinter_classes.anyOf,
|
||||||
selectedPlugins: config.internal.classes.finger_classes
|
selectedPlugins: config.propagation.network_scan.fingerprinters
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'PostBreachActions',
|
name: 'PostBreachActions',
|
||||||
allPlugins: schema.definitions.post_breach_actions.anyOf,
|
allPlugins: schema.definitions.post_breach_actions.anyOf,
|
||||||
selectedPlugins: config.monkey.post_breach.post_breach_actions
|
selectedPlugins: config.post_breach_actions
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'CredentialCollectors',
|
name: 'CredentialCollectors',
|
||||||
allPlugins: schema.definitions.credential_collectors.anyOf,
|
allPlugins: schema.definitions.credential_collectors_classes.anyOf,
|
||||||
selectedPlugins: config.monkey.credential_collectors.credential_collectors
|
selectedPlugins: config.credential_collectors
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
@ -40,7 +45,7 @@ function isUnsafePluginSelected(pluginDescriptor) {
|
||||||
pluginDescriptor.allPlugins.forEach(i => pluginSafety[i.enum[0]] = i.safe);
|
pluginDescriptor.allPlugins.forEach(i => pluginSafety[i.enum[0]] = i.safe);
|
||||||
|
|
||||||
for (let selected of pluginDescriptor.selectedPlugins) {
|
for (let selected of pluginDescriptor.selectedPlugins) {
|
||||||
if (!pluginSafety[selected]) {
|
if (!pluginSafety[selected.name]) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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}
|
||||||
|
}
|
|
@ -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.'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -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': ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
};
|
|
@ -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'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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/'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -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.'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
}
|
|
@ -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'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
export const pluginConfigurationSchema = {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'name': {
|
||||||
|
'title': 'Name',
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'safe': {
|
||||||
|
'type': 'boolean'
|
||||||
|
},
|
||||||
|
'options': {
|
||||||
|
'type': 'object'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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"'
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue